想要做与此类似的事情,但即使存在空值而不包含它们,也能完成行聚合。
import pandas as pd
import numpy as np
df = pd.DataFrame(data= {'Subject': ['X', 'G', 'H', 'M'],
'Col1': ['cat', 'dog', np.nan, 'horse'],
'Col2': [np.nan, 'black', 'brown', 'grey'],
'Col3': ['small', 'medium', 'large', 'large']})
df['Col4'] = df['Col1'] + ', ' + df['Col2'] + ', ' + df['Col3']
为了澄清,这是我正在寻找的结果数据框
Subject Col1 Col2 Col3 Col4
0 X cat NaN small cat, small
1 G dog black medium dog, black, medium
2 H NaN brown large brown, large
3 M horse grey large horse, grey, large
您可以对列轴使用
apply
、dropna
和 join
:
df['Col4'] = df[['Col1', 'Col2', 'Col3']].apply(lambda x: ','.join(x.dropna()), axis=1)
它给出了预期的结果:
Subject Col1 Col2 Col3 Col4
0 X cat NaN small cat,small
1 G dog black medium dog,black,medium
2 H NaN brown large brown,large
3 M horse grey large horse,grey,large
对于像这样的小型数据帧,它应该比 @yatu 的方法快 30% 左右,但另一种方法对于较大的数据帧更好。
set_index
和 stack
(这将删除缺失值)、groupby
,并与 str.join
聚合:
df['Col4'] = (df.set_index('Subject')
.stack()
.groupby(level=0, sort=False)
.agg(', '.join)
.values)
print(df)
Subject Col1 Col2 Col3 Col4
0 X cat NaN small cat, small
1 G dog black medium dog, black, medium
2 H NaN brown large brown, large
3 M horse grey large horse, grey, large
时间 -
df_ = pd.concat([df]*1000, axis=0).reset_index(drop=True)
%timeit df_[['Col1', 'Col2', 'Col3']].apply(lambda x: ','.join(x.dropna()), axis=1)
# 743 ms ± 17.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit (df_.set_index('Subject').stack().groupby(level=0, sort=False).agg(', '.join).values)
# 5.73 ms ± 168 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
以下版本的yatu回答是为了回答@annena的问题:
为什么 set_index 选择“Subject”?如果我只想加入 Col1 和 Col3 而不想加入 Col3 怎么办?
def join_columns(df: pd.DataFrame, cols: list[str], join_str: str = '; ') -> pd.Series:
df_cp = df.copy()
at_least_one_col_populated = df_cp[cols].notnull().any(axis=1)
df_cp.loc[at_least_one_col_populated, 'return_col'] = df_cp[cols].stack().groupby(level=0, sort=False).agg(join_str.join).values
return df_cp['return_col']
df = pd.DataFrame({
'col1': ['1', '1', None, '1', None],
'col2': [None, None, None, None, None],
'col3': ['2', '2', '2', None, None],
})
df['joined'] = join_columns(df, ['col1', 'col3'])
df
用文字代替代码回答: 我认为“主题”被传递给
set_index()
因为它是独一无二的。这在我的决定中是不必要的,因为我过滤掉了全空白的行。
您可以将 Col1 和 Col3 指定为数据帧切片,这就是我的函数的作用。