У меня есть блок кода, который в настоящее время работает, но я заканчиваю тем, что использую его снова и снова, и я не могу понять, как его функционализировать (или упростить до такой степени, что я могу его функционализировать).
В самом простом случае мои данные выглядят как первые три столбца перед функцией, а выходной столбец - это то, что функция должна создать:
Years | Input | Growth Vector | Output
2015 | | NaN | 37.40
2016 | | 1.5375 | 57.50
2017 | 75.00| 1.3043 | 75.00
2018 | | 1.4213 | 106.60
2019 | | 1.4309 | 152.53
2020 | | 1.3418 | 204.67
2021 | | 1.3843 | 283.32
2022 | | 1.5978 | 452.71
Пара складок:
- Столбец Input может представлять собой одну пару год / значение или столбец с несколькими значениями года.Например, один раз у меня есть данные за 2016–2020 годы, и мне нужно вменять 2015, 2021 и 2022. Однако можно предположить, что в любом входном столбце будет непрерывная пара год / значение (т. Е. Данных за 2017 год не будети 2019, но не 2018).
- Каждый раз, когда я использую функцию, Вектор роста будет рассчитываться по-разному (путем агрегирования по году, одному или нескольким другим измерениям и расчета годового изменения в процентах).
- Необходимо вменять как предыдущий, так и последующие годы, используя правильную формулу в каждом случае (т. Е. Предыдущие годы - это Вектор стоимости / роста, в то время как будущие годы - Значение * Вектор роста).
- Когда несколько лет вменяются вВ этом направлении необходимо сначала вычислить значение, наиболее близкое к необработанным данным, а затем рекурсивно использовать самый последний вмененный год для расчета следующего года (например, 2016 должен быть рассчитан до 2015 года, так как 2015 должен быть значением 2016 года, поделенным на Вектор роста 2016 годазначение).
Вот версия кодаВ настоящее время я использую:
Step 1: aggregate the user-defined Growth Vector source column
according to user-defined dimensions and calculate the annual percent change
df_change= (df
.sort_values(by=['Dimension1','Dimension2,'Year'])
.loc[:,['Dimension1', 'Dimension2','Year','Value1']]
.groupby(['Dimension1', 'Dimension2','Year'])
.sum()
.assign(Growth_Vector = lambda df: df.apply(lambda x: x.pct_change() + 1))
.reset_index()
)
Step 2: expand the Growth Vector temporary data frame to include
all dimension tags from the main data frame (so as to make both data frames
have the same length). This will replicate the Growth Vector values across
dimensions not used in the Growth Vector calculation.
key_df = df[['Dimension1', 'Dimension2', 'Dimension3']].drop_duplicates().reset_index(drop=True)
min_year = df[['Years']].min()
max_year = df[['Years']].max()
years = pd.DataFrame(data={'dummy':1, 'Year':list(range(min_year,max_year+1))})
df_expander = key_df.assign(dummy=1).merge(years).drop('dummy', axis=1)
expanded_df = df_expander.merge(df, how='left', on=['Dimension1', 'Dimension2', 'Dimension3','Year'])
Step 3: impute the missing years in order so as to provide the recursive
values for multiple years in a row being imputed. Melt the columns together
without overwriting any previously calculated or original values.
df2 = (expanded_df.merge(df_change [['Dimension1', 'Dimension2','Year','Growth_Vector']],
how='left',
on=['Dimension1', 'Dimension2','Year'])
.assign(value_imp_2016= lambda df: (df['Value2'] / df['Growth_Vector']).shift(-1))
.assign(value_imp_2015 = lambda df: (df['value_imp_2016'] / df['Growth_Vector']).shift(-1))
.assign(value_imp_2018 = lambda df: df['Value2'].shift(1) * df['Growth_Vector'])
.assign(value_imp_2019 = lambda df: df['value_imp_2018'].shift(1) * df['Growth_Vector'])
.assign(value_imp_2020 = lambda df: df['value_imp_2019'].shift(1) * df['Growth_Vector'])
.assign(value_imp_2021 = lambda df: df['value_imp_2020'].shift(1) * df['Growth_Vector'])
.assign(value_imp_2022 = lambda df: df['value_imp_2021'].shift(1) * df['Growth_Vector'])
.assign(**{'Value2 Imputed': lambda df: df['Value2'].fillna(df['value_imp_2015'])})
.assign(**{'Value2 Imputed': lambda df: df['Value2 Imputed'].fillna(df['value_imp_2016'])})
.assign(**{'Value2 Imputed': lambda df: df['Value2 Imputed'].fillna(df['value_imp_2018'])})
.assign(**{'Value2 Imputed': lambda df: df['Value2 Imputed'].fillna(df['value_imp_2019'])})
.assign(**{'Value2 Imputed': lambda df: df['Value2 Imputed'].fillna(df['value_imp_2020'])})
.assign(**{'Value2 Imputed': lambda df: df['Value2 Imputed'].fillna(df['value_imp_2021'])})
.assign(**{'Value2 Imputed': lambda df: df['Value2 Imputed'].fillna(df['value_imp_2022'])})
.assign(**{'Value2': lambda df: df['Value Imputed2']})
.drop({'Growth_Vector',
'value_imp_2016',
'value_imp_2015',
'value_imp_2018',
'value_imp_2019',
'value_imp_2020',
'value_imp_2021',
'value_imp_2022',
'Value2 Imputed',
}, axis=1)
)
В этом примере «df» - это большой фрейм данных, который включает столбец источника вектора роста «Value1», необработанные данные, для которых мне нужны дополнительные годы, вмененные «Value2»и все размерные столбцы.Фрейм данных «df_change» имеет ту же длину, что и «df», и те же столбцы измерений, что и столбец «Вектор роста».И, наконец, «df2» - это выходной кадр, который равен «df», за исключением того, что он включает в себя выходной столбец «Значение».
Пожалуйста, помогите!Как бы это выглядело как вызываемая функция?Есть ли более простой способ добиться того, что я делаю?