2016-12-09 2 views
0

Первый dataframe: inj_2014 (35040, 991), в котором ссылки столбцов соответствуют тому, что называется EAN.Нужна помощь в оптимизации цикла с 3-мя кадрами данных

  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 года и начинаются снова в марте 2014 года, в df есть 2 строки. Колонки сд и редактор соответствуют дате начала и дате окончания

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

Третьего dataframe: цены (1125,9). В основном каждый EAN имеет различные спецификации цена, что изменения в течение года (Q1-Q2-Q3-Q4) и время (пик offpeak)

 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 по цене и положил его в новом dataframe, принимая во внимание:

  • тот факт, что инъекции не следует рассчитывать, если дата не в рамках договора (или возвращать 0)
  • факт, что два разных контракта могут иметь один и тот же 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 часов, чтобы получить мои результаты, и они могут даже ошибиться. Я могу справиться с несколькими днями, когда вы обнаружите ошибку-запустить-найти misake -... но не через несколько месяцев.

Я уверен, что есть способ оптимизировать этот цикл, получить огромное количество времени (мне уже удалось получить от 200 до 100 часов). Тем не менее, я довольно новичок в python/pandas/etc, и у меня нет опыта для его оптимизации; это отчаянный призыв.

ответ

0

Трудно написать точный ответ без дополнительной информации, но вот попытка.

Первый, стек 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 

Это все проверялось, пожалуйста, адаптировать по мере необходимости.

+0

Спасибо, я уже попробую! –

Смежные вопросы