串接在大熊猫数据帧中的所有列

问题描述 投票:6回答:4

我有可能具有不同数量的列和这些列的数量通常会发生变化,从50到100。我需要创建一个最终列,它是简单地所有的列连接的多个数据帧的熊猫。基本上列的第一行中的字符串应该是所有列的第一行中的字符串的总和(串联)。我写了下面的循环,但我觉得有可能是做一个更好的更有效的方法。如何做到这一点的任何想法

num_columns = df.columns.shape[0]
col_names = df.columns.values.tolist()
df.loc[:, 'merged'] = ""
for each_col_ind in range(num_columns):
    print('Concatenating', col_names[each_col_ind])
    df.loc[:, 'merged'] = df.loc[:, 'merged'] + df[col_names[each_col_ind]]
python pandas
4个回答
14
投票

sum解决方案,但输出float,所以转换为intstr是必要的:

df['new'] = df.sum(axis=1).astype(int).astype(str)

apply功能join另一种解决方案,但它的slowiest:

df['new'] = df.apply(''.join, axis=1)

最后非常快numpy solution - 转换为numpy array然后'sum'

df['new'] = df.values.sum(axis=1)

时序:

df = pd.DataFrame({'A': ['1', '2', '3'], 'B': ['4', '5', '6'], 'C': ['7', '8', '9']})
#[30000 rows x 3 columns]
df = pd.concat([df]*10000).reset_index(drop=True)
#print (df)

cols = list('ABC')

#not_a_robot solution
In [259]: %timeit df['concat'] = pd.Series(df[cols].fillna('').values.tolist()).str.join('')
100 loops, best of 3: 17.4 ms per loop

In [260]: %timeit df['new'] = df[cols].astype(str).apply(''.join, axis=1)
1 loop, best of 3: 386 ms per loop

In [261]: %timeit df['new1'] = df[cols].values.sum(axis=1)
100 loops, best of 3: 6.5 ms per loop

In [262]: %timeit df['new2'] = df[cols].astype(str).sum(axis=1).astype(int).astype(str)
10 loops, best of 3: 68.6 ms per loop

编辑如果某些列的dtypes不objectstring投(显然DataFrame.astypes):

df['new'] = df.astype(str).values.sum(axis=1)

15
投票
df = pd.DataFrame({'A': ['1', '2', '3'], 'B': ['4', '5', '6'], 'C': ['7', '8', '9']})

df['concat'] = pd.Series(df.fillna('').values.tolist()).str.join('')

给我们:

df
Out[6]: 
   A  B  C concat
0  1  4  7    147
1  2  5  8    258
2  3  6  9    369

要选择一组给定的列:

df['concat'] = pd.Series(df[['A', 'B']].fillna('').values.tolist()).str.join('')

df
Out[8]: 
   A  B  C concat
0  1  4  7     14
1  2  5  8     25
2  3  6  9     36

然而,我发现这种方法有时可能会导致NaNs被填充,他们不应该,所以这里的另一种方式:

>>> from functools import reduce
>>> df['concat'] = df[cols].apply(lambda x: reduce(lambda a, b: a + b, x), axis=1)
>>> df
   A  B  C concat
0  1  4  7    147
1  2  5  8    258
2  3  6  9    369

虽然应该指出的是,这种做法是慢了很多:

$ python3 -m timeit 'import pandas as pd;from functools import reduce; df=pd.DataFrame({"a": ["this", "is", "a", "string"] * 5000, "b": ["this", "is", "a", "string"] * 5000});[df[["a", "b"]].apply(lambda x: reduce(lambda a, b: a + b, x)) for _ in range(10)]'
10 loops, best of 3: 451 msec per loop

$ python3 -m timeit 'import pandas as pd;from functools import reduce; df=pd.DataFrame({"a": ["this", "is", "a", "string"] * 5000, "b": ["this", "is", "a", "string"] * 5000});[pd.Series(df[["a", "b"]].fillna("").values.tolist()).str.join(" ") for _ in range(10)]'
10 loops, best of 3: 98.5 msec per loop

6
投票

我没有足够的信誉发表评论,所以我建立我的答案关闭黑点的回应。

为了清楚起见,午餐盒评论说,它没有为Python 3.7.0。它也没有对我关于Python 3.6.3。原来这里是答案的黑点:

df['concat'] = pd.Series(df.fillna('').values.tolist()).str.join('')

这里是我的Python 3.6.3修改:

df['concat'] = pd.Series(df.fillna('').values.tolist()).map(lambda x: ''.join(map(str,x)))

1
投票

即使用numpy的阵列上面给出的解决方案,为我伟大的工作。

但是,有一点要小心的是索引,当你从numpy.ndarray得到df.values,由于轴标签从df.values删除。

因此,要采取上述为例(我最经常使用的一个)提供的解决方案之一:

df['concat'] = pd.Series(df.fillna('').values.tolist()).str.join('')

该部分:

df.fillna('').values

不保留原始DataFrame的指标。不是当DataFrame有共同0, 1, 2, ...排索引方案,但是当DataFrame以其他任何方式进行索引该解决方案将无法正常工作的问题。您可以通过添加一个index=参数pd.Series()解决这个问题:

df['concat'] = pd.Series(df.fillna('').values.tolist(), 
                         index=df.index).str.join('')

我总是添加index=说法只是为了安全起见,即使我敢肯定,DataFrame是行索引为0, 1, 2, ...

© www.soinside.com 2019 - 2024. All rights reserved.