我有一个熊猫数据框,如下所示:
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循环或使用迭代的东西,但是其他帖子似乎说这是个坏主意,我应该使用矢量化,cython或lambda。到目前为止,在这3个中,我只处理了一个非常简单的lambda。其他解决方案对我来说还是个谜,因为该解决方案似乎建议一个接一个地执行直到完成。
任何人和所有帮助表示赞赏!
谢谢
编辑:下面的示例预期输出(我编辑了一些日期,以便更好地了解逻辑):
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
答案 0 :(得分:1)
这是另一个选项,它分离了费率/年矩阵的计算,并稍后将其附加到输入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)
答案 1 :(得分:0)
您可以使用两个用户定义的函数和apply
方法来完成此操作
import pandas as pd
import numpy as np
df = pd.DataFrame(data={'id': ['ref1','ref2','ref3','ref4','ref5'],
'Total': [100, 20, 30, 40, 10],
'Yr_to_Use': [2020, 2028, 2021, 2025, 2022],
'First_Year_Del': [5,2,7,9,4],
'Del_rate':[10,5,16,18,30]})
def f(r):
'''
Computes values per year and respective year
'''
n = (r['Total'] - r['First_Year_Del'])//r['Del_rate']
leftover = (r['Total'] - r['First_Year_Del'])%r['Del_rate']
r['values'] = [r['First_Year_Del']] + [r['Del_rate'] for _ in range(n)] + [leftover]
r['years'] = np.arange(r['Yr_to_Use'], r['Yr_to_Use'] + len(r['values']))
return r
df = df.apply(f, axis=1)
def get_year_range(r):
'''
Computes min and max year for each row
'''
r['y_min'] = min(r['years'])
r['y_max'] = max(r['years'])
return r
df = df.apply(get_year_range, axis=1)
y_min = df['y_min'].min()
y_max = df['y_max'].max()
#Initialize each year value to zero
for year in range(y_min, y_max+1):
df[year] = 0
def expand(r):
'''
Update value for each year
'''
for v, y in zip(r['values'], r['years']):
r[y] = v
return r
# Apply and drop temporary columns
df = df.apply(expand, axis=1).drop(['values', 'years', 'y_min', 'y_max'], axis=1)