note.nkmk.me

pandasで行・列ごとの最頻値を取得するmode

Date: 2018-05-20 / tags: Python, pandas

pandas.Seriesおよびpandas.DataFrameのメソッドmode()を使うと、各列・各行の最頻値を取得できる。

ユニークな要素の個数やリストなどを取得したい場合は以下の記事を参照。

また、最頻値を含む要約統計量をまとめて取得したい場合はdescribe()メソッドが便利。

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

  • pandas.Seriesmode()
  • pandas.DataFramemode()
    • 列ごとの最頻値を取得
    • 行ごとの最頻値を取得
  • 最頻値の頻度(出現回数)を取得
スポンサーリンク

pandas.Seriesのmode()

pandas.Seriesからmode()を呼ぶとpandas.Seriesが返る。

import pandas as pd

s = pd.Series(['X', 'X', 'Y', 'X'])
print(s)
# 0    X
# 1    X
# 2    Y
# 3    X
# dtype: object

print(s.mode())
# 0    X
# dtype: object

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

pandas.Seriesの要素が最頻値そのものの値。

mode_value = s.mode()[0]
print(mode_value)
# X

print(type(mode_value))
# <class 'str'>

最頻値が複数ある場合は以下の通り。

s_same = pd.Series(['X', 'Y', 'Y', 'X'])
print(s_same)
# 0    X
# 1    Y
# 2    Y
# 3    X
# dtype: object

print(s_same.mode())
# 0    X
# 1    Y
# dtype: object

print(s_same.mode()[0])
# X

最頻値のリストを取得したい場合はtolist()メソッドを使う。

l_modes = s_same.mode().tolist()
print(l_modes)
# ['X', 'Y']

print(type(l_modes))
# <class 'list'>

pandas.DataFrameのmode()

pandas.DataFrameにもmode()メソッドがある。

以下のpandas.DataFrameを例とする。

df = pd.DataFrame({'col1': ['X', 'X', 'Y', 'X'],
                   'col2': ['X', 'Y', 'Y', 'X']},
                  index=['row1', 'row2', 'row3', 'row4'])
print(df)
#      col1 col2
# row1    X    X
# row2    X    Y
# row3    Y    Y
# row4    X    X

列ごとの最頻値を取得

pandas.DataFrameからmode()メソッドを呼ぶと、デフォルトで列ごとの最頻値が要素となるpandas.DataFrameが返る。列によって最頻値の個数が異なる場合、空き部分は欠損値NaNとなる。

print(df.mode())
#   col1 col2
# 0    X    X
# 1  NaN    Y

print(type(df.mode()))
# <class 'pandas.core.frame.DataFrame'>

各列の最頻値の個数は欠損値NaNではない要素の個数をカウントするcount()メソッドで取得できる。

print(df.mode().count())
# col1    1
# col2    2
# dtype: int64

結果のpandas.DataFrameの一行目が各列の最頻値(複数ある場合はその中の一つ)になる。一行目はiloc[0]で取得可能。

print(df.mode().iloc[0])
# col1    X
# col2    X
# Name: 0, dtype: object

pandas.DataFrameからmode()を呼んで列を選択すると欠損値NaNを含む場合があるが、先に列を選択してからpandas.Seriesとしてmode()を呼ぶと欠損値NaNは含まないという違いがある。

print(df.mode()['col1'])
# 0      X
# 1    NaN
# Name: col1, dtype: object

print(df['col1'].mode())
# 0    X
# dtype: object

あまり使いどころはないかもしれないが、apply()メソッドで各列からmode()を呼んでtolist()でリスト化すると、リスト(list型)を要素とするpandsa.Seriesを取得することもできる。

l_mode = df.apply(lambda x: x.mode().tolist())
print(l_mode)
# col1       [X]
# col2    [X, Y]
# dtype: object

print(l_mode.iat[1])
# ['X', 'Y']

print(type(l_mode.iat[1]))
# <class 'list'>

print(l_mode.iat[1][1])
# Y

print(type(l_mode.iat[1][1]))
# <class 'str'>

なお、このとき結果のpandas.Seriesの行名indexは元のpandas.DataFrameの列名となる。元の列名が数値の場合は結果のpandas.Seriesの値の選択を[番号]とするとエラーとなり、iat[番号]とする必要があるので注意。例では文字列なので[番号]でも問題ない。

行ごとの最頻値を取得

引数axis=1とすると行ごとの最頻値が取得できる。

print(df.mode(axis=1))
#       0    1
# row1  X  NaN
# row2  X    Y
# row3  Y  NaN
# row4  X  NaN

欠損値NaNではない要素の個数をカウントするcount()メソッドにも引数axisがある。

print(df.mode(axis=1).count(axis=1))
# row1    1
# row2    2
# row3    1
# row4    1
# dtype: int64

なお、pandasでは列ごとに型dtypeをもつので、基本的には列ごとに同種のデータが並んでいることを前提としている。

したがって本来は行ごとに最頻値を求めることはあまりなく、行ごとに同種のデータが並んでいるのであれば転置したほうがいいかもしれない。

df_t = df.T
print(df_t)
#      row1 row2 row3 row4
# col1    X    X    Y    X
# col2    X    Y    Y    X

print(df_t.mode())
#   row1 row2 row3 row4
# 0    X    X    Y    X
# 1  NaN    Y  NaN  NaN

最頻値の頻度(出現回数)を取得

最頻値の頻度(出現回数)はpandas.Seriesのメソッドvalue_counts()で取得できる。

value_counts()は、ユニークな要素の値がindex、その頻度(出現回数)がdataとなるpandas.Seriesを返す。

デフォルトでは出現回数が多い順にソートされるので、value_counts()メソッドが返すpandas.Seriesの先頭の値が最頻値の頻度となる。

print(df['col1'].value_counts())
# X    3
# Y    1
# Name: col1, dtype: int64

print(df['col1'].value_counts().iat[0])
# 3

元のpandas.Seriesの要素が結果のpandas.Seriesindexとなる。数値がindexの場合は[番号]で値を指定できない(エラーになる)ためiat[番号]を使って厳密に指定している。(上の例は文字列なので[番号]でも問題はない)

各列の最頻値の頻度を取得するにはapply()を使う。

print(df.apply(lambda x: x.value_counts().iat[0]))
# col1    3
# col2    2
# dtype: int64

各列の要約統計量を算出するdescribe()メソッドでも最頻値とその頻度が求められる。

print(df.describe())
#        col1 col2
# count     4    4
# unique    2    2
# top       X    Y
# freq      3    2

項目topが最頻値でfreqがその頻度。最頻値が複数ある場合もその中の一つだけが返される。結果はpandas.DataFrameなので、locatなどで行や要素を取得可能。

print(df.describe().loc['freq'])
# col1    3
# col2    2
# Name: freq, dtype: object

print(df.describe().at['freq', 'col2'])
# 2

describe()には引数axisはないので、行に対して適用したい場合は転置してから呼ぶ。

print(df.T.describe())
#        row1 row2 row3 row4
# count     2    2    2    2
# unique    1    2    1    1
# top       X    Y    Y    X
# freq      2    1    2    2

describe()についての詳細は以下の記事を参照。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事