【问题标题】:Need help optimizing a loop with 3 dataframes需要帮助优化具有 3 个数据帧的循环
【发布时间】:2017-04-25 03:06:03
【问题描述】:

第一个数据帧:inj_2014 (35040, 991),其中列引用对应于所谓的 EAN。

          Date                 541448860005060119 541448860003851078 ...
0         2014-01-01 00:00:00                 0.0                0.0
1         2014-01-01 00:15:00                 0.1                0.0
...

第二个数据帧:db (1125,17)。在这里,EAN 被重新组合在一列中。行数比 991 多,因为它对应于合同规范:如果合同在 2014 年 2 月结束并在 2014 年 3 月再次开始,则 df 中有 2 行。 sd 和 ed 列分别对应开始日期和结束日期

                    EAN          sd            ed  ...
0    541448860008422181  2014-07-02    2017-01-03
1    541449200002077458  2012-01-04    2014-05-07
...

第三个数据框:价格 (1125,9)。基本上每个 EAN 都有不同的价格规格,全年(Q1-Q2-Q3-Q4)和时间(高峰-非高峰)变化

     Q1_peak  Q1_off_peak  ... Q4_off_peak                  EAN
0    82.0264      56.9196          61.9826   541448860008422181
1    85.2736      57,8456          58,7564   541449200002077458
...

我想要做的:将inj_2014中的数字(即注入)乘以价格并将其放入新的数据框中,考虑到:

  • 如果日期不在合同范围内(或返回0),则不应计算注入的事实
  • 事实上 2 个不同的合同可能具有相同的 EAN,因此应该输出 2 个不同的列(例如,EAN_1 表示最近的合同)
  • 注入的价格应乘以取决于日期和 EAN 的事实

我已经写了一些有用的函数:

def in_contrat(date, sd, ed):
    '''True if date within date limits'''
    if sd < date < ed:
        return True
    else:
        return False

def price_name(date, dates_2014): #dates_2014 = list of the quarter limit dates
    '''returns price name corresponding to the given date'''
    if date < date_2014[1]:
        if peak(date):
            return 'Q1_peak'
        else:
            return 'Q1_off_peak'
    elif date < date_2014[2]:
        if peak(date):
            return 'Q2_peak'
    ...

def in_contrat(date, sd, ed):
    '''True if date within date limits'''
    if sd < date < ed:
        return True
    else:
        return False

def get_index(df, test):
    '''returns list with index occurences of the specific EAN number in the db'''
    index = []
    for i in range(len(df)):
        if df['EAN'][i] == test:
            index.append(i)
    return index

所以我尝试用这个材料编写我的主函数:

def daily_calculation(inj_2014, db, prices):
    list_EAN = []
    for i in range(len(db)):
        EAN = db['EAN'][i]
        if EAN not in list_EAN:
            list_EAN.append(EAN)
            index = get_index(prices, EAN)[0]
        else : 
            index = get_index(prices, EAN)[1]
        for j in range(len(inj_2014)):
            date = inj_2014['Date'][j]
            name = price_name(date, dates_2014)
            EBIQ = prices[name][index]
            valeur_injection = inj_2014[EAN][j]/4000
            if in_contrat(date, db['sd'][i], db['ed'][i]) and inj_2014[EAN][j] != 0:
                results.set_value(j, EAN, (valeur_injection)*EBIQ)
            else:
                results.set_value(j, EAN, 0)
    return results

所以问题是,这似乎有效。然而,考虑到我只计算第一列所花费的时间,我应该需要 80 到 100 小时才能得到我的结果,甚至可能是错误的。我可以处理几天运行-查找错误-运行-查找错误-...但不是几个月。

我确信有一种方法可以优化这个循环,从而获得大量时间(我已经设法从 200 小时缩短到 100 小时)。但是,我对 python/pandas/etc 还是很陌生,我没有自己优化它的经验;这是一种绝望的呼唤。

【问题讨论】:

    标签: python performance loops pandas optimization


    【解决方案1】:

    没有更多信息很难写出准确的答案,但这里是一个尝试。

    首先,堆叠inj_2014,将列名放入一个名为EAN的新列中:

    inj_stacked = inj_2014.set_index('Date') \
                          .stack() \ 
                          .reset_index(drop=False) \
                          .rename(columns={'level_1': 'EAN', 0: 'injection'})
    

    第二,与db合并(价格我建议查一下):

    inj_stacked = inj_stacked.merge(db, on='EAN', how='outer')
    

    注意:您必须尝试使用​​ how 的不同值。以上是我的最佳猜测。

    第三,向量化你应用的操作:

    inj_stacked['in_contrat'] = (inj_stacked['Date'] > inj_stacked['sd']) \
                              & (inj_stacked['Date'] < inj_stacked['ed'])
    
    inj_stacked['price_name'] = inj_stacked['Date'].apply(price_name, 
                                                          args=(dates_2014,))
    

    第四,查询价格:

    inj_stacked['price'] = prices.set_index('EAN').lookup(
        inj_stacked['EAN'], 
        inj_stacked['price_name']).values
    

    这都是未经测试的,请根据需要进行调整。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-20
      • 2013-05-24
      • 1970-01-01
      • 2012-01-29
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多