Python で解析 11

“Advent Calendar 2013 - Python で解析!” の十一日目。DataFrame - 7

1. 前回の補足

今回は concat を取り上げるのだが、その前に、十日目の記事を読み返していたら、書き忘れていたことがあったので、先に補足しておく。

In [10]: df4 = df1.join([df2, df3])

In [11]: df4
Out[11]:
       体重  名前 性別   身長         誕生日 好きなもの
3B005  79  山田  男  181  1982/02/02   ばなな
3B003  71  鈴木  男  173  1983/03/03   いちご
3B002  51  佐藤  女  159  1984/04/04   NaN
3B001  52  木村  女  164         NaN   メロン

上の join の場合、'how' に 'left' を指定したのと同じになる。

In [12]: df1.join([df2, df3], how='left')
Out[12]:
       体重  名前 性別   身長         誕生日 好きなもの
3B005  79  山田  男  181  1982/02/02   ばなな
3B003  71  鈴木  男  173  1983/03/03   いちご
3B002  51  佐藤  女  159  1984/04/04   NaN
3B001  52  木村  女  164         NaN   メロン

merge の場合の省略値は 'inner' だったが、join でも 'inner' を指定することができる。

In [13]: df1.join([df2, df3], how='inner')
Out[13]:
       体重  名前 性別   身長         誕生日 好きなもの
3B005  79  山田  男  181  1982/02/02   ばなな
3B003  71  鈴木  男  173  1983/03/03   いちご

'outer' も指定できる。

In [14]: df1.join([df2, df3], how='outer')
Out[14]:
       体重   名前   性別   身長         誕生日 好きなもの
3B001  52   木村    女  164         NaN   メロン
3B002  51   佐藤    女  159  1984/04/04   NaN
3B003  71   鈴木    男  173  1983/03/03   いちご
3B004 NaN  NaN  NaN  NaN  1981/01/01   りんご
3B005  79   山田    男  181  1982/02/02   ばなな

だが、 join で複数の DataFrame をつなぐ時には 'right' は指定できない。

In [15]: df1.join([df2, df3], how='right')
(中略)
ValueError: Only can inner (intersect) or outer (union) join the other axis

一つだけなら OK。

In [16]: df1.join(df2, how='right')
Out[16]:
       体重   名前   性別   身長         誕生日
3B004 NaN  NaN  NaN  NaN  1981/01/01
3B005  79   山田    男  181  1982/02/02
3B003  71   鈴木    男  173  1983/03/03
3B002  51   佐藤    女  159  1984/04/04

2. では、 concat のための準備を

In [1]: import pandas as pd

In [2]: df1 = pd.DataFrame({
   ...: u'名前': [u'山田', u'鈴木', u'佐藤', u'木村'],
   ...: u'性別': [u'男', u'男', u'女', u'女'] ,
   ...: u'身長': [181, 173, 159, 164],
   ...: u'体重': [79, 71, 51, 52]
   ...: },
   ...: index=['3B005', '3B003', '3B002', '3B001']
   ...: )

In [3]: df2 = pd.DataFrame({
   ...: u'名前': [u'田中', u'山田', u'鈴木', u'佐藤'],
   ...: u'誕生日': ['1981/01/01', '1982/02/02', '1983/03/03', '1984/04/04']
   ...: },
   ...: index=['3B004','3B005','3B003', '3B002']
   ...: )

In [4]: df1
Out[4]:
       体重  名前 性別   身長
3B005  79  山田  男  181
3B003  71  鈴木  男  173
3B002  51  佐藤  女  159
3B001  52  木村  女  164

In [5]: df2
Out[5]:
       名前         誕生日
3B004  田中  1981/01/01
3B005  山田  1982/02/02
3B003  鈴木  1983/03/03
3B002  佐藤  1984/04/04

3. で、 concat を

merge や join は横につなぐイメージ (結合) だが、 concat は縦につなぐイメージ (連結)。通常の python の list + list のようなものだ。

In [6]: df3 = pd.concat([df1, df2])

In [7]: df3
Out[7]:
       体重  名前   性別         誕生日   身長
3B005  79  山田    男         NaN  181
3B003  71  鈴木    男         NaN  173
3B002  51  佐藤    女         NaN  159
3B001  52  木村    女         NaN  164
3B004 NaN  田中  NaN  1981/01/01  NaN
3B005 NaN  山田  NaN  1982/02/02  NaN
3B003 NaN  鈴木  NaN  1983/03/03  NaN
3B002 NaN  佐藤  NaN  1984/04/04  NaN

レコードは単純に追加されるので、index が同じでも関係がなく、別のレコードして追加される。同じ名前のカラムは統合され、そうでないものは追加される。

In [8]: df3.columns
Out[8]: Index([u'体重', u'名前', u'性別', u'誕生日', u'身長'], dtype=object)

In [9]: df3.index
Out[9]: Index([u'3B005', u'3B003', u'3B002', u'3B001', u'3B004', u'3B005', u'3B003', u'3B002'], dtype=object)

連結後は index が一意になってないことに注意。DataFrame の index は RDBMS のようにユニーク制約という訳ではないようだ。その代わりに (?)、ユニークかどうかをチェックすることができる。

In [10]: df3.index.is_unique
Out[10]: False

今回はこんなところで。