Python で解析 9
“Advent Calendar 2013 - Python で解析!” の九日目。DataFrame - 6
1. お決まりの準備を…
今回は DataFrame のマージについて。マージとは、二つのデータフレームを結合することで、SQL で言うところの join と同等のもので、数学的には集合演算とかベン図とか…を思い出してもらえればいいだろう。さて、その前にいつものように準備を。
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] ...: }) In [3]: df2 = pd.DataFrame({ ...: u'名前': [u'田中', u'山田', u'鈴木', u'佐藤'], ...: u'性別': [u'男', u'女', u'男', u'女'] , ...: u'誕生日': ['1981/01/01', '1982/02/02', '1983/03/03', '1984/04/04'] ...: }) In [4]: df1 Out[4]: 体重 名前 性別 身長 0 79 山田 男 181 1 71 鈴木 男 173 2 51 佐藤 女 159 3 52 木村 女 164 In [5]: df2 Out[5]: 名前 性別 誕生日 0 田中 男 1981/01/01 1 山田 女 1982/02/02 2 鈴木 男 1983/03/03 3 佐藤 女 1984/04/04
今回はマージを取り扱うので、データは二つ用意する。誕生日のデータの方には、田中くんが増えていて、山田さんが女性になっていて、木村さんがいないという違いがある。そして、データの順番が一致していない。マージの振る舞いを確認するために、わざと少しばかりややこしくしている。
1. 何も考えずにマージ
In [6]: pd.merge(df1, df2) Out[6]: 体重 名前 性別 身長 誕生日 0 71 鈴木 男 173 1983/03/03 1 51 佐藤 女 159 1984/04/04
件数が少なくなってしまったが、表示されている各数値に間違いはないので、どうやらマージはできたようだ。
2. キーカラムを指定してマージ
Pandas の merge は、指定したそれぞれの DataFrame の同じカラム名をキーにしてマージする。なので、実は次のようにカラム名を指定したのと同じことなのだ。
In [7]: pd.merge(df1, df2, on=[u'名前', u'性別']) Out[7]: 体重 名前 性別 身長 誕生日 0 71 鈴木 男 173 1983/03/03 1 51 佐藤 女 159 1984/04/04
SQL もこのぐらい便宜を計らってほしいものだが…というのはさておき…。
試しに性別がキーに含まれないようにして、名前だけでマージすると次のようになる。
In [8]: pd.merge(df1, df2, on=u'名前') Out[8]: 体重 名前 性別_x 身長 性別_y 誕生日 0 79 山田 男 181 女 1982/02/02 1 71 鈴木 男 173 男 1983/03/03 2 51 佐藤 女 159 女 1984/04/04
性別が一致しなくても、名前だけで一致すればいいので、山田氏のレコードが増えた。その一方で、性別項目が二つできている。性別のサフィックスの '_x' が左に書いた df1 のもので、'_y' が右に書いた df2 のもの。
3. レコード数の差異を制御
df1 と df2 が完全に一致してないので、それをどう取り扱うかを制御してみる。SQL で言うところの left join とか outer join とか…のことだ。
最初の例では 2 件になってしまったが、それは両方に存在するレコードのみが抽出されたからで、以下と同等。
In [9]: pd.merge(df1, df2, how='inner') Out[9]: 体重 名前 性別 身長 誕生日 0 71 鈴木 男 173 1983/03/03 1 51 佐藤 女 159 1984/04/04
左側 (すなわち df1) さえあれば、右側 (すなわち df2) がなくてもかまわないなら、次のように書く。
In [10]: pd.merge(df1, df2, how='left') Out[10]: 体重 名前 性別 身長 誕生日 0 79 山田 男 181 NaN 1 71 鈴木 男 173 1983/03/03 2 51 佐藤 女 159 1984/04/04 3 52 木村 女 164 NaN
逆に左側がなくても、右側さえあれば良いなら、次のように書く。
In [11]: pd.merge(df1, df2, how='right') Out[11]: 体重 名前 性別 身長 誕生日 0 71 鈴木 男 173 1983/03/03 1 51 佐藤 女 159 1984/04/04 2 NaN 田中 男 NaN 1981/01/01 3 NaN 山田 女 NaN 1982/02/02
どちらか片方にさえあれば有効とするなら、how に 'outer' を指定する。
In [12]: pd.merge(df1, df2, how='outer') Out[12]: 体重 名前 性別 身長 誕生日 0 79 山田 男 181 NaN 1 71 鈴木 男 173 1983/03/03 2 51 佐藤 女 159 1984/04/04 3 52 木村 女 164 NaN 4 NaN 田中 男 NaN 1981/01/01 5 NaN 山田 女 NaN 1982/02/02
これが最大件数になる。
いずれの例でも同じく、データが存在しないところは NaN (Not a Number) となる。
なお、ここまでの例で 'pd.mege()' としているが、'df1.merge(df2)' のように書くことともできる。今回の説明の on や how の意味も同じように使える。'df1.merge(df2)' の方がオブジェクト指向らしい書き方なのだが、軽く調べた限りではマイノリティーな感じ。データマイニングする人は、オブジェクト指向にこだわらない傾向があるのかもしれない。
今回はこんなところで。