2017-03-07 67 views
0

我有兩個相當大的Pandas數據框,像〜300k行,一個有N〜30列(包括一個「Description」之一),另一個只有一個「Description」列。第一個df包含完整的數據,但有一些線條太多(幾千)和其他一些缺失線條(大約600),大致均勻地散佈在整個數據中;另一個正確地指定行,但沒有任何其他數據。我想將它們合併成一個單一的數據框,它具有由後者指定的行和前者的信息(即,丟棄不出現在後者中的行並在需要的地方創建新行,例如用nan's填充)。所以最終的數據幀應該有M×N的大小,M是第二個數據幀的行數。在版本合併樣式中合併使用索引的Pandas數據框

這將是一個pandas.merge的原型案例,如果不是我想要合併的鍵具有重複的事實。它們「大多是獨一無二的」,但有些條目會重複(通常在不少於100行之後),我不希望它們多次出現。相反,我想做一些看起來像「版本控制」的東西,即逐行比較以獲得兩個描述的最佳匹配,刪除第一個數據框中添加的行,並從正確的行中推出新的行。事實上,如果我只提取兩個CSV中的兩個df的「描述」列,我就可以輕鬆地用手工完成我需要的工作。融合(線條足夠長以至於在如何檢查相等的線條時確實沒有模棱兩可),但是1)這很慢並且2)它不能解決我的問題(最終我會得到第二個數據框,因爲我不得不放棄其他列使用融合)。

爲了舉例說明,說我有以下兩個dataframes:

df1 = pd.DataFrame({'Description': ['A','B','Y','D','A','E','F','Y','B'], 'Values': np.arange(9)**2}) 
df2 = pd.DataFrame({'Description': ['A','B','D','A','E','B','F','B']}) 

>>> df1 
    Description Values 
0 A 0 
1 B 1 
2 Y 4 
3 D 9 
4 A 16 
5 E 25 
6 F 36 
7 Y 49 
8 B 64 
>>> df2 
    Description 
0 A 
1 B 
2 D 
3 A 
4 E 
5 B 
6 F 
7 B 

一個我想獲得的是:

Description Values 
0 A 0.0 
1 B 1.0 
2 D 9.0 
3 A 16.0 
4 E 25.0 
5 B NaN 
6 F 36.0 
7 B 64.0 

唯一一種-的解決方案,我發現是添加一列到複製索引的第一個數據框只需

df1['id'] = df1.index 

(我知道的是標準d,即np.arange(len(df1))),使用pd.merge(df1, df2, how='right'),然後從合併的數據幀中提取對應於列id的最大增加序列的索引。爲此,參見例如Longest increasing subsequence這將需要適應,以便始終包括序列中的任何NaN。然而,在重新發明輪子之前,我想知道是否有人知道這個代碼的一個已經存在的實現,也許在某些用於自動化版本控制的包中?

編輯:在以前版本的問題df2df2 = pd.DataFrame({'Description': ['A','B','D','A','E','Z','F','B']})。閱讀@jezrael的第一個答案,我意識到它建議額外的行是由字母Z「特殊」,但實際上它們將出現在數據框的其他地方。這使@jezrael提出了一個非常好的和優雅的答案,但不幸的是這並不適合我。

另一方面,對於一個稍微簡化的假設,實際上要刪除的行是比較特殊的,所以我將它們重命名爲'Y',因爲我可以事先刪除它們並忽略這部分問題 - 「增加「部分是我真正關心的。

回答

1

我認爲你需要創建具有不同價值觀的新列,其中重複的內容cumcount

df1['a'] = df1.groupby('Description').cumcount() 
df2['a'] = df2.groupby('Description').cumcount() 

print (df1) 
    Description Values a 
0   A  0 0 
1   B  1 0 
2   C  4 0 
3   D  9 0 
4   A  16 1 
5   E  25 0 
6   F  36 0 
7   A  49 2 
8   B  64 1 
print (df2) 
    Description a 
0   A 0 
1   B 0 
2   D 0 
3   A 1 
4   E 0 
5   Z 0 
6   F 0 
7   B 1 

print (pd.merge(df1, df2, how='right', on=['Description','a'])) 
     Description Values a 
0   A  0.0 0 
1   B  1.0 0 
2   D  9.0 0 
3   A 16.0 1 
4   E 25.0 0 
5   F 36.0 0 
6   B 64.0 1 
7   Z  NaN 0 

如果順序很重要,加reset_indexsort_values和持續drop助手列:

df = pd.merge(df1, df2.reset_index(), how='right', on=['Description','a']) 
df = df.sort_values('index').drop(['a','index'], axis=1) 
print (df) 
     Description Values 
0   A  0.0 
1   B  1.0 
2   D  9.0 
3   A 16.0 
4   E 25.0 
7   Z  NaN 
5   F 36.0 
6   B 64.0 
+0

感謝快速回答!不幸的是,儘管這解決了我寫的例子,但我擔心一般情況下還有一個難題使得這個解決方案無法工作:df2中的附加行很可能已經出現在其他地方(在df1和df2中)。例如。 df2 = pd.DataFrame({'Description':['A','B','D','A','E','C','F','B']})。在這種情況下,您的解決方案會將C值賦予該行,而不是NaN(如果還有其他C向下,則會打破所有匹配,因爲cumcount()與此不同) –

+1

:('merge' is不是有'重複'值的朋友,現在我沒有其他的想法了。你能否通過評論中的值來改變樣本? – jezrael

+0

編輯這個問題,謝謝!我也非常感謝答案,我學會了cumcount()命令今天:-) –