【Python】データ解析に欠かせない!Pandasの使い方④

こんにちは、unogram管理人のうのちゅ〜です。

今回は、Pythonによるデータ解析に欠かせないライブラリPandasの使い方の解説第4回です。Pandasは、機械学習に必要なデータの前処理や加工、統計量の算出にも便利で、Pythonユーザならぜひとも使いこなせるようにしておきたいライブラリです。

Pandas公式の10 minutes to pandasを参考に進めている本シリーズ、第1回【Python】データ解析に欠かせない!Pandasの使い方①からご覧いただくとスムーズに理解できるかと思います。

今回は主にPandasのDataFrameオブジェクトにおける「関数の適用や分割・結合、リシェイプ」の基礎について解説します。多くの項目について触れますが、そもそもpandasでどんなことができるかをざっと把握するのに良いのではないかと思います。

それでは見ていきましょう!



Pandasの使い方④

pandasとnumpyをインポートし、DataFrameオブジェクトを生成します。

import pandas as pd
import numpy as np

dates = pd.date_range('20201031', periods=6)
groups=list('ABCD')
data = np.random.randn(6, 4)
df = pd.DataFrame(data, index=dates, columns=groups)
df

関数の適用 df.apply

関数の適用にはapplyメソッドを使用します。

次の例では、累積和を計算するnumpy関数np.cumsumを適用しています。各列において、累積和が計算されています。

df.apply(np.cumsum)

applyを使ってラムダ式を適用することもできます。

df.apply(lambda x: x.max() - x.min())
# A    1.781077
# B    2.680666
# C    2.231306
# D    2.166986
# dtype: float64

ヒストグラムデータの取得 s.value_counts

s.value_counts()でSeriesオブジェクトsのヒストグラムデータを取得します。

# まずはSeriesオブジェクトを生成します。
s = pd.Series(np.random.randint(0,5,size=10))
s
# 0    0
# 1    3
# 2    4
# 3    1
# 4    0
# 5    0
# 6    0
# 7    0
# 8    3
# 9    0
# dtype: int64

# ヒストグラムデータを取得します。
s.value_counts()
# 0    6
# 3    2
# 4    1
# 1    1
# dtype: int64

文字列処理 s.str

pandasでは文字列処理のメソッドも多数存在します。

次の例ではs.str.lower()を使って大文字から小文字への変換を行っています。

s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
s.str.lower()
# 0       a
# 1       b
# 2       c
# 3    aaba
# 4    baca
# 5     NaN
# 6    caba
# 7     dog
# 8     cat
# dtype: object



結合 concat()

pandasのオブジェクトを結合するには、concat()関数を使用します。

次の例では、DataFrameオブジェクトを生成した後にそれを分割し、concat()関数によって再度結合しています。

# DataFrameオブジェクトの生成
df = pd.DataFrame(np.random.randn(10, 6))
df
# DataFrameを分割します
pieces = [df[:4],df[4:8],df[8:]]
pieces
# [          0         1         2         3         4         5
#  0 -0.907016  0.735526 -0.240477  1.268705  0.694990 -1.004654
#  1  0.103227 -1.328243  0.518848  0.857957  0.650291 -1.760258
#  2 -0.972405 -0.814367  0.978712 -0.122058  1.306795 -0.360572
#  3 -0.037834  1.609901  2.272998 -2.246091  0.355922 -0.892762,
#            0         1         2         3         4         5
#  4 -0.347648 -2.110396  1.352681  0.123324  1.215190  0.240402
#  5 -0.775457  0.236903  0.082670 -1.554752  2.342210 -1.075235
#  6  0.896721 -1.149019  0.146462  0.915369 -0.308049 -0.509561
#  7  1.681150 -1.186034 -0.428528 -1.214983 -0.780730  0.369989,
#            0         1         2         3         4         5
#  8 -0.520190  0.908379  0.203712  1.192885  1.283230 -0.530512
#  9 -0.266325 -1.139703 -1.063883  0.203660  0.027437  1.862154]

# pd.concat()関数を使用すると、結合して元のDataFrameに戻ります。
pd.concat(pieces)

結合 merge()

merge()関数も結合に使用する関数です。

最初の例では、leftとrightで共通する列名’key’を明示して結合しています。’key’が’foo’である行に、lvalに1をもつ行と2をもつ行、rvalに3をもつ行と4をもつ行が存在するため、それらの組み合わせのDataFrameが返されます。

 # 2つのDataFrameを用意します。
left = pd.DataFrame({'key': ['foo', 'foo'], 'lval': [1, 2]})
print(left)
#   key  lval
# 0  foo     1
# 1  foo     2
right = pd.DataFrame({'key': ['foo', 'foo'], 'rval': [3, 4]})
print(right)
#   key  rval
# 0  foo     3
# 1  foo     4

pd.merge(left,right, on='key')

次の例では、’key’が’foo’である行は、lvalに1、rvalに3、’key’が’bar’である行は、lvalに2、rvalに4となっています。

left = pd.DataFrame({'key': ['foo', 'bar'], 'lval': [1, 2]})
print(left)
#   key  lval
# 0  foo     1
# 1  bar     2
right = pd.DataFrame({'key': ['foo', 'bar'], 'rval': [3, 4]})
print(right)
#   key  rval
# 0  foo     3
# 1  bar     4

# この場合にmergeによって返されるDataFrameは次のようになります。
pd.merge(left,right,on='key')

グルーピング groupby

groupbyメソッドを使うと、次のようなグルーピングが可能です。

  • Splitting: ある基準でデータをグループに分割する
  • Applying: 各グループに独立して関数を適用する
  • Combining: 結果をデータ構造に結合する

グルーピング→メソッドの適用で、グルーピングした各グループにそれぞれメソッドを作用させることができます。

次の例では、生成したDataFrameオブジェクトの’A’列でグルーピングを行い、各グループに関して数値の総和を求めています。

# まずはDataFrameを生成します。
df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar',
                             'foo', 'bar', 'foo', 'foo'],
                       'B': ['one', 'one', 'two', 'three',
                             'two', 'two', 'one', 'three'],
                       'C': np.random.randn(8),
                       'D': np.random.randn(8)})
df
df.groupby('A').sum()

複数の列を指定してグルーピングすることも可能です。次の例では、’A’列と’B’列で階層的にグルーピングを行った上で、各グループの数値データ列の総和を求めています。

df.groupby(['A', 'B']).sum()



リシェイプ stack(), unstack(), pivot_table()

stack()メソッドでは、列方向に並んでいるデータを行方向に並べ替えます。

# DataFrameを作成します。まずはindex作成の準備をします。
tuples = list(zip(*[['bar', 'bar', 'baz', 'baz'],
                        ['one', 'two', 'one', 'two']]))
tuples
# [('bar', 'one'),
#  ('bar', 'two'),
#  ('baz', 'one'),
#  ('baz', 'two')]

# 作成したタプルのリストを'first', 'second'という列名で階層型index化します。
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
index
# MultiIndex([('bar', 'one'),
#             ('bar', 'two'),
#             ('baz', 'one'),
#             ('baz', 'two')],
#            names=['first', 'second'])

# 作成した階層型indexを用いてDataFrameを作成します。
df = pd.DataFrame(np.random.randn(4, 2), index=index, columns=['A', 'B'])
df
# stack()メソッドによって列方向のデータが行方向に積み重ねられるように整形されます。
stacked=df.stack()
stacked
# first  second   
# bar    one     A   -0.462222
#                B    0.878767
#        two     A   -0.983438
#                B   -1.868406
# baz    one     A   -0.537239
#                B    1.519777
#        two     A   -0.101561
#                B   -1.350996
# dtype: float64

stackの逆の操作はunstack()メソッドで行います。

# デフォルトでは最後のラベルでunstackされます。
stacked.unstack()
# 1番目のラベルでunstackしたい場合
stacked.unstack(1)
# 0番目のラベルでunstackしたい場合
stacked.unstack(0)

次の例では、ピボットテーブルを作成します。

# まずはDataFrameを準備します。
df = pd.DataFrame({'A': ['one', 'one', 'two', 'three'] * 3,
                       'B': ['A', 'B', 'C'] * 4,
                       'C': ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2,
                       'D': np.random.randn(12),
                       'E': np.random.randn(12)})
df

indexを’A’, ‘B’列から、columnsを’C’列から、valuesを”列から取得してピボットテーブルを作成します。該当するデータが存在しない位置はNaNとなります。

pd.pivot_table(df, values='E', index=['A', 'B'], columns=['C'])

まとめ

今回は、Pythonによるデータ解析に欠かせないライブラリPandasの使い方を解説しました。第4回として、主に関数の適用や分割・結合、リシェイプの基礎について解説しました。

参考にした10 minutes to pandasは、そもそもpandasでどんなことができるかをざっと把握するのに良いのではないかと思いますが、より詳しく学びたいという方は下記の参考書などを使って学習するのも良いかと思います。

次回でいよいよ10 minutes to pandasは最後になります。お楽しみに!

参考書学習は…

Pandasはデータ解析需要の増加に伴い、多数の専門書が刊行されています。必要に応じて書籍を通して学ぶこともデータ解析力の向上には欠かせません。

numpyやpandasを含めて、データサイエンスに必要なライブラリを俯瞰的に詳しく学習したい方は次の書籍がおすすめです。

参考

10 minutes to pandas