通过从SQL DB导入的pd Dataframe子集提高性能循环

时间:2017-07-21 12:26:14

标签: python mysql performance loops

我是python /编码的新手。我正在努力制作下面的代码(非常自豪)但我现在遇到性能问题 - 不知道如何解决它们。

我的任务如下: 每个产品都有交货时间和生产时间戳。生产时间可以从交货前1天15:00到交货前30分钟。我想将每个交货时间的生产时间汇总到15分钟,并在每个时间间隔内对生产单位执行几个简单的操作 (并非所有这些都是内置的功能)   - 体积加权平均价格,总量(总和),标准差等。

我的问题: 数据集包含大约1100万个数据点。计算6个月的时间超过24小时。我试图遍历sql查询,只导入了15分钟的时间段,但情况更糟

我的问题: 您是否认为有任何方法可以改善此操作的性能? 这将是惊人的< 3

原始输入数据看起来像:

Column StartOfDelivery EndOfDelivery ProductionDateTime PriceEURpMW QuantityMW p*Q 73 2017-01-03 01:00:00 2017-01-03 02:00:00 2017-01-02 19:03:00 37,4 20 748 80 2017-01-03 01:00:00 2017-01-03 02:00:00 2017-01-02 19:08:00 35,9 25 897,5 86 2017-01-03 01:00:00 2017-01-03 02:00:00 2017-01-02 19:23:00 36,3 1 36,3 94 2017-01-03 01:00:00 2017-01-03 02:00:00 2017-01-02 19:24:00 35,3 0,4 14,12 915 2017-01-03 02:00:00 2017-01-03 03:00:00 2017-01-02 23:47:00 33,7 5 168,5 929 2017-01-03 02:00:00 2017-01-03 03:00:00 2017-01-02 23:50:00 32,6 0,3 9,78 340 03.01.2017 02:00:00 2017-01-03 03:00:00 2017-01-02 22:17:00 34 7,9 268,6 345 2017-01-03 02:00:00 2017-01-03 03:00:00 2017-01-02 22:19:00 34 0,8 27,2

输出数据如下所示:

index   StartDelivery   Production(intervall)   Quantity    VWAP
17  2017-01-03 01:00:00 2017-01-02 19:00:00       45       36,56666667
18  2017-01-03 01:00:00 2017-01-02 19:15:00       1,4      36,01428571
...
69  2017-01-03 02:00:00 2017-01-02 22:15:00       8,7      34
70  2017-01-03 02:00:00 2017-01-02 23:45:00       5,3      33,63773585

我的代码到目前为止:

import mysql.connector
import numpy as np
import pandas as pd
import datetime




conn=mysql.connector.connect(user='AriHeck',password='none',host='local',database='DataEvaluation', port=3308)
df = pd.read_sql("select StartOfDelivery,EndOfDelivery,ProdDateTime,PriceEURpMW,QuantityMW, PriceEURpMW*QuantityMW as 'p*Q'  from `Production`\
where timestampdiff(hour,StartOfDelivery,EndOfDelivery)=1 AND StartOfDelivery >= '2017-01-03 01:00:00'  AND StartOfDelivery < '2017-01-03 03:00:00'", con=conn)

#Delivery Time Loop
dt=datetime.datetime.strptime('2017-01-03 01:00:00', "%Y-%m-%d %H:%M:%S") 
end_date=datetime.datetime.strptime('2017-01-05 00:00:00', "%Y-%m-%d %H:%M:%S")

#Dummies loops
incr_delivery_loop=datetime.timedelta(hours=1)
incr_production_loop=datetime.timedelta(minutes=15)
delta_start=datetime.timedelta(days=1) 
delta_end=datetime.timedelta(minutes=30)

#Dummies Data
a=1
delivery_array=[0]*a
production_array=[0]*a
time_remaining_array=[0]*a
VWAP_array=np.zeros(a)
quantity_array=np.zeros(a)

#Start Delivery time loop
while (dt <= end_date):

    #Production Time Loop: 
        #Start Production: 1 Day before delivery 15:00 (3:00 PM), End Production 30 mins before delivery
    prod_time=(dt-delta_start).replace(hour=15)
    end_prod=dt-delta_end 

    while (prod_time<=end_prod):

        quantity=df[(df['StartOfDelivery']==dt)& (df['ProdDateTime']>=prod_time) & (df['ProdDateTime']<(prod_time+incr_production_loop))].QuantityMW.sum()
        if (quantity==0):
            VWAP=0        
        else:   
            #Calculate  Volume Weighted Average Price
            pq_total=df[(df['StartOfDelivery']==dt)& (df['ProdDateTime']>=prod_time) & (df['ProdDateTime']<(prod_time+incr_production_loop))]['p*Q'].sum()
            VWAP=pq_total/quantity

        #Save values to  arrays
        VWAP_array=np.append(VWAP_array,VWAP)
        quantity_array=np.append(quantity_array,quantity)
        delivery_array.append(dt)
        production_array.append(prod_time)

       #Increments
        prod_time=prod_time+incr_production_loop

    dt=dt+incr_delivery_loop
#END LOOPS

#Save to Dataframe 
WAP_dict={'TimeOfDelivery':delivery_array,
          'ProductionDateTime':production_array,
          'VWAP':VWAP_array,
          'Quantity':quantity_array,} 
df_WAP=pd.DataFrame(WAP_dict)
df_WAP=df_WAP[['TimeOfDelivery','ProductionDateTime','Quantity','VWAP']]


#Output
print(df_WAP.head(50)) 

python 3.4,Windows 10,eclipse IDE

1 个答案:

答案 0 :(得分:0)

欢迎来到python! Profiling您的代码将是一个很好的起点:)

也就是说,随着数据集的增长,每次调用都会:

df['some_column']==some_variable

变得更贵。如果您在处理2天数据时表现良好,但在扩展到6个月时表现下降,则可能是罪魁祸首。

尝试通过将order by StartOfDelivery添加到SQL查询的末尾来对数据进行预排序。然后将数据帧拆分为数据帧列表,其中每个子帧仅包含循环体内所需的15分钟增量记录。

然后,您可以将该列表作为主循环而不是:

进行迭代
while (dt <= end_date):

这应该删除所有数据帧过滤,并使您的执行时间与数据集大小成线性(ish)。