python - python - 合并以相同字母开头的Pandas DataFrame列

假设我有一个DataFrame


>>> df = pd.DataFrame({'a1':[1,2],'a2':[3,4],'b1':[5,6],'b2':[7,8],'c':[9,0]})


>>> df


 a1 a2 b1 b2 c


0 1 3 5 7 9


1 2 4 6 8 0


>>> 



我想合并(可能不合并,但是连接它)的第一个名字字母相等的列,比如,a1和a2等。 但是有一个c列没有其他类似的列,因此我希望不抛出错误,而是将NaN添加到它们。

我想将宽DataFrame变成长DataFrame,以这种方式合并它。

我已经有了问题的解决方案,唯一的问题是效率非常低,我想要一个更高效,更快的解决方案(与我的不同),我目前有一个for循环和try except(呃,听起来很糟糕)的代码:


>>> df2 = pd.DataFrame()


>>> for i in df.columns.str[:1].unique():


 try:


 df2[i] = df[[x for x in df.columns if x[:1] == i]].values.flatten()


 except:


 l = df[[x for x in df.columns if x[:1] == i]].values.flatten().tolist()


 df2[i] = l + [pd.np.nan] * (len(df2) - len(l))



>>> df2


 a b c


0 1 5 9.0


1 3 7 0.0


2 2 6 NaN


3 4 8 NaN


>>> 



我想用更好的代码获得相同的结果。

时间:

使用字典推导:


df = pd.DataFrame({i: pd.Series(x.to_numpy().ravel()) 


 for i, x in df.groupby(lambda x: x[0], axis=1)})


print (df)


 a b c


0 1 5 9.0


1 3 7 0.0


2 2 6 NaN


3 4 8 NaN



我推荐melt,然后是pivot ,要解决重复项,你需要在cumcounted列上进行透视。


u = df.melt()


u['variable'] = u['variable'].str[0] # extract the first letter


u.assign(count=u.groupby('variable').cumcount()).pivot('count', 'variable', 'value')



variable a b c


count 


0 1.0 5.0 9.0


1 2.0 6.0 0.0


2 3.0 7.0 NaN


3 4.0 8.0 NaN



可以尝试(axis=1 ):


def f(g,a):


 ret = g.stack().reset_index(drop=True)


 ret.name = a


 return ret



pd.concat( (f(g,a) for a,g in df.groupby(df.columns.str[0], axis=1)), axis=1)



输出:


 a b c


0 1 5 9.0


1 3 7 0.0


2 2 6 NaN


3 4 8 NaN




df.groupby(df.columns.str[0],1).agg(lambda x : x.tolist()).sum().apply(pd.Series).T


Out[391]: 


 a b c


0 1.0 5.0 9.0


1 3.0 7.0 0.0


2 2.0 6.0 NaN


3 4.0 8.0 NaN



使用renamegroupby.apply


df = (df.rename(columns = dict(zip(df.columns, df.columns.str[:1])))


 .groupby(level=0, axis=1, group_keys=False)


 .apply(lambda x: pd.DataFrame(x.values.flat, columns=np.unique(x.columns))))



print(df)


 a b c


0 1 5 9.0


1 3 7 0.0


2 2 6 NaN


3 4 8 NaN



pd.meltpd.groupby中使用pd.concat


pd.concat([d.T.melt(value_name=k)[k] for k, d in df.groupby(df.columns.str[0], 1)], 1)



输出:


 a b c


0 1 5 9.0


1 3 7 0.0


2 2 6 NaN


3 4 8 NaN



这个解决方案给出了与CS95类似的答案,速度快了2到3倍。


grouping = df.columns.map(lambda s: int(s[1:]) if len(s) > 1 else 1)


df.columns = df.columns.str[0] # Make a copy if the original dataframe needs to be retained


result = pd.concat((g for _, g in df.groupby(grouping, axis=1)), 


 axis=0, ignore_index=True, sort=False)



输出


 a b c


0 1 5 9.0


1 2 6 0.0


2 3 7 NaN


3 4 8 NaN



...