簡體   English   中英

基於列之間的部分字符串匹配合並數據幀

[英]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 因此,我們需要conditionschoicesdefault (如果不匹配)。
  • 使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM