"BOKU"のITな日常

62歳・文系システムエンジニアの”BOKU”は日々勉強を楽しんでます

Pandas:DataFrameの結合・分割のあれこれとCSV保存

Pandasで、データを結合したり分割したりするパターンをまとめてみます。

f:id:arakan_no_boku:20200329000112p:plain

 

 はじめに

 

今回は「結合」・「分割」です。

pandasには多くの機能があり、いろんなやり方ができますが、自分で使うのは割と一定のパターンに限られるので、とりあえず、それだけまとめます。

pandas.pydata.org

コード例は、以下がインポートされている前提とします。

import pandas as pd

例のデータは 以下の要領でCSVファイルを読み込んだ「t」というDataFrameがある想定で例を書いていきます。

t = pd.read_csv('./csvdata/a.csv')

 

 

 データ結合

 

2つのDataFrameをくっつけます。

行追加(ユニオン)と列追加(ジョイン)があります。

さらに、ジョインには

  • 両方に存在するデータのみ結合する:inner_join
  • 片側だけに存在するデータでも結合する:outer_join

があります。

さらに、outer_joinには、構文に書くときの位置関係で

  • 左側に存在するデータを軸に結合する:left_outer_join
  • 右側に存在するデータを軸に結合する:right_outer_join

があります。

 

行追加(ユニオン)

 

concatを使います。

t1 = pd.read_csv('csvdata/t_1.csv')
t2 = pd.read_csv('csvdata/t_2.csv')
t = pd.concat([t1, t2], ignore_index=True)

これでt1にt2の行が追加されます。

ignore_index=Trueを指定しているので、インデックスは0から振りなおされます。

 

 列追加(ジョイン)

 

 以下の2つのデータでJOINしてみます。

こちらが「a.csv

id  name   price
0 S01 アイテムA 500
1 S02 アイテムB 850
2 S07 アイテムF 500
3 S08 アイテムG 850
4 S09 アイテムH 1200

こちらが「b.csv」です。

  id     cate size
0 S01 food big
1 S02 food small
2 S03 drink medium
3 S04 food big
4 S06 drink small

これを、idをキーにして結合します。

 

left outer(左側だけ存在するデータでも結合)

a = pd.read_csv('./csvdata/a.csv')
b = pd.read_csv('./csvdata/b.csv')
jd = pd.merge(a, b, on="id", how="left")
print(jd)    

結果です。

  id name price cate size
0 S01 アイテムA 500 food big
1 S02 アイテムB 850 food small
2 S07 アイテムF 500 drink medium
3 S08 アイテムG 850 NaN NaN
4 S09 アイテムH 1200 NaN NaN 

右側(b.csv)にないカラムは「NaN」になっています。 

 

right outer(右側だけ存在するデータでも結合)

a = pd.read_csv('./csvdata/a.csv')
b = pd.read_csv('./csvdata/b.csv')
jd = pd.merge(a, b, on="id", how="right")
print(jd)

結果です。 

  id name price cate size
0 S01 アイテムA 500.0 food big
1 S02 アイテムB 850.0 food small
2 S07 アイテムF 500.0 drink medium
3 S03 NaN NaN drink medium
4 S04 NaN NaN food big
5 S06 NaN NaN drink small

左側(a.csv)にないカラムは「NaN」になってます。

 

inner(両方に存在するデータのみ結合)

a = pd.read_csv('./csvdata/a.csv')
b = pd.read_csv('./csvdata/b.csv')
jd = pd.merge(a, b, on="id", how="inner")
print(jd)

結果です。 

  id name price cate size
0 S01 アイテムA 500 food big
1 S02 アイテムB 850 food small
2 S07 アイテムF 500 drink medium 

 

列追加

 

単価と数があるデータに合計額列を追加するパターンです。

例えば、こんなデータを「c」として

id name item_price count
0 S01 アイテムA 500 4
1 S02 アイテムB 850 2
2 S07 アイテムF 500 6
3 S08 アイテムG 850 4
4 S09 アイテムH 1200 1

item_price列とcount列を掛け合わせて、あたらしいprice列を作ると

c["price"] = c["item_price"] * c["count"]
print(c.head())

結果はこうなります。 

id name item_price count price
0 S01 アイテムA 500 4 2000
1 S02 アイテムB 850 2 1700
2 S07 アイテムF 500 6 3000
3 S08 アイテムG 850 4 3400
4 S09 アイテムH 1200 1 1200

 

データ分割 

 

行分割する場合と列分割があります。

 

単純に行をわける分割

例えば、上記のこのDataFrame「c」を、3行とそれ以降にわけます。

c1 = c[:3]
c2 = c[3:]

これで、こんな感じにわかれます。 

id name item_price count price
0 S01 アイテムA 500 4 2000
1 S02 アイテムB 850 2 1700
2 S07 アイテムF 500 6 3000


id name item_price count price
3 S08 アイテムG 850 4 3400
4 S09 アイテムH 1200 1 1200

Pythonのスライスのイメージです。

 

グルーピングしてグループごとに行分割

ようするに。

  id name price cate size
0 S01 アイテムA 500.0 food big
1 S02 アイテムB 850.0 food small
2 S07 アイテムF 500.0 drink medium
3 S03 NaN NaN drink medium
4 S04 NaN NaN food big
5 S06 NaN NaN drink small

こういうデータを「cate」列の「food」グループと「drink」グループ単位で行分割して2つのDataFrameにわけます。

gjd_food = jd.groupby("cate").get_group("food")
print(gjd_food)
gjd_drink = jd.groupby("cate").get_group("drink")
print(gjd_drink)

実行した結果は、こう分かれます。 

foodグループと、drinkグループになってます。

  id name price cate size
0 S01 アイテムA 500.0 food big
1 S02 アイテムB 850.0 food small
4 S04 NaN NaN food big


id name price cate size
2 S07 アイテムF 500.0 drink medium
3 S03 NaN NaN drink medium
5 S06 NaN NaN drink small 

 

列単位の分割

 

上記の例を、キーとして「id」列を残して、「name」・「price」と「cate」・「size」の2つのDataFrameにわけてみます。

f:id:arakan_no_boku:20200526215609p:plain

結果はこうなります。
選択した列のみのDataFrameに分割されてます。

  id name price
0 S01 アイテムA 500.0
1 S02 アイテムB 850.0
2 S07 アイテムF 500.0
3 S03 NaN NaN
4 S04 NaN NaN
5 S06 NaN NaN


id cate size
0 S01 food big
1 S02 food small
2 S07 drink medium
3 S03 drink medium
4 S04 food big
5 S06 drink small

 

 

CSV形式ファイルに保存

 

結合・分割と関係ないですが、DataFrameをCSVファイルに保存するパターンもついでに書いておきます。

CSV保存をデフォルトでやってしまうと

  • セパレータは「,(カンマ)」
  • index(行番号)も出力する
  • headerも出力する

で保存されます。

でも、普通行番号(index)はいりません。

なので、「false」を指定して保存しないようにします。

1.to_csv("csvdata/r1.csv", index=False) 

あと。

漢字が含まれ、かつ、出力したCSVWindows版のExcelで使うなら、漢字コードを「SJIS」にします。

1.to_csv("csvdata/r1.csv", index=False, encoding="shift_jis")  

ヘダーを出力せず、セパレータを「タブ(\t)」にする場合です。

1.to_csv("csvdata/r1.csv", sep="\t", index=False, header=False)

この回はこんな感じで。

ではでは。