note.nkmk.me

pandasでn個の最大値・最小値を取得(nlargest, nsmallest)

Posted: 2020-06-11 / Tags: Python, pandas

pandas.DataFrame, Seriesからn個の最大値・最小値(大きい方からn個、小さい方からn個)を含む行・要素を取得するには、nlargest(), nsmallest()メソッドを使う。

ここでは以下の内容について説明する。

  • 最大値・最小値の取得: max(), min()
  • nlargest(), nsmallest()の基本的な使い方
    • pandas.Seriesの場合
    • pandas.DataFrameの場合
  • 重複した値の処理: 引数keep
  • n個の最大値・最小値をリストやNumPy配列ndarrayで取得
  • pandas.DataFrameのすべての列に対して一括処理

最大値や最小値となる要素の行名を取得したい場合や、pandas.DataFrame, Series全体を昇順・降順にソートしたい場合は以下の記事を参照。

また、Python組み込みのリストに対して最大値・最小値をn個取得したい場合は以下の記事を参照。

以降のサンプルコードでは以下のpandas.DataFrameおよびpandas.Seriesを例として使う。

import pandas as pd
import numpy as np

df = pd.DataFrame({'col1': [2, 3, 1, 3, 3, 4],
                   'col2': [30, 10, 10, 40, 40, 20]},
                  index=['A', 'B', 'C', 'D', 'E', 'F'])
print(df)
#    col1  col2
# A     2    30
# B     3    10
# C     1    10
# D     3    40
# E     3    40
# F     4    20

s = df['col1']
print(s)
# A    2
# B    3
# C    1
# D    3
# E    3
# F    4
# Name: col1, dtype: int64
スポンサーリンク

最大値・最小値の取得: max(), min()

最大値・最小値のみ(1個だけ)を取得したい場合はmax(), min()メソッドを使う。

pandas.DataFrameに対しては、各列の最大値・最小値を要素とするpandas.Seriesが返される。

print(df.max())
# col1     4
# col2    40
# dtype: int64

print(type(df.max()))
# <class 'pandas.core.series.Series'>

print(df.min())
# col1     1
# col2    10
# dtype: int64

print(type(df.min()))
# <class 'pandas.core.series.Series'>

引数axis1とすると各行の最大値・最小値となる。

print(df.max(axis=1))
# A    30
# B    10
# C    10
# D    40
# E    40
# F    20
# dtype: int64

print(df.min(axis=1))
# A    2
# B    3
# C    1
# D    3
# E    3
# F    4
# dtype: int64

pandas.Seriesに対しては、要素の値(スカラー値)が返される。

print(s.max())
# 4

print(type(s.max()))
# <class 'numpy.int64'>

print(s.min())
# 1

print(type(s.min()))
# <class 'numpy.int64'>

nlargest(), nsmallest()の基本的な使い方

n個の最大値・最小値(大きい方からn個、小さい方からn個)を取得するにはnlargest(), nsmallest()メソッドを使う。該当する値が重複して存在する場合の処理については後述。

pandas.Seriesの場合

第一引数nに個数を指定する。大きい方からn個、または、小さい方からn個を要素とするpandas.Seriesが返される。

print(s.nlargest(4))
# F    4
# B    3
# D    3
# E    3
# Name: col1, dtype: int64

print(type(s.nlargest(4)))
# <class 'pandas.core.series.Series'>

print(s.nsmallest(4))
# C    1
# A    2
# B    3
# D    3
# Name: col1, dtype: int64

print(type(s.nsmallest(4)))
# <class 'pandas.core.series.Series'>

n=1の場合も、要素数が1個のpandas.Seriesとなる。

print(s.nlargest(1))
# F    4
# Name: col1, dtype: int64

print(type(s.nlargest(1)))
# <class 'pandas.core.series.Series'>

同様の処理は.sort_values(ascending=False).head(n), .sort_values().head(n)でも可能だが、npandas.Series全体の要素数に比べて小さい場合はnlargest(), nsmallest()のほうが高速とのこと。

Faster than .sort_values(ascending=False).head(n) for small n relative to the size of the Series object. pandas.Series.nlargest — pandas 1.0.4 documentation

Faster than .sort_values().head(n) for small n relative to the size of the Series object. pandas.Series.nsmallest — pandas 1.0.4 documentation

sort_values(), head()については以下の記事を参照。

pandas.DataFrameの場合

pandas.DataFrameの場合、第一引数nに個数、第二引数columnsに列名を指定する。指定した列の大きい方からn個、または、小さい方からn個を含む行のpandas.DataFrameが返される。

print(df.nlargest(4, 'col1'))
#    col1  col2
# F     4    20
# B     3    10
# D     3    40
# E     3    40

print(type(df.nlargest(4, 'col1')))
# <class 'pandas.core.frame.DataFrame'>

print(df.nsmallest(4, 'col1'))
#    col1  col2
# C     1    10
# A     2    30
# B     3    10
# D     3    40

print(type(df.nsmallest(4, 'col1')))
# <class 'pandas.core.frame.DataFrame'>

n=1の場合も、1行のpandas.DataFrame

print(df.nlargest(1, 'col1'))
#    col1  col2
# F     4    20

print(type(df.nlargest(1, 'col1')))
# <class 'pandas.core.frame.DataFrame'>

第二引数columnsには列名のリストも指定可能。

リストの後ろの列から順にソートして、上からn行を返すイメージ。最終結果はリストの最初に指定した列が降順(nlargest())または昇順(nsmallest())に並ぶ。

print(df.nlargest(4, ['col1', 'col2']))
#    col1  col2
# F     4    20
# D     3    40
# E     3    40
# B     3    10

print(df.nlargest(4, ['col2', 'col1']))
#    col1  col2
# D     3    40
# E     3    40
# A     2    30
# F     4    20

各列が独立にソートされるわけではないので注意。各列それぞれの最大値・最小値をn個取得する例は後述。

df.sort_values(columns, ascending=False), df.sort_values(columns, ascending=True).head(n)と同等だが、nlargest(), nsmallest()のほうが効率がよい(performant)とのこと。

This method is equivalent to df.sort_values(columns, ascending=False).head(n), but more performant. pandas.DataFrame.nlargest — pandas 1.0.4 documentation

This method is equivalent to df.sort_values(columns, ascending=True).head(n), but more performant. pandas.DataFrame.nsmallest — pandas 1.0.4 documentation

pandas.Seriesのようにnと行数との関係は示されていない。処理速度が重要な場合は、実際に実行する条件で処理時間を計測してみるといいかもしれない。

重複した値の処理: 引数keep

nlargest(), nsmallest()において、該当する値が重複して存在する場合の処理は引数keepで指定可能。引数keepはpandas0.24.0で追加。それより前のバージョンでは使えない。

以下の例はpandas.DataFramensmallest()だが、pandas.Seriesnlargest()でも考え方は同じ。

デフォルトはkeep='first'で、元のpandas.DataFrameまたはpandas.Seriesで上にある行・要素が優先される(上から順に残る)。

print(df.nsmallest(4, 'col1'))
#    col1  col2
# C     1    10
# A     2    30
# B     3    10
# D     3    40

print(df.nsmallest(4, 'col1', keep='first'))
#    col1  col2
# C     1    10
# A     2    30
# B     3    10
# D     3    40

keep='last'とすると、下にある行・要素が優先される(下から順に残る)。

print(df.nsmallest(4, 'col1', keep='last'))
#    col1  col2
# C     1    10
# A     2    30
# E     3    40
# D     3    40

keep='all'とすると、重複する行・要素すべてが残る。

print(df.nsmallest(4, 'col1', keep='all'))
#    col1  col2
# C     1    10
# A     2    30
# B     3    10
# D     3    40
# E     3    40

pandas.DataFrameにおいて引数columnsをリストで指定した場合、各列の要素がすべて一致しているときのみ重複しているとみなされる。いずれかの列のみが同じでも重複しているとはみなされないので注意。

print(df.nsmallest(3, ['col1', 'col2'], keep='all'))
#    col1  col2
# C     1    10
# A     2    30
# B     3    10

print(df.nsmallest(4, ['col1', 'col2'], keep='all'))
#    col1  col2
# C     1    10
# A     2    30
# B     3    10
# D     3    40
# E     3    40

n個の最大値・最小値をリストやNumPy配列ndarrayで取得

pandas.DataFrameの任意の列(= pandas.Series)のn個の最大値・最小値をリストで取得したい場合はtolist()を使う。

print(df['col1'].nsmallest(4).tolist())
# [1, 2, 3, 3]

print(type(df['col1'].nsmallest(4).tolist()))
# <class 'list'>

NumPy配列ndarrayで取得したい場合はto_numpy()またはvaluesを使う(to_numpy()はpandas0.24.0で追加)。

print(df['col1'].nsmallest(4).to_numpy())
# [1 2 3 3]

print(type(df['col1'].nsmallest(4).to_numpy()))
# <class 'numpy.ndarray'>

print(df['col1'].nsmallest(4).values)
# [1 2 3 3]

print(type(df['col1'].nsmallest(4).values))
# <class 'numpy.ndarray'>

pandas.DataFrameのすべての列に対して一括処理

pandas.DataFrameのすべての列のn個の最大値・最小値を一括で取得する例は以下の通り。

ここでは、結果をリスト、辞書(キーが列名)、numpy.ndarrayとしている。

print(df['col1'].nsmallest(3))
# C    1
# A    2
# B    3
# Name: col1, dtype: int64

print(df['col2'].nsmallest(3))
# B    10
# C    10
# F    20
# Name: col2, dtype: int64

print([df[col_name].nsmallest(3).tolist() for col_name in df])
# [[1, 2, 3], [10, 10, 20]]

print({col_name: col.nsmallest(3).tolist() for col_name, col in df.iteritems()})
# {'col1': [1, 2, 3], 'col2': [10, 10, 20]}

print(np.array([df[col_name].nsmallest(3).tolist() for col_name in df]))
# [[ 1  2  3]
#  [10 10 20]]

pandas.DataFrameのイテレーション、および、リスト内包表記、辞書内包表記、リストからnumpy.ndarrayへの変換を利用している。

なお、keep='all'として各列の要素数が異なる場合、numpy.ndarrayにはそのまま変換できないので注意。

print([df[col_name].nsmallest(3, keep='all').tolist() for col_name in df])
# [[1, 2, 3, 3, 3], [10, 10, 20]]

print({col_name: col.nsmallest(3, keep='all').tolist() for col_name, col in df.iteritems()})
# {'col1': [1, 2, 3, 3, 3], 'col2': [10, 10, 20]}

print(np.array([df[col_name].nsmallest(3, keep='all').tolist() for col_name in df]))
# [list([1, 2, 3, 3, 3]) list([10, 10, 20])]
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事