【Python】pandas でデータ操作 (中編)

pandas でデータを操作する時の Tips (前編の続きの中編) です。

環境は Python 2.7.11, pandas 0.20.3 です。

今回扱う内容は以下です。

  1. 連結 (concat, append)
  2. 結合 (merge, join)
  3. 適用 (apply)
  4. 写像 (map)
  5. 集約 (aggregate)
  6. グループ化 (groupby)

1. 連結 (concat, append)

pandas.concat は pandas オブジェクトを連結する。DataFrame の list を指定する。デフォルトは axis=0 で縦方向の連結 (積み上げ), axis=1 で横方向の連結となる。 keys を指定することで MultiIndex を振ることができ, 同名の列がある場合に区別できる。

In [1]: import pandas as pd

In [2]: import numpy as np

In [3]: df1 = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]}, index=[0, 1, 2, 3])

In [4]: df1
Out[4]:
   A  B
0  1  5
1  2  6
2  3  7
3  4  8

In [5]: df2 = pd.DataFrame({'A': [9, 10, 11, 12], 'B': [13, 14, 15, 16]}, index=[4, 5, 6, 7])

In [6]: df2
Out[6]:
    A   B
4   9  13
5  10  14
6  11  15
7  12  16

In [7]: pd.concat([df1, df2])
Out[7]:
    A   B
0   1   5
1   2   6
2   3   7
3   4   8
4   9  13
5  10  14
6  11  15
7  12  16

In [8]: pd.concat([df1, df2], axis=1)
Out[8]:
     A    B     A     B
0  1.0  5.0   NaN   NaN
1  2.0  6.0   NaN   NaN
2  3.0  7.0   NaN   NaN
3  4.0  8.0   NaN   NaN
4  NaN  NaN   9.0  13.0
5  NaN  NaN  10.0  14.0
6  NaN  NaN  11.0  15.0
7  NaN  NaN  12.0  16.0

In [9]: df3 = pd.DataFrame({'C': [9, 10, 11, 12], 'D': [13, 14, 15, 16]}, index=[0, 1, 2, 3])

In [10]: pd.concat([df1, df3], axis=1)
Out[10]:
   A  B   C   D
0  1  5   9  13
1  2  6  10  14
2  3  7  11  15
3  4  8  12  16

In [11]: pd.concat([df1, df2], axis=1, keys=['a', 'b'])
Out[11]:
     a          b
     A    B     A     B
0  1.0  5.0   NaN   NaN
1  2.0  6.0   NaN   NaN
2  3.0  7.0   NaN   NaN
3  4.0  8.0   NaN   NaN
4  NaN  NaN   9.0  13.0
5  NaN  NaN  10.0  14.0
6  NaN  NaN  11.0  15.0
7  NaN  NaN  12.0  16.0

pandas.DataFrame.append は DataFrame のメソッドとなるので concat よりシンプルに書ける。

In [12]: df1.append(df2)
Out[12]:
    A   B
0   1   5
1   2   6
2   3   7
3   4   8
4   9  13
5  10  14
6  11  15
7  12  16

In [13]: df1.append(pd.Series([5, 9], index=['A', 'B'], name=4))
Out[13]:
   A  B
0  1  5
1  2  6
2  3  7
3  4  8
4  5  9

In [14]: df1.append(pd.Series([5, 9], index=['A', 'B']), ignore_index=True)
Out[14]:
   A  B
0  1  5
1  2  6
2  3  7
3  4  8
4  5  9

2. 結合 (merge, join)

結合は pandas.DataFrame.mergepandas.DataFrame.join がある。

join メソッドのデフォルトは how=’left’ (左外部結合) である。他に right (右外部結合), outer (完全外部結合), inner (内部結合) が選択できる。

In [15]: df4 = pd.DataFrame({'C': [9, 10, 11, 12], 'D': [13, 14, 15, 16]}, index=[0, 1, 4, 5])

In [16]: df4
Out[16]:
    C   D
0   9  13
1  10  14
4  11  15
5  12  16

In [17]: df1
Out[17]:
   A  B
0  1  5
1  2  6
2  3  7
3  4  8

In [18]: df1.join(df4)
Out[18]:
   A  B     C     D
0  1  5   9.0  13.0
1  2  6  10.0  14.0
2  3  7   NaN   NaN
3  4  8   NaN   NaN

In [19]: df1.join(df4, how='right')
Out[19]:
     A    B   C   D
0  1.0  5.0   9  13
1  2.0  6.0  10  14
4  NaN  NaN  11  15
5  NaN  NaN  12  16

In [20]: df1.join(df4, how='inner')
Out[20]:
   A  B   C   D
0  1  5   9  13
1  2  6  10  14

In [21]: df1.join(df4, how='outer')
Out[21]:
     A    B     C     D
0  1.0  5.0   9.0  13.0
1  2.0  6.0  10.0  14.0
2  3.0  7.0   NaN   NaN
3  4.0  8.0   NaN   NaN
4  NaN  NaN  11.0  15.0
5  NaN  NaN  12.0  16.0

3. 適用 (apply)

pandas.DataFrame.apply は DataFrame の各列 (axis=0, デフォルト値) または各行 (axis=1) に対して関数を適用する。

In [22]: df1
Out[22]:
   A  B
0  1  5
1  2  6
2  3  7
3  4  8

In [23]: df1.apply(np.mean)
Out[23]:
A    2.5
B    6.5
dtype: float64

In [24]: df1.apply(np.mean, axis=1)
Out[24]:
0    3.0
1    4.0
2    5.0
3    6.0
dtype: float64

4. 写像 (map)

pandas.Series.map は Series の値に対して対応する値を map する。対応関係は Series か dict で指定する。以下は gender 列に含まれる ‘f’, ‘m’ を ‘female’, ‘male’ に置き換える例。

In [25]: df_ceo = pd.DataFrame({'name': ['Marissa Mayer', 'Elon Musk', 'Steve Jobs'],'gender': ['f', 'm', 'm']})

In [26]: df_ceo
Out[26]:
  gender           name
0      f  Marissa Mayer
1      m      Elon Musk
2      m     Steve Jobs

In [27]: df_ceo['gender'].map(pd.Series(['female', 'male'], index=['f', 'm']))
Out[27]:
0    female
1      male
2      male
Name: gender, dtype: object

In [28]: df_ceo['gender'].map({'f': 'female', 'm': 'male'})
Out[28]:
0    female
1      male
2      male
Name: gender, dtype: object

In [29]: df_ceo['name'].map(lambda x : x.replace(' ', ''))
Out[29]:
0    MarissaMayer
1        ElonMusk
2       SteveJobs
Name: name, dtype: object

5. 集約 (aggregate)

pandas.DataFrame.aggregate は全ての列に対して指定した関数で集約する。 agg は alias。

In [30]: df1.agg(['mean', 'var', 'prod'])
Out[30]:
              A            B
mean   2.500000     6.500000
var    1.666667     1.666667
prod  24.000000  1680.000000

6. グループ化 (groupby)

グループ化は split-apply-combine (分離-適用-統合) のステップを一つ以上含むプロセスで行われる。

  • Splitting: 基準に基づきグループに分離する
  • Applying: グループごとに独立に関数を適用する
  • Combining: 結果を結合する

pandas.DataFrame.groupby はグループ化された GroupBy object を返す。列名以外にも index も指定できる。

In [31]: iris.groupby('species')
Out[31]: <pandas.core.groupby.DataFrameGroupBy object at 0x1068479d0>

GroupBy object に対して集約関数を適用する。

In [32]: iris.groupby('species').size()
Out[32]:
species
setosa        50
versicolor    50
virginica     50
dtype: int64

In [33]: iris.groupby('species').mean()
Out[33]:
            sepal_length  sepal_width  petal_length  petal_width
species
setosa             5.006        3.418         1.464        0.244
versicolor         5.936        2.770         4.260        1.326
virginica          6.588        2.974         5.552        2.026

In [34]: iris.groupby('species').var()
Out[34]:
            sepal_length  sepal_width  petal_length  petal_width
species
setosa          0.124249     0.145180      0.030106     0.011494
versicolor      0.266433     0.098469      0.220816     0.039106
virginica       0.404343     0.104004      0.304588     0.075433

In [35]: iris.groupby('species').describe()
Out[35]:
           petal_length                                               \
                  count   mean       std  min  25%   50%    75%  max
species
setosa             50.0  1.464  0.173511  1.0  1.4  1.50  1.575  1.9
versicolor         50.0  4.260  0.469911  3.0  4.0  4.35  4.600  5.1
virginica          50.0  5.552  0.551895  4.5  5.1  5.55  5.875  6.9

           petal_width        ...  sepal_length      sepal_width         \
                 count   mean ...           75%  max       count   mean
species                       ...
setosa            50.0  0.244 ...           5.2  5.8        50.0  3.418
versicolor        50.0  1.326 ...           6.3  7.0        50.0  2.770
virginica         50.0  2.026 ...           6.9  7.9        50.0  2.974


                 std  min    25%  50%    75%  max
species
setosa      0.381024  2.3  3.125  3.4  3.675  4.4
versicolor  0.313798  2.0  2.525  2.8  3.000  3.4
virginica   0.322497  2.2  2.800  3.0  3.175  3.8

[3 rows x 32 columns]

複数の集約関数の場合は, 関数の list を agg に渡す。

In [36]: iris.groupby('species').agg([np.mean, np.var])
Out[36]:
           sepal_length           sepal_width           petal_length  \
                   mean       var        mean       var         mean
species
setosa            5.006  0.124249       3.418  0.145180        1.464
versicolor        5.936  0.266433       2.770  0.098469        4.260
virginica         6.588  0.404343       2.974  0.104004        5.552

                     petal_width
                 var        mean       var
species
setosa      0.030106       0.244  0.011494
versicolor  0.220816       1.326  0.039106
virginica   0.304588       2.026  0.075433

In [37]: iris.groupby('species').agg(lambda x: x.std())
Out[37]:
            sepal_length  sepal_width  petal_length  petal_width
species
setosa          0.352490     0.381024      0.173511     0.107210
versicolor      0.516171     0.313798      0.469911     0.197753
virginica       0.635880     0.322497      0.551895     0.274650

おわりに

中編では pandas.DataFrame の連結・結合・グループ化を中心に紹介しました。後編では時系列データの処理について紹介します。


[1] Python pandas 図でみる データ連結 / 結合処理
[2] Merge, join, and concatenate