note.nkmk.me

pandasでユニークな要素の個数、頻度(出現回数)をカウント

Date: 2018-01-12 / Modified: 2018-05-20 / tags: Python, pandas

pandas.DataFrameの列、pandas.Seriesにおいて、ユニークな要素の個数(重複を除いた件数)、及び、それぞれの要素の頻度(出現回数)を取得する方法を説明する。

pandas.Seriesのメソッドunique(), value_counts(), nunique()を使う。nunique()pandas.DataFrameのメソッドとしても用意されている。

ユニークな要素ではなく条件を満たす要素の個数をカウントしたい場合は以下の記事を参照。

また、ユニークな要素の個数や最頻値、その頻度(出現回数)などを列ごとにまとめて算出するメソッドdescribe()もある。

ここでは、

  • pandas.Series.unique()
  • pandas.Series.value_counts()
  • pandas.Series.nunique(), pandas.DataFrame.nunique()

の基本的な使い方を説明したあと、

  • ユニークな要素の個数(重複を除いた件数)
  • ユニークな要素の値のリスト
  • ユニークな要素の頻度(出現回数)
  • ユニークな要素とその出現回数の辞書
  • 最頻値とその頻度
  • 規格化した頻度

を取得する方法を紹介する。

例として以下のデータを使用する。説明のため欠損値NaNを代入している。

import pandas as pd
import numpy as np

df = pd.read_csv('data/src/sample_pandas_normal.csv')
df.iloc[1] = np.nan
print(df)
#       name   age state  point
# 0    Alice  24.0    NY   64.0
# 1      NaN   NaN   NaN    NaN
# 2  Charlie  18.0    CA   70.0
# 3     Dave  68.0    TX   70.0
# 4    Ellen  24.0    CA   88.0
# 5    Frank  30.0    NY   57.0

サンプルのcsvファイルはコチラ。

スポンサーリンク

pandas.Series.unique()

unique()は、ユニークな要素の値のリストを返す。list型(Pythonの組み込み型)ではなく一次元のNumPy配列ndarray型。

欠損値NaNも含まれる。

u = df['state'].unique()
print(u)
print(type(u))
# ['NY' nan 'CA' 'TX']
# <class 'numpy.ndarray'>

pandas.Series.value_counts()

value_counts()は、ユニークな要素の値がindex、その出現個数がdataとなるpandas.Seriesを返す。要素の頻度(出現回数)が必要な場合はこちらを使う。

vc = df['state'].value_counts()
print(vc)
print(type(vc))
# NY    2
# CA    2
# TX    1
# Name: state, dtype: int64
# <class 'pandas.core.series.Series'>

デフォルトでは出現回数が多いものから順にソートされる(降順)が、引数ascending=Trueとすると昇順にソートされ、引数sort=Falseとするとソートされない。

print(df['state'].value_counts(ascending=True))
# TX    1
# CA    2
# NY    2
# Name: state, dtype: int64

print(df['state'].value_counts(sort=False))
# CA    2
# NY    2
# TX    1
# Name: state, dtype: int64

デフォルトではNaNは除外されるが、引数dropna=FalseとするとNaNもカウントされる。

print(df['state'].value_counts(dropna=False))
# NY     2
# CA     2
# TX     1
# NaN    1
# Name: state, dtype: int64

引数normalize=Trueとすると、合計が1になるように規格化した値が返される。

欠損値NaNが含まれている場合は引数dropnaの設定によって値が異なるので注意。

print(df['state'].value_counts(dropna=False, normalize=True))
# NY     0.333333
# CA     0.333333
# TX     0.166667
# NaN    0.166667
# Name: state, dtype: float64

pandas.Series.nunique(), pandas.DataFrame.nunique()

pandas.Series.nunique()はユニークな要素の個数を整数int型で返す。

デフォルトではNaNは除外され、引数dropna=FalseとするとNaNも含んだ結果となる。

nu = df['state'].nunique()
print(nu)
print(type(nu))
# 3
# <class 'int'>

print(df['state'].nunique(dropna=False))
# 4

pandas.DataFrame.nunique()はユニークな要素の個数を列ごとに算出する。pandas.Series型を返す。

デフォルトではNaNは除外され、引数dropna=FalseとするとNaNも含んだ結果となる。

また、デフォルトでは列ごとの値だが、引数axis=1またはaxis='columns'とすると行ごとの値を返す。

nu_col = df.nunique()
print(nu_col)
print(type(nu_col))
# name     5
# age      4
# state    3
# point    4
# dtype: int64
# <class 'pandas.core.series.Series'>

print(df.nunique(dropna=False))
# name     6
# age      5
# state    4
# point    5
# dtype: int64

print(df.nunique(dropna=False, axis='columns'))
# 0    4
# 1    1
# 2    4
# 3    4
# 4    4
# 5    4
# dtype: int64

ユニークな要素の個数(重複を除いた件数)

上述の通り、pandas.Series.nunique(), pandas.DataFrame.nunique()によってユニークな要素の個数(重複を除いた件数)をカウントできる。

print(df['state'].nunique())
# 3

print(df.nunique())
# name     5
# age      4
# state    3
# point    4
# dtype: int64

ユニークな要素の値のリスト

unique()ではNumPy配列ndarray型でユニークな要素の値のリストを取得できる。list型(Pythonの組み込み型)が欲しい場合はtolist()メソッドで変換可能。

print(df['state'].unique().tolist())
print(type(df['state'].unique().tolist()))
# ['NY', nan, 'CA', 'TX']
# <class 'list'>

value_counts()で取得したpandas.Seriesindextolist()メソッドを適用してもOK。valuesでNumPy配列ndarray型として取得することもできる。

print(df['state'].value_counts().index.tolist())
print(type(df['state'].value_counts().index.tolist()))
# ['NY', 'CA', 'TX']
# <class 'list'>

print(df['state'].value_counts(dropna=False).index.values)
print(type(df['state'].value_counts().index.values))
# ['NY' 'CA' 'TX' nan]
# <class 'numpy.ndarray'>

上述のように、unique()の場合は常にNaNが含まれるが、value_counts()は引数dropnaによってNaNを含むかどうかを指定できる。

ユニークな要素の頻度(出現回数)

ユニークな要素それぞれの頻度(出現回数)を得るには、value_counts()で取得したpandas.Seriesの値にアクセスすればよい。

print(df['state'].value_counts()['NY'])
# 2

print(df['state'].value_counts().NY)
# 2

forループで要素の値と頻度(出現回数)を取り出したい場合はiteritems()メソッドを使う。

for index, value in df['state'].value_counts().iteritems():
    print(index, ': ', value)
# NY :  2
# CA :  2
# TX :  1

ユニークな要素とその出現回数の辞書

value_counts()で取得したpandas.Seriesto_dict()メソッドを適用し、辞書化することもできる。

d = df['state'].value_counts().to_dict()
print(d)
print(type(d))
# {'NY': 2, 'CA': 2, 'TX': 1}
# <class 'dict'>

print(d['NY'])
# 2

forループで要素の値と頻度(出現回数)を取り出したい場合はitems()メソッドを使う。

for key, value in d.items():
    print(key, ': ', value)
# NY :  2
# CA :  2
# TX :  1

辞書dict型のforループ処理については以下の記事も参照。

最頻値とその頻度

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

以下のように取得できる。

print(df['state'].value_counts())
# NY    2
# CA    2
# TX    1
# Name: state, dtype: int64

print(df['state'].value_counts().index[0])
# NY

print(df['state'].value_counts().iat[0])
# 2

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

pandas.DataFrameの各列に適用するにはapply()メソッドを使う。

print(df.apply(lambda x: x.value_counts().index[0]))
# name     Frank
# age         24
# state       NY
# point       70
# dtype: object

print(df.apply(lambda x: x.value_counts().iat[0]))
# name     1
# age      2
# state    2
# point    2
# dtype: int64

最頻値が複数ある場合、上の方法だと一つの最頻値しか取得できない。

mode()

pandas.Seriesmode()メソッドは最頻値をpandas.Seriesとして返すメソッド。この結果をtolist()でリスト化すると最頻値をリストとして取得できる。最頻値が一つだけの場合もリストになるので注意。

print(df['state'].mode())
# 0    CA
# 1    NY
# dtype: object

print(df['state'].mode().tolist())
# ['CA', 'NY']

print(df['age'].mode().tolist())
# [24.0]

apply()メソッドで各列にmode()を適用するとlist型を要素とするpandas.Series()が得られる。

s_mode = df.apply(lambda x: x.mode().tolist())
print(s_mode)
# name     [Alice, Charlie, Dave, Ellen, Frank]
# age                                    [24.0]
# state                                [CA, NY]
# point                                  [70.0]
# dtype: object

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

print(s_mode['name'])
# ['Alice', 'Charlie', 'Dave', 'Ellen', 'Frank']

print(type(s_mode['name']))
# <class 'list'>

mode()pandas.DataFrameのメソッドとしても用意されている。pandas.DataFrameを返す。列ごとに最頻値の個数が異なるので空き部分は欠損値NaNとなる。

print(df.mode())
#       name   age state  point
# 0    Alice  24.0    CA   70.0
# 1  Charlie   NaN    NY    NaN
# 2     Dave   NaN   NaN    NaN
# 3    Ellen   NaN   NaN    NaN
# 4    Frank   NaN   NaN    NaN

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

print(df.mode().count())
# name     5
# age      1
# state    2
# point    1
# dtype: int64

mode()の詳細は以下の記事を参照。

describe()

また、冒頭に書いたようにdescribe()メソッドで列ごとのユニークな要素の個数や最頻値、その頻度(出現回数)をまとめて算出可能。各項目はloc[]で取得できる。

print(df.astype('str').describe())
#          name   age state point
# count       6     6     6     6
# unique      6     5     4     5
# top     Frank  24.0    CA  70.0
# freq        1     2     2     2

print(df.astype('str').describe().loc['top'])
# name     Frank
# age       24.0
# state       CA
# point     70.0
# Name: top, dtype: object

describe()では列の型dtypeによって算出される項目が異なるのでastype()で型変換(キャスト)している。describe()の詳細は以下の記事を参照。

最頻値が複数存在する場合でもdescribe()で最頻値(項目top)として返される値は一つだけなので注意。

規格化した頻度

上述の通り、value_counts()の引数normalizeTrueにすると、合計が1になるように規格化した値が返される。

欠損値NaNが含まれている場合は引数dropnaの設定によって値が異なるので注意。

複数データから頻度分布を比較するときなどに便利。

print(df['state'].value_counts(dropna=False, normalize=True))
# NY     0.333333
# CA     0.333333
# TX     0.166667
# NaN    0.166667
# Name: state, dtype: float64
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事