加快熊猫数据框的操作

时间:2018-07-12 09:31:48

标签: python python-3.x pandas dataframe etl

我目前正在从R切换到python,想知道我是否可以加快以下数据帧操作的速度。我有一个包含50万行和17列的销售数据集,在将它们放入仪表板之前,需要对其进行一些计算。我的数据如下:

location  time  product  sales
store1    2017  brandA   10
store1    2017  brandB   17 
store1    2017  brandC   15
store1    2017  brandD   19
store1    2017  catTot   86
store2    2017  brandA   8
store2    2017  brandB   23 
store2    2017  brandC   5
store2    2017  brandD   12
store2    2017  catTot   76
.         .     .         .
.         .     .         .
.         .     .         .
.         .     .         .

catTot是我从原始数据集中获得的预先汇总,该原始数据集显示了给定商店在给定时间段内的总销售额。如您所见,其他产品仅占总数的一小部分,从不相加,但是它们却包含在总数中。由于我想反映给定位置的总销售额而不显示所有产品(由于仪表板中的性能问题),因此我需要将catTot值替换为实际上是当前值减去总和的总计其他产品。

当前,我遍历嵌套的for循环以进行更改。代码如下:

df['location'] = df.location.astype('category')
df['time'] = df.time.astype('category')

var_geo = []
var_time = []
for var_time in df.time.cat.categories:
    for var_geo in df.location.cat.categories:
        df_tmp = []
        fct_eur = []

        df_tmp = df[(df['location'] == var_geo) & (df['time'] == var_time)]
        fct_eur = df_tmp.iloc[len(df_tmp)-1,3] df_tmp.iloc[0:len(df_tmp)-2,3].sum()
        df.loc[(df['location'] == var_geo) & (df['time'] == var_time) & (df['product'] == 'catTot'), ['sales']] = fct_eur

如您所见,catTot始终是被屏蔽数据帧中的最后一行。现在,此操作每次大约需要9分钟,因为我有23个商店位置,大约880种产品,30个时间段和5种不同的度量,因此大约有50万行。有没有更优雅或更不快的方法来进行这种操作?

2 个答案:

答案 0 :(得分:1)

您可以创建一个分组密钥,其中所有非“ catTot”都设置为“ sales”,然后pivot_table聚合sales列,例如:

agg = df.pivot_table(
    index=['location', 'time'],
    columns=np.where(df['product'] == 'catTot', 'catTot', 'sales'),  
    values='sales', 
    aggfunc='sum'
)

这会给你:

               catTot  sales
location time
store1   2017      86     61
store2   2017      76     48

然后您可以执行new_total = agg['catTot'] - agg['sales']

location  time
store1    2017    25
store2    2017    28
dtype: int64

答案 1 :(得分:0)

一个朋友实际上提出了解决我的问题的这种方式。这段代码也是他的代码,它构建了一个嵌套目录,并将度量添加到每一行的键中,但是除catTot之外的所有内容都乘以-1。因此,最后将仅保留其余部分。

for row in data:
        safe_add(mapping, row[0], int(row[1]), row[2], int(row[3]))
def safe_add(mapping, store, year, brand, count):
    if not store in mapping:
        mapping[store] = {}
    if not year in mapping[store]:
        mapping[store][year] = 0
    if brand != 'catTot':
        count = count * -1
    new_count = count + mapping[store][year]
    mapping[store][year] = new_count

获取嵌套目录后,我遍历字典一次,以获取需要写出的行数。我这样做是为了能够预先填充一个空的df并将其填充。

counter=0    
for geo in mapping.keys():
    for time in mapping[store].keys():
        counter +=1
df_annex = pd.DataFrame(data=None, index=np.arange(0, counter), columns=df.columns)
for geo in mapping.keys():
    for time in mapping[store].keys():
        df_annex.iloc[counterb, 0] = geo
        .
        .

写完字典后,我简单地从df中提取了旧的总计,并将其与附件合并。结果是7.88s与9分钟的时间。