加快对熊猫数据框的许多访问

Posted

技术标签:

【中文标题】加快对熊猫数据框的许多访问【英文标题】:speeding up many accesses to pandas dataframe 【发布时间】:2017-03-29 20:15:44 【问题描述】:

我正在使用数据框来存储有关哪些人服用哪种药物的信息。描述人的特征的多索引中大约有 16000 行,以及不同药物的 1000 列。 example table excerpt。

我使用这个 DataFrame 来汇总数百万人的信息:对于每个人,我查询多个数据库并进行一些字符串解析,以获取有关此人特征和所服用药物的信息。因此我不能做任何直接加入/合并。然后,对于那个人,我访问 DataFrame 以在与患者药物对应的一组列中增加与患者对应的行中的值:

df.loc[(age, gender, etc), [drug1, drug2, etc] ] += 1.  

这很慢,因为我是按顺序为每个人做的。由于我需要同时增加许多列,“.at”将无济于事。是唯一不以这种方式使用 Pandas 的解决方案,还是有其他方法可以加快速度?这个 DataFrame 只有大约 250 Mb,所以像 SQLite3 这样的磁盘数据库似乎有点矫枉过正?

相关: Pandas DataFrame performance Pandas dataframe and speed

【问题讨论】:

.loc 本身并不是一项昂贵的操作。为了让它变得昂贵,你需要重复很多次。如果是这种情况,最好定义一般问题,看看是否有替代方案。 可能是一个聚合? x = pd.DataFrame('age':[12,12,13,13,14,14], 'gender':['m','m','f','f','f','m'],'druga':[1,1,0,1,1,0],'drugb':[0,1,1,1,1,0] ) 然后使用x.groupby(['gender','age']).aggregate(np.sum) 是的,这正是问题所在:我为数据库中的每个人重复一次。一般的问题是创建这个计数的DataFrame,但我愿意用另一种方法来创建它。 我编辑了这个问题,试图更好地代表这个问题。该数据库大于 100Gb(代表数百万人),因此需要对其进行迭代。连接所有数据是行不通的。除非我误解了你的建议。 您可能应该提供更多关于数据的外观以及您当前正在获取数据的详细信息 - 从它的声音来看,我会在数据库中使用 SQL,或者执行类似 holdagg = pd.DataFrame() for i in range(10): holdagg = pd.concat([holdagg.reset_index(),x]).groupby(['gender','age']).aggregate(np.sum) 的操作,其中 i 和 x 被替换为适合内存的数据库的最大块。 【参考方案1】:

我使用了 jeremycg 的评论。我惊讶地发现,使用如下定义的数据框聚合速度要快得多:

idx = pd.MultiIndex.from_product([range(10),range(10),range(10)['count','denom']], 
     names=['year','age','visits','type'])       
df = pd.DataFrame(np.zeros((len(idx),len(drugs))), index = idx, columns = drugs)
df = df.sort_index()

运行大约需要 3.6 秒:

for i in range(1000):
    age = np.random.randint(0,10,1)[0]
    year = np.random.randint(0,10,1)[0]
    visits = np.random.randint(0,10,1)[0]
    drugs = [drugs[drug_i] for drug_i in np.random.permutation(len(drugs))[:50]]
    df.loc[(age, year, visits,'count'),drugs] += 1
    df.loc[(age, year, visits,'denom'),drugs] -= 1

运行大约需要 1.6 秒:

aggmat = d:np.zeros(2000) for d in ['age','year','visits'] + drugs
aggmat['type'] = ['count','denom']*1000
for i in range(0,1000,2):
    aggmat['age'][i:(i+2)] = np.random.randint(0,10,1)[0]
    aggmat['year'][i:(i+2)] = np.random.randint(0,10,1)[0]
    aggmat['visits'][i:(i+2)] = np.random.randint(0,10,1)[0]
    for drug_i in np.random.permutation(len(drugs))[:50]:
       aggmat[drugs[drug_i]][i] = 1
       aggmat[drugs[drug_i]][i+1] = -1
z = pd.DataFrame(aggmat).groupby(['age','year','visits','type']).sum() 
df.loc[z.index,:] += z

【讨论】:

以上是关于加快对熊猫数据框的许多访问的主要内容,如果未能解决你的问题,请参考以下文章

带有大熊猫数据框的python代码很慢

如何加快熊猫数据框迭代

访问熊猫数据框的正确方法[重复]

多个熊猫数据框的交集

对熊猫数据框的列应用差异[重复]

首先按最大负值对熊猫数据框的列进行排序