Pandas DataFrameのマージ、データ加工、抽出、ファイル出力
マージ
今回のサンプルでは、プログラムの中でDataFrameを定義します。

import pandas as pd
emp = pd.DataFrame({
    "ID": ["U123", "U124", "U125", "U126", "U127"],
    "名前": ["鈴木", "佐藤", "田中", "渡辺", "山本"],
    "組織ID": ["D1", "D2", "D3", "D2", "D1"]
})
org = pd.DataFrame({
    "組織ID": ["D1", "D2", "D3"],
    "組織名": ["営業部", "製造部", "経理部"]
})

上で定義した2つのDataFrameをいきなりおもむろにマージして1個にしてみましょう。はい。

df = pd.merge(emp, org)
print(df.head(10))

ちゃんと1個になっていることが確認できると思います。
このように、2つのDataFrameに、列名が共通する列が1つだけある場合は、 単にmerge関数でDataFrameを2つ指定するだけで全てが行われます。
そうでない場合の方法は後述することにして、先にこのデータを使って色々やってみます。

# 列の一覧を表示
print(df.columns)
# Index(['ID', '名前', '組織ID', '組織名'], dtype='object')
# 単純に連結したDataFrameの列の並びに沿っていることが分かります。

# 列名から列番号(先頭が0)を取得
print(df.columns.get_loc("組織名"))

# locで指定した人の組織名を表示
print(df.loc[2,"組織名"])

# ilocで指定した人の組織名を表示
print(df.iloc[2, 3])

# 値を変更する
df.iloc[2, 3] = "第二製造部"
print(df)

# 年齢というSeriesを定義して、DataFrameに追加する
ages = pd.Series([30,27,35,38,29])
df["年齢"] = ages
print(df)

ファイル出力

# CSV出力
df.to_csv("/content/drive/MyDrive/colaroot/data/output_merged.csv")

# Excel出力
df.to_excel("/content/drive/MyDrive/colaroot/data/output_merged.xlsx")

条件によるデータの抽出

# 条件を満たす行だけを抽出
print(df[df["年齢"] >= 30])
#     ID  名前 組織ID    組織名  年齢
#0  U123  鈴木   D1    営業部  30
#2  U124  佐藤   D2  第二製造部  35
#3  U126  渡辺   D2    製造部  38

# 複数の条件を連結するときは、&&や||ではなく&と|なので注意。
# また丸括弧は省略できないらしいので注意
print(df[(df["年齢"] >= 30) | (df["組織ID"] == "D1")])
#     ID  名前 組織ID    組織名  年齢
#0  U123  鈴木   D1    営業部  30
#1  U127  山本   D1    営業部  27
#2  U124  佐藤   D2  第二製造部  35
#3  U126  渡辺   D2    製造部  38

# 上の例ではdf[]を二重に記述する必要がありますが、queryを使うとSQLのWHERE句みたいに書けます。
# ちなみに列名が空白文字を含む場合は、バッククォートで囲めばOKだそう
print(df.query("年齢 >= 30"))

# queryの場合はandやorになる。ORのように大文字にはできないので注意
print(df.query("年齢 >= 30 or 組織ID == 'D1'"))

# 「30歳か35歳」という条件はisinで抽出できる
print(df[df["年齢"].isin([30,35])])
#     ID  名前 組織ID    組織名  年齢
#0  U123  鈴木   D1    営業部  30
#2  U124  佐藤   D2  第二製造部  35

# 同じ操作のquery版。こちらは角括弧ではなく丸括弧です。覚えるしかない
print(df.query("年齢 in (30,35)"))

# 変数が使える。変数はqueryの中で@をつけて参照できる
x = 35
print(df.query("年齢 >= @x"))
x = (35,36,37)
print(df.query("年齢 in @x"))

ソートやその他の操作

# 最大値の取得
print(df["年齢"].max())

# 年齢の降順でソート。並び順が変わるだけで、Indexはソートされないので注意
a = df.sort_values(by="年齢")
print(a)
#     ID  名前 組織ID    組織名  年齢
#1  U127  山本   D1    営業部  27
#4  U125  田中   D3    経理部  29
#0  U123  鈴木   D1    営業部  30
#2  U124  佐藤   D2  第二製造部  35
#3  U126  渡辺   D2    製造部  38

# 組織IDの昇順、年齢の降順でソート
a = df.sort_values(by=["組織ID","年齢"], ascending=[True,False])
print(a)

マージ処理のオプション

emp2 = pd.DataFrame({
    "ID": ["U123", "U124", "U125", "U126", "U127"],
    "名前": ["鈴木", "佐藤", "田中", "渡辺", "山本"],
    "所属": ["D1", "D2", "D3", "D2", "D4"]
})
org2 = pd.DataFrame({
    "組織ID": ["D1", "D2", "D3"],
    "組織名": ["営業部", "製造部", "経理部"]
})
df2 = pd.merge(emp2, org2, left_on="所属", right_on="組織ID", how="left")
print(df2)
#     ID  名前  所属 組織ID  組織名
#0  U123  鈴木  D1   D1  営業部
#1  U124  佐藤  D2   D2  製造部
#2  U125  田中  D3   D3  経理部
#3  U126  渡辺  D2   D2  製造部
#4  U127  山本  D4  NaN  NaN

冒頭で行ったマージ処理の補足です。この例では二つの事を説明しています。 まず、DataFrameの連結(JOIN)に使いたい列の名前が異なる場合はどうするの? 上の例のように、merge関数のleft_onで左のDataFrameの列名(ここでは"所属")、 right_onで右の列名(ここでは"組織名")を指定すればOKです。
またその所属列のように、連結キー列の値の中に片側にしかないものがある場合(この例では"D4")どうなるの? これは、SQLの用語でいわゆる外部結合の指定と同じことがmerge関数のhow=で可能です。 上記の例ではleft、つまり「左外部結合」、つまり左側のDataFrameの連結キーに右側にはない物がある場合、 そのレコードを削除することはせずに足りない情報の部分をNaN(SQLのNULLに相当)で補っています。
howに指定できる値は4種類、inner、left、right、outerです。SQLの外部結合をご存じの方は多分類推通りの処理になります。 howを省略した際のデフォルトはinner、つまりINNER JOIN=内部結合、 つまり連結キー列の値が片方にしかない場合、その行は削除されて連結されます。

Misc. Topics Top

(first uploaded 2024/01/06 last updated (not ever), URANO398)