Pandas:相同名称列的平均值

15

我有一个数据帧,其中包含类似以下的列:

['id','name','foo1', 'foo1', 'foo1', 'foo2','foo2', 'foo3']
我想要一个新的数据框,其中共享相同名称的列被平均:
['id','name','foo1', 'foo2','foo3']

这里的列foo1将是原始数据框中名为foo1的三列的平均值,foo2将是名为foo2和foo3的两列的平均值,而foo3将保持不变。

注意:id和name不是数字类型,我必须保留它们。


2
设置id和name的索引,按列名分组,计算平均值(mean()),然后重置索引。 - Zeugma
但是如果我有很多非数字列,比如ID和名称怎么办?将索引设置为所有非数字列可以吗? - user3635284
1个回答

15

基本思想是按列名分组,并对每个组执行平均操作。

我看到了一些评论并尝试为您提供不同的方法来实现目标。 (解决方案(3)是我发现的最佳解决方案!

(1)快速解决方案。 如果您只有非常有限的非数字列,并且拥有唯一的名称,例如,列idname。 您可以执行以下操作:

首先设置索引['id', 'name']以保留它们,

df = df.set_index(['id', 'name']) 

然后使用DataFrame.groupby函数对columns进行分组,设置axis=1(迭代每列),对每个组应用mean函数。

df.groupby(by=df.columns, axis=1).mean()

最后,重置索引以恢复['id','name']列。

df = df.reset_index()

这里是一个示例代码:

In [35]: df = pd.DataFrame([['001', 'a', 1, 10, 100, 1000], ['002', 'b', 2, 20, 200, 2000]], columns=['id', 'name', 'c1', 'c2', 'c2', 'c3'], index=list('AB'))

In [36]: df = df.set_index(['id', 'name'])

In [37]: df = df.groupby(by=df.columns, axis=1).mean()

In [38]: df = df.reset_index()

In [39]: df
Out[39]: 
    id name  c1   c2    c3
0  001    a   1   55  1000
1  002    b   2  110  2000

(2) 完整解决方案。如果您有许多非数值且命名唯一的列,您可以执行以下操作:

首先,将数据框转置,

df2 = df.transpose()

然后进行分组操作(根据其索引和 axis=0),但要小心处理每个分组:对于这些数字分组,返回它们的平均值;而对于这些非数字分组,返回它们的第一行:

df2 = df2.groupby(by=df2.index, axis=0).apply(lambda g: g.mean() if isinstance(g.iloc[0,0], numbers.Number) else g.iloc[0])

最后,将其转换回去:

df = df2.transpose()

这里是代码示例:

In [98]: df = pd.DataFrame([['001', 'a', 1, 10, 100, 1000], ['002', 'b', 2, 20, 200, 2000]], columns=['id', 'name', 'c1', 'c2', 'c2', 'c3'], index=list('AB'))

In [99]: df2 = df.transpose()

In [100]: df2 = df2.groupby(by=df2.index, axis=0).apply(lambda g: g.mean() if isinstance(g.iloc[0,0], numbers.Number) else g.iloc[0])

In [101]: df3 = df2.transpose()

In [102]: df3
Out[102]: 
  c1   c2    c3   id name
A  1   55  1000  001    a
B  2  110  2000  002    b

In [103]: df
Out[103]: 
    id name  c1  c2   c2    c3
A  001    a   1  10  100  1000
B  002    b   2  20  200  2000

你需要import numbers

更多说明:

(3) 全部都在这里!这个解决方案是我找到的最佳方案:

df.groupby(by=df.columns, axis=1).apply(lambda g: g.mean(axis=1) if isinstance(g.iloc[0,0], numbers.Number) else g.iloc[:,0])

我尝试为未转置的组处理每个组,也就是说:

df.groupby(by=df.columns, axis=1).apply(gf)

并且

gf = lambda g: g.mean(axis=1) if isinstance(g.iloc[0,0], numbers.Number) else g.iloc[:,0]

我以前失败了,因为我没有仔细设置轴。你必须为mean函数设置axis=1,并且对于非数字组返回列。

谢谢!


这让我遇到了一个关于“没有数值类型可聚合”的错误,列如下:id: object,name: object,foo1: float64,foo1: float64,foo1: float64,foo2: float64,foo2: float64,foo3: float64。 - user3635284
抱歉,我修好了。 - rojeeer
谢谢!方案3确实是我需要的,验证数据是否为数字的检查是我无法完成的。谢谢! - user3635284

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接