如何在Pandas DataFrame中将多个列值连接到单个列中

vzgqcmou  于 2022-09-21  发布在  其他
关注(0)|答案(15)|浏览(344)

这个问题与前面的this posted相同。我想连接三列,而不是连接两列:

以下是两列的组合:

  1. df = DataFrame({'foo':['a','b','c'], 'bar':[1, 2, 3], 'new':['apple', 'banana', 'pear']})
  2. df['combined']=df.apply(lambda x:'%s_%s' % (x['foo'],x['bar']),axis=1)
  3. df
  4. bar foo new combined
  5. 0 1 a apple a_1
  6. 1 2 b banana b_2
  7. 2 3 c pear c_3

我想用这个命令组合三列,但它不起作用,你有什么想法吗?

  1. df['combined']=df.apply(lambda x:'%s_%s' % (x['bar'],x['foo'],x['new']),axis=1)
xv8emn3q

xv8emn3q1#

另一种使用DataFrame.apply()的解决方案,当您想要联接更多列时,它的打字稍微少一点,可伸缩性更强:

  1. cols = ['foo', 'bar', 'new']
  2. df['combined'] = df[cols].apply(lambda row: '_'.join(row.values.astype(str)), axis=1)
zkure5ic

zkure5ic2#

您可以使用字符串连接来组合列,可以使用分隔符或不使用分隔符。您必须转换非字符串列上的类型。

  1. In[17]: df['combined'] = df['bar'].astype(str) + '_' + df['foo'] + '_' + df['new']
  2. In[17]:df
  3. Out[18]:
  4. bar foo new combined
  5. 0 1 a apple 1_a_apple
  6. 1 2 b banana 2_b_banana
  7. 2 3 c pear 3_c_pear
cx6n0qe3

cx6n0qe33#

如果要合并更多列,使用Series方法str.cat可能会很方便:

  1. df["combined"] = df["foo"].str.cat(df[["bar", "new"]].astype(str), sep="_")

基本上,您选择第一列(如果它还不是str类型,则需要追加.astype(str)),然后再追加其他列(用可选的分隔符分隔)。

bnlyeluc

bnlyeluc4#

我只是想对两种解决方案(针对30K行df)进行时间比较:

  1. In [1]: df = DataFrame({'foo':['a','b','c'], 'bar':[1, 2, 3], 'new':['apple', 'banana', 'pear']})
  2. In [2]: big = pd.concat([df] * 10**4, ignore_index=True)
  3. In [3]: big.shape
  4. Out[3]: (30000, 3)
  5. In [4]: %timeit big.apply(lambda x:'%s_%s_%s' % (x['bar'],x['foo'],x['new']),axis=1)
  6. 1 loop, best of 3: 881 ms per loop
  7. In [5]: %timeit big['bar'].astype(str)+'_'+big['foo']+'_'+big['new']
  8. 10 loops, best of 3: 44.2 ms per loop

还有几个选项:

  1. In [6]: %timeit big.ix[:, :-1].astype(str).add('_').sum(axis=1).str.cat(big.new)
  2. 10 loops, best of 3: 72.2 ms per loop
  3. In [11]: %timeit big.astype(str).add('_').sum(axis=1).str[:-1]
  4. 10 loops, best of 3: 82.3 ms per loop
展开查看全部
zazmityj

zazmityj5#

@allen给出的答案相当通用,但对于较大的 Dataframe 可能缺乏性能:

Reduced确实好了很多

  1. from functools import reduce
  2. import pandas as pd
  3. # make data
  4. df = pd.DataFrame(index=range(1_000_000))
  5. df['1'] = 'CO'
  6. df['2'] = 'BOB'
  7. df['3'] = '01'
  8. df['4'] = 'BILL'
  9. def reduce_join(df, columns):
  10. assert len(columns) > 1
  11. slist = [df[x].astype(str) for x in columns]
  12. return reduce(lambda x, y: x + '_' + y, slist[1:], slist[0])
  13. def apply_join(df, columns):
  14. assert len(columns) > 1
  15. return df[columns].apply(lambda row:'_'.join(row.values.astype(str)), axis=1)
  16. # ensure outputs are equal
  17. df1 = reduce_join(df, list('1234'))
  18. df2 = apply_join(df, list('1234'))
  19. assert df1.equals(df2)
  20. # profile
  21. %timeit df1 = reduce_join(df, list('1234')) # 733 ms
  22. %timeit df2 = apply_join(df, list('1234')) # 8.84 s
展开查看全部
kokeuurv

kokeuurv6#

可能最快的解决方案是在纯Python中操作:

  1. Series(
  2. map(
  3. '_'.join,
  4. df.values.tolist()
  5. # when non-string columns are present:
  6. # df.values.astype(str).tolist()
  7. ),
  8. index=df.index
  9. )

与@MaxU答案的比较(使用同时包含数字列和字符串列的big数据框):

  1. %timeit big['bar'].astype(str) + '_' + big['foo'] + '_' + big['new']
  2. # 29.4 ms ± 1.08 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
  3. %timeit Series(map('_'.join, big.values.astype(str).tolist()), index=big.index)
  4. # 27.4 ms ± 2.36 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

与@derChambers答案的比较(使用他们的df数据框,其中所有列都是字符串):

  1. from functools import reduce
  2. def reduce_join(df, columns):
  3. slist = [df[x] for x in columns]
  4. return reduce(lambda x, y: x + '_' + y, slist[1:], slist[0])
  5. def list_map(df, columns):
  6. return Series(
  7. map(
  8. '_'.join,
  9. df[columns].values.tolist()
  10. ),
  11. index=df.index
  12. )
  13. %timeit df1 = reduce_join(df, list('1234'))
  14. # 602 ms ± 39 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  15. %timeit df2 = list_map(df, list('1234'))
  16. # 351 ms ± 12.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
展开查看全部
xkrw2x1b

xkrw2x1b7#

我想你少了一个*%s*

  1. df['combined']=df.apply(lambda x:'%s_%s_%s' % (x['bar'],x['foo'],x['new']),axis=1)
6bc51xsx

6bc51xsx8#

首先将列转换为字符串。然后使用.T.agg(‘_’.Join)函数将它们连接起来。有关更多信息,请访问here

  1. # Initialize columns
  2. cols_concat = ['first_name', 'second_name']
  3. # Convert them to type str
  4. df[cols_concat] = df[cols_concat].astype('str')
  5. # Then concatenate them as follows
  6. df['new_col'] = df[cols_concat].T.agg('_'.join)
iqjalb3h

iqjalb3h9#

  1. df = DataFrame({'foo':['a','b','c'], 'bar':[1, 2, 3], 'new':['apple', 'banana', 'pear']})
  2. df['combined'] = df['foo'].astype(str)+'_'+df['bar'].astype(str)

如果使用字符串(‘_’)连接,请将列转换为所需的字符串,然后可以连接 Dataframe 。

a6b3iqyw

a6b3iqyw10#

  1. df['New_column_name'] = df['Column1'].map(str) + 'X' + df['Steps']

X=x是用来分隔两个合并列的任何分隔符(例如:空格)。

pgccezyw

pgccezyw11#

如果您有一个想要连接的列的列表,并且可能想要使用分隔符,下面是您可以做的

  1. def concat_columns(df, cols_to_concat, new_col_name, sep=" "):
  2. df[new_col_name] = df[cols_to_concat[0]]
  3. for col in cols_to_concat[1:]:
  4. df[new_col_name] = df[new_col_name].astype(str) + sep + df[col].astype(str)

这应该比apply更快,并且需要连接任意数量的列。

omqzjyyz

omqzjyyz12#

@derChambers我又找到了一个解决方案:

  1. import pandas as pd
  2. # make data
  3. df = pd.DataFrame(index=range(1_000_000))
  4. df['1'] = 'CO'
  5. df['2'] = 'BOB'
  6. df['3'] = '01'
  7. df['4'] = 'BILL'
  8. def eval_join(df, columns):
  9. sum_elements = [f"df['{col}']" for col in columns]
  10. to_eval = "+ '_' + ".join(sum_elements)
  11. return eval(to_eval)
  12. # profile
  13. %timeit df3 = eval_join(df, list('1234')) # 504 ms
展开查看全部
rlcwz9us

rlcwz9us13#

您可以创建一个函数来使实现更简洁(例如。如果您在整个实施过程中多次使用此功能):

  1. def concat_cols(df, cols_to_concat, new_col_name, separator):
  2. df[new_col_name] = ''
  3. for i, col in enumerate(cols_to_concat):
  4. df[new_col_name] += ('' if i == 0 else separator) + df[col].astype(str)
  5. return df

示例用法:

  1. test = pd.DataFrame(data=[[1,2,3], [4,5,6], [7,8,9]], columns=['a', 'b', 'c'])
  2. test = concat_cols(test, ['a', 'b', 'c'], 'concat_col', '_')
aor9mmx1

aor9mmx114#

  • 关注@Allen回复**

如果您需要将此类操作与其他 Dataframe 转换链接,请使用assign

  1. df.assign(
  2. combined = lambda x: x[cols].apply(
  3. lambda row: "_".join(row.values.astype(str)), axis=1
  4. )
  5. )
watbbzwu

watbbzwu15#

考虑到要组合三列,则需要三个格式说明符'%s_%s_%s',而不仅仅是两个'%s_%s'。以下内容将完成此工作

  1. df['combined'] = df.apply(lambda x: '%s_%s_%s' % (x['foo'], x['bar'], x['new']), axis=1)
  2. [Out]:
  3. foo bar new combined
  4. 0 a 1 apple a_1_apple
  5. 1 b 2 banana b_2_banana
  6. 2 c 3 pear c_3_pear

或者,如果想要创建一个单独的列表来存储想要组合的列,可以使用以下方法。

  1. columns = ['foo', 'bar', 'new']
  2. df['combined'] = df.apply(lambda x: '_'.join([str(x[i]) for i in columns]), axis=1)
  3. [Out]:
  4. foo bar new combined
  5. 0 a 1 apple a_1_apple
  6. 1 b 2 banana b_2_banana
  7. 2 c 3 pear c_3_pear

最后一种方法更方便,因为用户只需更改或添加列表中的列名-它需要的更改较少。

展开查看全部

相关问题