Pandas对CSV大数据集的分组均值计算

6 投票
1 回答
5886 浏览
提问于 2025-04-18 03:33

一个常见的SQL写法是“选择A,计算X的平均值,从表中按A分组”,我想在pandas中实现这个功能。假设数据存储在一个CSV文件里,而且文件太大,无法一次性加载到内存中。

如果CSV文件可以放进内存,那么只需要简单的两行代码就能搞定:

data=pandas.read_csv("report.csv")
mean=data.groupby(data.A).mean()

但是如果CSV文件无法一次性读入内存,我们可能会尝试:

chunks=pandas.read_csv("report.csv",chunksize=whatever)
cmeans=pandas.concat([chunk.groupby(data.A).mean() for chunk in chunks])
badMeans=cmeans.groupby(cmeans.A).mean()

不过,这样得到的cmeans表会对每个不同的A值重复出现一次,因为每次读取的块里可能会多次出现这个A值(因为read_csv的chunksize并不知道要按什么字段分组)。结果,最终的badMeans表计算出来的结果是错的……它需要计算一个加权平均值。

所以一个可行的方法似乎是这样的:

final=pandas.DataFrame({"A":[],"mean":[],"cnt":[]})
for chunk in chunks:
    t=chunk.groupby(chunk.A).sum()
    c=chunk.groupby(chunk.A).count()
    cmean=pandas.DataFrame({"tot":t,"cnt":c}).reset_index()
    joined=pandas.concat(final,cmean)
    final=joined.groupby(joined.A).sum().reset_indeX()

mean=final.tot/final.cnt

我是不是漏掉了什么?这看起来太复杂了……我宁愿写一个循环,一行一行地处理CSV,也不想搞这个。应该有更简单的方法。

1 个回答

10

我觉得你可以试试下面这种方法,对我来说似乎简单一些。我准备了以下数据:

id,val
A,2
A,5
B,4
A,2
C,9
A,7
B,6
B,1
B,2
C,4
C,4
A,6
A,9
A,10
A,11
C,12
A,4
A,4
B,6
B,5
C,7
C,8
B,9
B,10
B,11
A,20

我会把数据分成5个一组:

chunks = pd.read_csv("foo.csv",chunksize=5)
pieces = [x.groupby('id')['val'].agg(['sum','count']) for x in chunks]

agg = pd.concat(pieces).groupby(level=0).sum()
print agg['sum']/agg['count']

id
A     7.272727
B     6.000000
C     7.333333

和不分组的版本相比:

df = pd.read_csv('foo.csv')
print df.groupby('id')['val'].mean()

id
A     7.272727
B     6.000000
C     7.333333

撰写回答