按列表顺序将两个数据框列与列表合并
Merged two dataframe columns with lists in order of lists
我正在尝试 merge/concatenate 两列都相关,但用“|”分隔文本数据除了将某些名称替换为“”并替换 |用 '\n'.
比如原始数据可能是:
First Names Last Names
0 Jim|James|Tim Simth|Jacobs|Turner
1 Mickey|Mini Mouse|Mouse
2 Mike|Billy|Natasha Mills|McGill|Tsaka
如果我想 merge/concatenate 导出全名并删除与 "Smith" 相关的条目,最终的 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
只是不确定如何在没有任何循环的情况下完成这个,或者是否有更有效/完全不同的方法。
感谢所有的输入!
这是使用 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)
我很喜欢 - 请使用它。
这是我尝试创建一个有创意的单行解决方案的尝试 - 它绝对有悖常理,因此不应使用 - 它只是为了好玩:
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
我有很多的理解力
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
撇开文字游戏,这对样本数据来说非常活泼
更长的解释
l
[['Jim|James|Tim', 'Simth|Jacobs|Turner'],
['Mickey|Mini', 'Mouse|Mouse'],
['Mike|Billy|Natasha', 'Mills|McGill|Tsaka']]
l
是列表的列表。我将广泛使用列表理解和迭代。
- 每个子列表包含 2 个字符串,我会将它们拆分并压缩在一起。
- 拆分的结果将是 "list" 个由
(first, last)
个名称组成的元组。我将使用 if z[1] != 'Smith'
过滤掉铁匠。
- 顺便说一句,在这一行中你可以使用
z[1] not in list_of_names
- 然后我将使用
' '.join
(这实际上是一个函数)将每个元组组合成 first last
- 然后我将使用另一个
'|'.join
将 first last
的子列表合并到 first1 last1|first2 last2
... 等等
之所以更快,是因为理解力得到了很大程度的优化。其他解决方案是使用 apply
,这是一种通用循环结构,只能在特殊情况下利用快速循环(知道更多的人,如果我错了请指正)。使用 lambda
绝对不是这些情况之一。
我正在尝试 merge/concatenate 两列都相关,但用“|”分隔文本数据除了将某些名称替换为“”并替换 |用 '\n'.
比如原始数据可能是:
First Names Last Names
0 Jim|James|Tim Simth|Jacobs|Turner
1 Mickey|Mini Mouse|Mouse
2 Mike|Billy|Natasha Mills|McGill|Tsaka
如果我想 merge/concatenate 导出全名并删除与 "Smith" 相关的条目,最终的 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
只是不确定如何在没有任何循环的情况下完成这个,或者是否有更有效/完全不同的方法。
感谢所有的输入!
这是使用 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)
我很喜欢
这是我尝试创建一个有创意的单行解决方案的尝试 - 它绝对有悖常理,因此不应使用 - 它只是为了好玩:
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
我有很多的理解力
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
撇开文字游戏,这对样本数据来说非常活泼
更长的解释
l
[['Jim|James|Tim', 'Simth|Jacobs|Turner'],
['Mickey|Mini', 'Mouse|Mouse'],
['Mike|Billy|Natasha', 'Mills|McGill|Tsaka']]
l
是列表的列表。我将广泛使用列表理解和迭代。- 每个子列表包含 2 个字符串,我会将它们拆分并压缩在一起。
- 拆分的结果将是 "list" 个由
(first, last)
个名称组成的元组。我将使用if z[1] != 'Smith'
过滤掉铁匠。- 顺便说一句,在这一行中你可以使用
z[1] not in list_of_names
- 顺便说一句,在这一行中你可以使用
- 然后我将使用
' '.join
(这实际上是一个函数)将每个元组组合成first last
- 然后我将使用另一个
'|'.join
将first last
的子列表合并到first1 last1|first2 last2
... 等等
之所以更快,是因为理解力得到了很大程度的优化。其他解决方案是使用 apply
,这是一种通用循环结构,只能在特殊情况下利用快速循环(知道更多的人,如果我错了请指正)。使用 lambda
绝对不是这些情况之一。