【问题标题】:Faster ways to sort and append large dataframe排序和追加大型数据框的更快方法
【发布时间】:2018-04-09 15:33:40
【问题描述】:

我正在尝试对每个产品销售日和产品 ID 的一些销售数据进行排序,然后我想用 pandas 计算一些统计数据。有没有一种有效的方法来做到这一点?我的数据集有数百万行。

数据集如下所示(df1, 3.000.000 + rows):-------------------------------- ---------------------------------------------

|productID |productCategory |expiryDate |Price |Currency |quantitySold| daySold| 

|Fdgd4   |Ergdgf |15sep2020 00:00:00 |125 |USD |5675 |18feb2017 12:45:17| 
|Sd23454 |sdfdsr |17mar2018 00:00:00 |39  |USD |654  |31jan2017 12:45:17| 
|Fdgd4   |Ergdgf |15sep2020 00:00:00 |125 |USD |300  |18feb2017 09:17:15| 
|Sd23454 |sdfdsr |17mar2018 00:00:00 |39  |USD |200  |31jan2017 15:30:35| 
|Rt4564  |fdgdf  |13jun2018 00:00:00 |45  |USD |1544 |31feb2017 13:25:31| 
|Fdgd4   |Ergdgf |15sep2020 00:00:00 |125 |USD |4487 |18mar2017 09:17:15| 
|Sd23454 |sdfdsr |17mar2018 00:00:00 |39  |USD |7895 |31aug2017 15:30:35|

我想每天对每个 productID 进行排序计算一些简单的统计数据。所以我认为我的代码应该首先每天订购行,然后按产品订购。然后它应该计算统计数据并将它们添加到表中。

本例中的结果是(df2):

|productID |productCategory |expiryDate |Price |Currency |quantitySold |daySold |volSTD |totalVol |totalRevenue|
------------------------------------------------------------------------**

|Sd23454 |sdfdsr |17mar2018 00:00:00 39  |USD |654  |31jan2017 12:45:17 |321.02 |854   |33306  |
|Fdgd4   |Ergdgf |15sep2020 00:00:00 125 |USD |300  |31jan2017 15:30:35 |0      |300   |37500  |
|Fdgd4   |Ergdgf |15sep2020 00:00:00 125 |USD |5675 |18feb2017 12:45:17 |840.04 |10162 |1270250|
|Rt4564  |fdgdf  |13jun2018 00:00:00 45  |USD |1544 |31feb2017 13:25:31 |0      |544   |69480  |
|Sd23454 |sdfdsr |17mar2018 00:00:00 39  |USD |7895 |31aug2017 15:30:35 |0      |7895  |307905 |

我在 pandas 中使用了一个嵌套的 for 循环,它给出了预期的结果,但它确实需要很长时间(几个小时)。 我正在寻找一种快速获得此结果的方法。

我的代码(可能是你见过的最糟糕的代码):

uniqueDays = df1.daySold.unique()
numberOfDays = df1.shape[0]
df_results = pd.Dataframe(columns=[‘productID’, ‘productCategory’, ‘expiryDate  Price’, ‘Currency’, ‘quantitySold’, ‘daySold’, ‘volSTD’, ‘totalVol’, ‘totalRevenue’])
For i in range(0, numberOfDays):
    temp1 = df1.loc[df1[‘daySold’]== uniqueDays[i]]
    uniqueID = temp1.productID.unique()
    NumberOfUniqueID = uniqueID.shape[0]
    for j in range(0, NumberOfUniqueID):
        temp2 = temp1.loc[temp1[‘daySold’]== uniqueID[j]
        volSTD = temp2.quantitySold.std()
        totalVol = temp2.quantitySold.sum()
        totalRevenue = temp2.quantitySold.dot(temp2.price)
        temp3 = temp2.iloc[0] # it does not matter which row I pick
        temp3[‘volSTD’] = volSTD
        temp3[‘totalVol’] = totalVol
        temp3[‘totalRevenue’] = totalRevenue
        df_results = df_results.append(temp3)

这给了我想要的结果,但它太慢了。特别是将列(volSTD、totalVol 和 totalRevenue)添加到 temp3 并将 temp3 附加到 df_results 总共需要 81.3% 的处理时间。

有没有人有更快的方法来做到这一点?使用向量?还是填充现有数据框而不是追加?

谢谢

【问题讨论】:

  • 你看过groupby吗?这听起来像是一个清晰的groupby 工作流程。

标签: python pandas numpy


【解决方案1】:

groupby 怎么样?可以说,它比循环更有效地处理迭代,并且代码更短且可读性更强。您将在daySoldproductID 上进行分组。这显然是模拟数据,但您需要先将您的 daySold 转换为 datetime 对象,这样您就可以轻松地对其进行分组 - 我只是保留了一天,但如果需要,您可以保留时间:

df.daySold=pd.to_datetime(df.daySold.apply(lambda x: x[:9]),format="%d%b%Y")

那么它只是一个单行。使用groupby 对象,您可以传递许多不同的聚合调用。

df.groupby(['daySold','productID']).agg({'quantitySold':[sum,np.std],'Price':[sum,np.std]})

                     quantitySold              Price     
                              sum          std   sum  std
daySold    productID                                     
2017-01-31 Sd23454            854   321.026479    78  0.0
2017-02-13 Rt4564            1544          NaN    45  NaN
2017-02-18 Fdgd4             5975  3800.698949   250  0.0
2017-03-18 Fdgd4             4487          NaN   125  NaN
2017-08-30 Sd23454           7895          NaN    39  NaN

编辑:

您可以使用 groupby 对象应用各种功能,现成的和您自己定义的。

所以你可以做一个点积,需要一个数据框的两个列/数组,像这样:

def dotter(df):
    return np.sum(df.quantitySold*df.Price)
    ## or if you want to use numpy--may be faster for large datasets:
    #return np.dot(df.quantitySold,df.Price)

使用groupby对象的apply方法调用:

 df.groupby(['daySold','productID']).apply(dotter)

daySold     productID
2017-01-31  Sd23454       33306
2017-02-13  Rt4564        69480
2017-02-18  Fdgd4        746875
2017-03-18  Fdgd4        560875
2017-08-30  Sd23454      307905
dtype: int64

【讨论】:

  • 谢谢,您的解决方案要快得多。只有我如何计算 groupby 中 price 和 quantitySold 之间的点乘?以及如何返回其他列(productID |productCategory |expiryDate |Price |Currency |quantitySold | daySold )?我只得到总和和标准。谢谢
  • 关于您的第二个问题 - 如果其他列与 productID 不同,您可以将它们添加到 groupby() 子句中,然后它们将成为 MultiIndex 的一部分。
  • 非常感谢!我正在使用 index=False 写入 csv,但没有意识到丢失的列实际上是索引。最后一个细节:是否可以在 agg() 中调用 dotter 函数?如果没有,我只需要加入两个数据框。再次感谢
猜你喜欢
  • 2021-09-25
  • 1970-01-01
  • 2021-04-10
  • 2011-07-18
  • 2018-06-26
  • 1970-01-01
  • 1970-01-01
  • 2018-02-09
  • 2012-03-25
相关资源
最近更新 更多