Pandas对CSV大数据集的分组均值计算
一个常见的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