Pandas 集中講座 その4 マージ(結合)
Pandasライブラリを覚えたい!公式「10 Minutes to pandas」をモチーフに使って実際に動作させ学習する。第4回 マージ(結合)
Pandas 集中講座(4)
Pandas 集中講座 その1 - chiyoh’s blog
Pandas 集中講座 その2 - chiyoh’s blog
Pandas 集中講座 その3 - chiyoh’s blog
Pandas 集中講座 その4 - chiyoh’s blog
Pandas 集中講座 その5 - chiyoh’s blog
Pandas 集中講座 その6 - chiyoh’s blog
Pandasとは、なにか?
初め考えていたのは、EXCELシートも扱えるPython版スプレッドシートライブラリ。 VBAの代わりにマクロをPython上で実行できる便利なものと考えていた。
Pandasを実際に使ってみると
始めて使ったのは、テキストデータをEXCELのxlsxに変換しておきたかったから。実際に変換してみると思ったより難しい(実際には、我々がEXCELを表計算としてとらえていなくて計算機能と印刷機能を持つワープロとして使っているのが原因)。また、Pandasも高機能なので出来ることが多く大いに迷ったが、それでもEXCELファイルの書き出しに成功したのでこれは便利だ!ということでこれを機に少し使ってみようと考えた。
公式「10 Minutes to pandas」を実際にやってみる (4/6)
Pandasを覚える!さて、グーグル先生に教えてもらえば大抵のことは分かるのだが、それが今の最適解なのか?と考えるとそうではない。グーグル先生のサーチ機能は、カンニングペーパーであり、単語帳である。欲しい答えを最小ステップでたどり着くための方法。例えるなら、望遠鏡、又は顕微鏡で拡大されたエリアで見つけた希望(答え)。なぜそうなるのか?なぜそう書けば動くのか?など、答えに対する成り立ちがすっぽり抜けてしまうのである。最近のPython環境は、Jupyter Notebookで敷地も下がって来ている。入門書や学習本を眺めて図を見てなんとなくへーとか言って分かった気になって何も残らないパターンになりかねない。今回選んだ方法は、グーグル先生の支援のもと公式のチュートリアル以前のPandas概要説明『10 Minutes to pandas』を上から順にJupyter Notebookを使い実行していってみようと思う。これにより、学習講座のWorkshop形式で講師が腹痛で欠席したので自己学習してなさい版くらいの知識に残ることを期待。実行した結果をここに残し、その時のメモ書きとエッセンスと晒してみる。
【解説】公式「10 Minutes to pandas」をJupyter Notebookを使って動作させながら確認し、突っ込みを入れる!(この文章を見る価値としては、原書が何をやっているのかが分かる、、、分かるはずである)
公式「10 Minutes to pandas」を実際にやってみる
6.マージ
CONCAT
Pandasは、結合/マージ型操作の場合に、Series、DataFrame、およびPanelオブジェクトを、インデックスおよびリレーショナル代数機能のためのさまざまな種類の設定ロジックと簡単に組み合わせるためのさまざまな機能を提供します。
マージセクションを参照してください。以下と一緒にパンダオブジェクトを連結するconcat():
df = pd.DataFrame(np.random.randn(10, 4)) df
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 0.604099 | 0.990079 | -0.521005 | 0.794407 |
1 | -1.028698 | -0.426349 | -1.379724 | -0.316860 |
2 | 1.980853 | -1.300201 | 1.245424 | 1.271737 |
3 | 1.547143 | 0.859297 | 0.453607 | 0.972436 |
4 | 0.976275 | 0.075214 | 0.576674 | -1.065869 |
5 | 0.143601 | -1.579016 | -0.335929 | -0.560030 |
6 | 1.771954 | -0.239358 | -0.652136 | -0.414211 |
7 | 0.107051 | 0.061522 | 0.685471 | 1.188601 |
8 | 1.958523 | -0.195262 | -0.214413 | 0.463809 |
9 | -0.913350 | -0.467059 | 1.669981 | -0.923343 |
pieces = [df[:3], 0*df[7:], df[3:7]] pieces
[ 0 1 2 3
0 0.604099 0.990079 -0.521005 0.794407
1 -1.028698 -0.426349 -1.379724 -0.316860
2 1.980853 -1.300201 1.245424 1.271737, 0 1 2 3
7 0.0 0.0 0.0 0.0
8 0.0 -0.0 -0.0 0.0
9 -0.0 -0.0 0.0 -0.0, 0 1 2 3
3 1.547143 0.859297 0.453607 0.972436
4 0.976275 0.075214 0.576674 -1.065869
5 0.143601 -1.579016 -0.335929 -0.560030
6 1.771954 -0.239358 -0.652136 -0.414211]
【解説】indexをスライスしてDataFrameを3つに分ける。0~2,3~6,7~9、アクセントとして7~9は、0を書けてゼロのスカラーにしてみた。それをリスト化した。
p_df = pd.concat(pieces) p_df
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 0.604099 | 0.990079 | -0.521005 | 0.794407 |
1 | -1.028698 | -0.426349 | -1.379724 | -0.316860 |
2 | 1.980853 | -1.300201 | 1.245424 | 1.271737 |
7 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
8 | 0.000000 | -0.000000 | -0.000000 | 0.000000 |
9 | -0.000000 | -0.000000 | 0.000000 | -0.000000 |
3 | 1.547143 | 0.859297 | 0.453607 | 0.972436 |
4 | 0.976275 | 0.075214 | 0.576674 | -1.065869 |
5 | 0.143601 | -1.579016 | -0.335929 | -0.560030 |
6 | 1.771954 | -0.239358 | -0.652136 | -0.414211 |
【解説】ちょっとアレンジを加えた。pd.concat
を使うことで、DataFrameの3つのリストが1つのDataFrameになった。
リストの頭から、順にindexに入っていることがわかる。元々付けられているIndexラベルがそのままになっている。
t = (p_df[0][8], p_df[1][8]) t
(0.0, -0.0)
t[0] == t[1]
True
【コメント】index=8ラベルで0掛けた結果-0と0と分離してしまった。 [https://ja.wikipedia.org/wiki/IEEE_754%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E8%B2%A0%E3%81%AE%E3%82%BC%E3%83%AD]
参加する
SQLスタイルのマージ データベーススタイルの結合の節を参照してください。
left = pd.DataFrame({'key': ['foo', 'foo'], 'lval': [1, 2]}) right = pd.DataFrame({'key': ['foo', 'foo'], 'rval': [4, 5]})
left
key | lval | |
---|---|---|
0 | foo | 1 |
1 | foo | 2 |
right
key | rval | |
---|---|---|
0 | foo | 4 |
1 | foo | 5 |
pd.merge(left, right, on='key')
key | lval | rval | |
---|---|---|---|
0 | foo | 1 | 4 |
1 | foo | 1 | 5 |
2 | foo | 2 | 4 |
3 | foo | 2 | 5 |
【解説】pd.merge
でマージである。引数でleft、次にrightそして、on='key'となっている。つまり、ベースはleft、追加はright、マージキーは'key'となり、indexを上から見ていく。マージなので2つのleft、right共に同じキーの時出力され同じ出でなければ破棄される。
l = 0 for lkey in left['key']: r =0 for rkey in right['key']: if lkey == rkey: print(lkey,left['lval'][l],right['rval'][r]) r+=1 l+=1
foo 1 4
foo 1 5
foo 2 4
foo 2 5
【解説】な感じに、leftとrightでの2重ループで同じキーかどうか確認して、同じであれば、マージして出力する。なので、keyの値が同じだと総当たりの組み合わせが出力されることになる。
pd.merge(left, right)
key | lval | rval | |
---|---|---|---|
0 | foo | 1 | 4 |
1 | foo | 1 | 5 |
2 | foo | 2 | 4 |
3 | foo | 2 | 5 |
与えることができるもう一つの例は次のとおりです。
left = pd.DataFrame({'key': ['foo', 'bar'], 'lval': [1, 2]}) right = pd.DataFrame({'key': ['foo', 'bar'], 'rval': [4, 5]})
left
key | lval | |
---|---|---|
0 | foo | 1 |
1 | bar | 2 |
right
key | rval | |
---|---|---|
0 | foo | 4 |
1 | bar | 5 |
pd.merge(left, right, on='key')
key | lval | rval | |
---|---|---|---|
0 | foo | 1 | 4 |
1 | bar | 2 | 5 |
【解説】今度のマージデータは、キーが一意なのでfooとbarが1ずつしかないので横付けマージと同じ結果になる。
追加
データフレームに行を追加します。付録を参照してください 。
df = pd.DataFrame(np.random.randn(8, 4), columns=['A', 'B', 'C', 'D']) df
A | B | C | D | |
---|---|---|---|---|
0 | 1.667774 | -0.436216 | -1.308609 | -0.271015 |
1 | 0.801015 | 0.398531 | 0.215097 | -1.087617 |
2 | 1.765974 | -0.364113 | -0.033961 | 1.117321 |
3 | 1.205805 | 0.155813 | -0.550467 | 1.129920 |
4 | -0.713234 | -0.595935 | -0.266757 | 1.690120 |
5 | -1.172786 | -0.069766 | 0.653920 | -0.537090 |
6 | -0.619824 | -0.507945 | -0.369917 | 0.600396 |
7 | -1.825166 | 2.128321 | 1.500123 | -1.485171 |
s = df.iloc[3]
s
A 1.205805
B 0.155813
C -0.550467
D 1.129920
Name: 3, dtype: float64
df.append(s, ignore_index=True)
A | B | C | D | |
---|---|---|---|---|
0 | 1.667774 | -0.436216 | -1.308609 | -0.271015 |
1 | 0.801015 | 0.398531 | 0.215097 | -1.087617 |
2 | 1.765974 | -0.364113 | -0.033961 | 1.117321 |
3 | 1.205805 | 0.155813 | -0.550467 | 1.129920 |
4 | -0.713234 | -0.595935 | -0.266757 | 1.690120 |
5 | -1.172786 | -0.069766 | 0.653920 | -0.537090 |
6 | -0.619824 | -0.507945 | -0.369917 | 0.600396 |
7 | -1.825166 | 2.128321 | 1.500123 | -1.485171 |
8 | 1.205805 | 0.155813 | -0.550467 | 1.129920 |
【解説】df.append
を使ってindexの最後に行を追加する。追加するのは、スライスされたindex=3ラベルのDataFrame。もちろんindexラベル3が付いているが、これを無視して最後に追加自動附番で8が割り当てられている。
df.append(s)
A | B | C | D | |
---|---|---|---|---|
0 | 1.667774 | -0.436216 | -1.308609 | -0.271015 |
1 | 0.801015 | 0.398531 | 0.215097 | -1.087617 |
2 | 1.765974 | -0.364113 | -0.033961 | 1.117321 |
3 | 1.205805 | 0.155813 | -0.550467 | 1.129920 |
4 | -0.713234 | -0.595935 | -0.266757 | 1.690120 |
5 | -1.172786 | -0.069766 | 0.653920 | -0.537090 |
6 | -0.619824 | -0.507945 | -0.369917 | 0.600396 |
7 | -1.825166 | 2.128321 | 1.500123 | -1.485171 |
3 | 1.205805 | 0.155813 | -0.550467 | 1.129920 |
【解説】ignore_index=Trueを追加しないと元からついているindexが代入される。