2017-01-10 163 views
3

我試圖合併/連接兩列都有相關,但由「|」分隔的單獨文本數據除了用「」替換某些名稱並替換| '\ n'。按列表順序合併兩個數據幀列表

例如,原始數據可能是:

First Names   Last Names 
0 Jim|James|Tim   Simth|Jacobs|Turner 
1 Mickey|Mini   Mouse|Mouse 
2 Mike|Billy|Natasha  Mills|McGill|Tsaka 

如果我想合併/連擊導出全名並刪除綁「史密斯」最後的DF應該像條目:

First Names   Last Names   Full Names 
0 Jim|James|Tim   Simth|Jacobs|Turner James Jacobs\nTim Turner 
1 Mickey|Mini   Mouse|Mouse   Mickey Mouse\nMini Mouse 
2 Mike|Billy|Natasha  Mills|McGill|Tsaka Mike Mills\nBilly McGill\nNatasha Tsaka 

我目前的做法迄今已有:

def parse_merge(df, col1, col2, splitter, new_col, list_to_exclude): 

    orig_order = pd.Series(list(df.index)).rename('index') 

    col1_df = pd.concat([orig_order, df[col1], df[col1].str.split(splitter, expand=True)], axis = 1) 
    col2_df = pd.concat([orig_order, df[col2], df[col2].str.split(splitter, expand=True)], axis = 1) 

    col1_melt = pd.melt(col1_df, id_vars=['index', col1], var_name='count') 
    col2_melt = pd.melt(col2_df, id_vars=['index', col2], var_name='count') 

    col2_melt['value'] = '(' + col2_melt['value'].astype(str) + ')' 
    col2_melt = col2_melt.rename(columns={'value':'value2'}) 

    melted_merge = pd.concat([col1_melt, col2_melt['value2']], axis = 1) 

    if len(list_to_exclude) > 0: 
     list_map = map(re.escape, list_to_exclude) 

    melted_merge.ix[melted_merge['value2'].str.contains('|'.join(list_map)), ['value', 'value2']] = '' 

    melted_merge[new_col] = melted_merge['value'] + " " + melted_merge['value2'] 

如果我叫:

parse_merge(names, 'First Names', 'Last Names', 'Full Names', ['Smith']) 

的數據變爲:

Index First Names  count value   value2  Full Names 
0 0  Jim|James|Tim  0  Jim    Smith   '' 
1 1  Mickey|Mini  0  Mickey   Mouse   Mickey Mouse 
2 2  Mike|Billy|Natasha 0  Mike    Mills   Mike Mills 

只是不知道如何完成這一點沒有任何循環或是否有更有效的/完全不同的方法。

感謝您的所有意見!

回答

2

我有一個很多理解

l = df.values.tolist() 

['|'.join(n) 
for n in [[' '.join(z) 
for z in zip(*[s.split('|') 
for s in r]) if z[1] != 'Smith'] 
for r in l]] 

['James Jacobs|Tim Turner', 
'Mickey Mouse|Mini Mouse', 
'Mike Mills|Billy McGill|Natasha Tsaka'] 

l = df.values.tolist() 

df['Full Names'] = [ 
    '|'.join(n) 
    for n in [[' '.join(z) 
    for z in zip(*[s.split('|') 
    for s in r]) if z[1] != 'Smith'] 
    for r in l]] 

df 

enter image description here


文字遊戲不談,這是非常活潑的過採樣數據

enter image description here


較長的解釋

l 

[['Jim|James|Tim', 'Simth|Jacobs|Turner'], 
['Mickey|Mini', 'Mouse|Mouse'], 
['Mike|Billy|Natasha', 'Mills|McGill|Tsaka']] 
  • l是列表的列表。我將廣泛使用列表解析和迭代。
  • 每個子列表由2個字符串組成,我將分割並壓縮在一起。
  • 拆分的結果將是由(first, last)名稱組成的元組的「列表」。我將使用if z[1] != 'Smith'來篩選史密斯。
    • 順便說一句,在這一行,你可以使用z[1] not in list_of_names
  • 然後我將使用' '.join(這實際上是一個功能),以每個元組結合first last
  • 然後我會用另一種'|'.join結合的first lastfirst1 last1|first2 last2子列表...等等等等

之所以這樣,是快是因爲內涵具有B- een在很大程度上進行了優化。其他解決方案是使用apply這是一個通用的循環結構,只能在特殊情況下利用快速循環(知道更多的人,如果我錯了,請糾正我)。使用lambda絕對不是這些情況之一。

+0

你能解釋這是如此高效,它究竟做了什麼? 我可以或多或少地理解第一個答案(AlexG的「combin_names」方法 - 但這超出了我的意思。) 道歉爲我有限的知識。 – wingsoficarus116

+0

@ wingsoficarus116更新了類似於解釋 – piRSquared

4

下面是使用pd.DataFrame.apply和濃縮液的一些Python的很好的內置功能:

def combine_names(row): 

    pairs = list(zip(row[0].split('|'), row[1].split('|'))) 
    return '\n'.join([' '.join(p) for p in pairs if p[1] != 'Simth']) 

df['Full Name'] = df.apply(combine_names, axis=1) 
+0

不錯的解決方案@亞歷克斯 – ade1e

+0

欣賞解決方案! 我該如何概括這適用於一個有n列的數據框,我只是想添加一個由兩列合併而成的列? 此外,我不太熟悉.apply - 我可以傳遞參數到combine_names嗎?如果這是一個例子,那麼傳遞一個名稱列表來跳過而不是「Smith」是理想的。 – wingsoficarus116

+0

您可以直接在'combine_names'函數中編寫一個名稱列表,但它只能帶一個參數。傳遞的參數是行(假設軸被設置爲1)。你也可以這樣稱呼它:'df [['First Names','Last Names']]。apply(combine_names,axis = 1)'如果你不僅僅是這兩列。回到你的第一點,你可以改變:'如果p [1]!='Simth''是這樣的:'如果p [1]不在['Simth','John','King']' – AlexG

3

我真的很喜歡@AlexG's solution - 請使用它。

這是我試圖創建一個創造性的一個班輪解決方案 - 這是絕對有害的,因此它不應該被使用 - 它只是爲了好玩:

In [78]: df 
Out[78]: 
      First Names   Last Names 
0  Jim|James|Tim Simth|Jacobs|Turner 
1   Mickey|Mini   Mouse|Mouse 
2 Mike|Billy|Natasha Mills|McGill|Tsaka 

In [79]: df['Full Names'] = \ 
    ...: (df.stack() 
    ...: .str.split(r'\|', expand=True) 
    ...: .unstack(level=1) 
    ...: .groupby(level=0, axis=1) 
    ...: .apply(lambda x: x.add(' ').sum(axis=1).str.strip()) 
    ...: .replace([r'\w+\s+Simth'], [np.nan], regex=True) 
    ...: .apply(lambda x: x.dropna().str.cat(sep='\n'), axis=1) 
    ...:) 
    ...: 

In [80]: df 
Out[80]: 
      First Names   Last Names        Full Names 
0  Jim|James|Tim Simth|Jacobs|Turner     James Jacobs\nTim Turner 
1   Mickey|Mini   Mouse|Mouse     Mickey Mouse\nMini Mouse 
2 Mike|Billy|Natasha Mills|McGill|Tsaka Mike Mills\nBilly McGill\nNatasha Tsaka