やりたいこと
df_A
kome | gu | date |
---|---|---|
ササニシキ | うめ | 20210211 |
ササニシキ | たまご | 20210213 |
コシヒカリ | おかか | 20210315 |
コシヒカリ | しゃけ | 20210511 |
df_B
gu | santi |
---|---|
うめ | 和歌山 |
しゃけ | 北海道 |
おかか | 鹿児島 |
こんぶ | 北海道 |
いくら | 北海道 |
df_Aとdf_Bを使って、df_Aをこうしたい
kome | gu | date | flag |
---|---|---|---|
ササニシキ | うめ | 20210211 | 和歌山 |
ササニシキ | たまご | 20210213 | |
コシヒカリ | おかか | 20210315 | 鹿児島 |
コシヒカリ | しゃけ | 20210511 | 北海道 |
guが一致したらdf_Bの値をdf_Aに追加するイメージ。
前提としてdf_Aとdf_Bのguは一意なものとします。
参考文献はこちら → https://note.nkmk.me/python-pandas-where-mask/
準備
サンプルを作成します。
おにぎりなのは趣味です。
import pandas as pd
import numpy as np
import time
df_A = pd.DataFrame({'kome': ["ササニシキ", "ササニシキ","コシヒカリ","コシヒカリ"],
'gu': ["うめ","たまご","おかか", "しゃけ"],
'date': [20210211, 20210213, 20210315, 20210511]})
df_B = pd.DataFrame({'gu': ["うめ", "しゃけ", "おかか","こんぶ","いくら"],
'santi': ["和歌山", "北海道", "鹿児島", "北海道", "北海道"]})
トライ1
whereを使う方法。
あらかじめ空の列を作成する必要があります。
df_A["flag"] = ""
_start = time.time()
for i in range(len(df_B)):
df_A["flag"].where(df_A["gu"]==df_B.at[i, "gu"],df_B.at[i, "santi"])
# 計測
print(time.time() - _start)
print(df_A)
# 出力結果
# >>> print(time.time() - _start)
# 0.14820408821105957
# >>> print(df_A)
# kome gu date flag
# 0 ササニシキ うめ 20210211
# 1 ササニシキ たまご 20210213
# 2 コシヒカリ おかか 20210315
# 3 コシヒカリ しゃけ 20210511
なぜかうまくいかない。
上書きしないようにしていたのでうまくいかないのは当たり前でした。
が、inplace=Trueにしてもなんか変。
df_A["flag"] = ""
_start = time.time()
for i in range(len(df_B)):
df_A["flag"].where(df_A["gu"]==df_B.at[i, "gu"],df_B.at[i, "santi"] , inplace=True)
# 計測
print(time.time() - _start)
print(df_A)
# 出力結果
# >>> print(time.time() - _start)
# 0.1444559097290039
# >>> print(df_A)
# kome gu date flag
# 0 ササニシキ うめ 20210211 北海道
# 1 ササニシキ たまご 20210213 北海道
# 2 コシヒカリ おかか 20210315 北海道
# 3 コシヒカリ しゃけ 20210511 北海道
潔くあきらめる。
人生諦めが肝心。
トライ2
locを使う方法。
存在しない列を設定してもOK。
_start = time.time()
for i in range(len(df_B)):
df_A.loc[df_A["gu"] == df_B.at[i, "gu"],'flag'] = df_B.at[i, "santi"]
# 計測
print(time.time() - _start)
print(df_A)
# 出力結果
# >>> print(time.time() - _start)
# 0.13238096237182617
# >>> print(df_A)
# kome gu date flag
# 0 ササニシキ うめ 20210211 和歌山
# 1 ササニシキ たまご 20210213
# 2 コシヒカリ おかか 20210315 鹿児島
# 3 コシヒカリ しゃけ 20210511 北海道
うまくいった。
あと微妙にwhereより早めな希ガス。
というわけで採用じゃー!
トライ3(1/27追記)
コメントいただき、mergeをやってみようと思いました。
実環境のデータは列名不一致&df_Bが100列相当なので見直し版。
※これはデータが一意な場合の話になります
import pandas as pd
import numpy as np
import time
df_A = pd.DataFrame({'kome': ["ササニシキ", "ササニシキ","コシヒカリ","コシヒカリ"],
'gu': ["うめ","たまご","おかか", "しゃけ"],
'date': [20210211, 20210213, 20210315, 20210511]})
# 列名の変更とダミー列の追加
df_B = pd.DataFrame({'sozai': ["うめ", "しゃけ", "おかか","こんぶ","いくら"],
'santi': ["和歌山", "北海道", "鹿児島", "北海道", "北海道"],
'santi2': ["和歌山", "北海道", "鹿児島", "北海道", "北海道"]})
#処理開始
_start = time.time()
df_A = pd.merge(df_A, df_B[["sozai", "santi"]], how="left", left_on="gu", right_on="sozai")
df_A = df_A.drop("sozai",axis=1)
# 計測
print(time.time() - _start)
print(df_A)
# 出力結果
# >>> print(time.time() - _start)
# 0.12956595420837402
# >>> print(df_A)
# kome gu date santi
# 0 ササニシキ うめ 20210211 和歌山
# 1 ササニシキ たまご 20210213 NaN
# 2 コシヒカリ おかか 20210315 鹿児島
# 3 コシヒカリ しゃけ 20210511 北海道
santiに該当する部分は名前共通なのでリネームしなくてもいいかなという。
スマートでよき!
1/27追記そのに
なんかおかしいなと思ったら、実環境のデータはキーが一意じゃなかったです。
ので、当方は2の方法を使います……。
確認不足ここに極まれり。