[英]Merge dataframes based on partial string-match between columns
我有兩個數據框 df1 和 df2:
df1 = pd.DataFrame({'a':['123456','123457', '23456', '23457', '345678','345679'],
'b':['e','f','g','h','i','j']})
df2 = pd.DataFrame({'id':['2', '123', '3456'],
'b1':['c1','c2','c3']})
ID b1
2 c1
123 c2
3456 c3
a b
123456 e
123457 f
23456 g
23457 h
456789 i
456789 j
我要創建的內容:
df3 = pd.DataFrame({'a':['123456','123457', '23456', '23457', '345678','345679'],
'b':['e','f','g','h','i','j'],
'id':['123','123','2','2','3456','3456'],
'b1':['c2','c2','c1','c1','c3','c3']})
a b id b1
123456 e 123 c2
123457 f 123 c2
23456 g 2 c1
23457 h 2 c1
456789 i 4567 c3
456789 j 4567 c3
如何根據給定字符 0-N 的“a”中的子字符串(前 N 個字符,N 基於“a1”中字符串的長度)的“a1”匹配將 df2 中的數據合並到 df1 中。
你可以試試這個:
import pandas as pd
import numpy as np
df1 = pd.DataFrame({'a':['123456','123457', '23456', '23457', '345678','345679'],
'b':['e','f','g','h','i','j']})
df2 = pd.DataFrame({'id':['2', '123', '3456'],
'b1':['c1','c2','c3']})
df3_test = pd.DataFrame({'a':['123456','123457', '23456', '23457', '345678','345679'],
'b':['e','f','g','h','i','j'],
'id':['123','123','2','2','3456','3456'],
'b1':['c2','c2','c1','c1','c3','c3']})
starts_with_map = map(df1['a'].str.startswith, df2['id'])
conditions = list(starts_with_map)
choices = range(len(conditions))
select_arr = np.select(conditions,
choices,np.nan)
# array([1., 1., 0., 0., 2., 2.]), we'll use this to access df2.index below in pd.concat
if np.isnan(select_arr).any():
vals = [df2.iloc[int(x),:].values if not np.isnan(x) else [np.nan]*df2.shape[1] for x in select_arr]
df3 = pd.concat([df1,pd.DataFrame(vals, columns=df2.columns)], axis=1)
else:
df3 = pd.concat([df1,df2.iloc[select_arr].reset_index(drop=True)],axis=1)
df3.equals(df3_test)
# True: i.e. result equals your df3_test
解釋代碼:
map(df1['a'].str.startswith, df2['id'])
在可迭代df2['id']
上使用 func startswith
,等等 '2'、'123' 和 '3456'。np.select
。 因此,我們需要conditions
、 choices
和default
(如果不匹配)。conditions = list(starts_with_map)
我們將地圖轉換為 3 個列表的列表(對於df2['id']
中的每個元素)。 首先,它將是:print(conditions[0])
0 False
1 False
2 True # match '2' on '23456' (df1.loc[2,'a'])
3 True # match '2' on '23456' (df1.loc[3,'a'])
4 False
5 False
Name: a, dtype: bool
我們還定義了選擇:我們想要 df2 的適當索引,所以只有 0,1,2,因此: choices = range(len(conditions))
。
最后,我們要添加if/else
構造,以確保在找不到匹配項時不會出錯。 例如,假設df2
看起來像這樣:
df2 = pd.DataFrame({'id':['2', '321', '3456'],
'b1':['c1','c2','c3']})
在這種情況下, select_arr
將變為array([nan, nan, 0., 0., 2., 2.])
(即df1
中沒有匹配'123456','123457
),我們會遇到錯誤嘗試訪問索引nan
處的df2
,該索引不存在。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.