Альтернатива зацикливанию? Векторизация, цитон? - PullRequest
0 голосов
/ 11 декабря 2019

У меня есть датафрейм pandas, похожий на приведенный ниже:

       Total    Yr_to_Use   First_Year_Del    Del_rate 2019 2020 2021 2022 2023 etc 
ref1    100       2020         5                 10    0    0    0    0   0
ref2    20        2028         2                 5     0    0    0    0   0 
ref3    30        2021         7                 16    0    0    0    0   0
ref4    40        2025         9                 18    0    0    0    0   0
ref5    10        2022         4                 30    0    0    0    0   0

В столбце «Итого» показано, сколько продукта необходимо доставить. «First_yr_Del» говорит вам, сколько будет доставлено в первый год. После этого скорость доставки возвращается к «Del_rate» - фиксированная ставка, которая может применяться каждый год, пока не будут доставлены все продукты. В столбце «Год использования» указывается столбец первого года, с которого должна начинаться доставка.

ПРИМЕР: Ref1 имеет 100 для доставки. Он начнет поставлять в 2020 году и будет поставлять 5 в первый год, и 10 каждый год после этого, пока не будут учтены все 100.

Есть идеи, как это сделать?

Я думалЯ мог бы использовать что-то вроде ниже, чтобы ссылаться на какие столбцы по очереди, но я даже не уверен, полезно ли это или нет, поскольку это будет зависеть от решения (в правильной версии base_date.year определен как первый столбецв таблице - 2019):

start_index_for_slice = df.columns.get_loc(base_date.year)
end_index_for_slice = start_index_for_slice+no_yrs_to_project
df.columns[start_index_for_slice:end_index_for_slice]

Я довольно плохо знаком с Python и не уверен, что немного забегаю вперед ...

То, как яЯ думаю, что пойти на это будет использовать цикл for, или что-то с использованием iterrows, но другие сообщения, кажется, говорят, что это плохая идея, и я должен использовать векторизацию, cython или lambdas. Из этих трех я до сих пор управлял только очень простой лямбдой. Другие являются для меня загадкой, поскольку решение, по-видимому, предлагает выполнять одно действие за другим до завершения.

Любая и вся помощь оценена!

Спасибо

РЕДАКТИРОВАТЬ: Пример ожидаемого результата ниже (я отредактировал некоторые даты, чтобы вы могли лучше увидеть логику):

       Total    Yr_to_Use   First_Year_Del Del_rate 2019 2020 2021 2022 2023etc 
ref1    100       2020         5              10    0    5    10    10   10
ref2    20        2021         2              5     0    0    2     5    5 
ref3    30        2021         7              16    0    0    7     16   7
ref4    40        2019         9              18    9    18   13    0    0
ref5    10        2020         4              30    0    4    6     0    0

1 Ответ

1 голос
/ 13 декабря 2019

Вот еще одна опция, которая разделяет вычисление матрицы ставок / лет и добавляет ее к входным данным df позже. По-прежнему выполняет цикл в самом скрипте (не «выводится наружу» для какой-либо функции numpy / pandas). Должно быть хорошо для 5k строк, я бы предположил.

import pandas as pd
import numpy as np

# create the inital df without years/rates
df = pd.DataFrame({'Total': [100, 20, 30, 40, 10], 
                   'Yr_to_Use': [2020, 2021, 2021, 2019, 2020], 
                   'First_Year_Del': [5, 2, 7, 9, 4],
                   'Del_rate': [10, 5, 16, 18, 30]})

# get number of rates + remainder
n, r = np.divmod((df['Total']-df['First_Year_Del']), df['Del_rate'])

# get the year of the last rate considering all candidates
max_year = np.max(n + r.astype(np.bool) + df['Yr_to_Use'])

# get the offsets for the start of delivery, year zero is 2019
offset = df['Yr_to_Use'] - 2019

# get a year index
yrs = np.arange(2019, max_year+1)

# prepare a matrix to hold the rates for all years
out = np.zeros((df['Total'].shape[0], yrs.shape[0]))
# this could probably be optimized by getting rid of the for loop:
for i in range(df['Total'].shape[0]):
    rates = np.concatenate([[df['First_Year_Del'][i]], n[i]*[df['Del_rate'][i]], [r[i]]])
    out[i, offset[i]:offset[i]+rates.shape[0]] = rates

# add the years/rates matrix to the original df    
df = pd.concat([df, pd.DataFrame(out, columns=yrs.astype(str))], axis=1, sort=False)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...