Вставить значения в таблицу по условию
Есть первый датафрейм df_org:
| ИНН | Доход-2018 | Расход-2018 | Прибыль-2018 | Доход-2019 | Расход-2019 | Прибыль-2019 |
|---|---|---|---|---|---|---|
| 525715668088 | ||||||
| 525715197343 | ||||||
| 525714499422 |
Второй датафрейм df_fin:
| ИНН | Доход | Расход | Прибыль | Дата-сост |
|---|---|---|---|---|
| 525715668088 | 200000 | 50000 | 150000 | 31.12.2018 |
| 525715668088 | 100000 | 50000 | 50000 | 31.12.2019 |
| 525714499422 | 300000 | 50000 | 250000 | 31.12.2018 |
Должны получить на выходе: df_org_fin:
| ИНН | Доход-2018 | Расход-2018 | Прибыль-2018 | Доход-2019 | Расход-2019 | Прибыль-2019 |
|---|---|---|---|---|---|---|
| 525715668088 | 200000 | 50000 | 150000 | 100000 | 50000 | 50000 |
| 525715197343 | ||||||
| 525714499422 | 300000 | 50000 | 250000 |
Вот мой код. Он вроде бы работает, но чувствую он сильно не оптимизирован и с циклами я миллион записей буду до второго пришествия формировать итоговую таблицу. Подскажите, как сделать правильно?
a=1
b=1
i=1
for inn in df_org['ИНН']:
print('ИНН', inn, "Строка", i)
i+=1
index_2018 = df_fin.loc[(df_fin['ИНН']==inn)&df_fin['Дата_сост']=='31.12.2018')].index
index_2019 = df_fin.loc[(df_fin['ИНН']==inn)&df_fin['Дата_сост']=='31.12.2019')].index
if index_2018.empty is not True:
df_org.loc[(df_org['ИНН']==inn), "Доход_2018"] = (df_fin.at[index_2018.to_list()[0], 'Доход'])
df_org.loc[(df_org['ИНН']==inn), "Расход_2018"] = (df_fin.at[index_2018.to_list()[0], 'Расход'])
df_org.loc[(df_org['ИНН']==inn), "Прибыль_2018"] = (df_fin.at[index_2018.to_list()[0], 'Прибыль'])
print('Добавлен 2018, запись:', a)
a+=1
if index_2019.empty is not True:
df_org.loc[(df_org['ИНН']==inn), "Доход_2019"] = (df_fin.at[index_2018.to_list()[0], 'Доход'])
df_org.loc[(df_org['ИНН']==inn), "Расход_2019"] = (df_fin.at[index_2018.to_list()[0], 'Расход'])
df_org.loc[(df_org['ИНН']==inn), "Прибыль_2019"] = (df_fin.at[index_2018.to_list()[0], 'Прибыль'])
print('Добавлен 2019, запись:', b)
b+=1
print('Всего записей 2018:', a)
print('Всего записей 2019:', b)
print('Итого обработано:', i)
Ответы (1 шт):
Из второго фрейма делаем сводную таблицу, где кроме данных формируется мультииндекс по столбцам, где статья - первый уровень, а год - второй. "ИНН" становится индексом (по строкам). Формируем из колоночного мультииндекса одноуровневый индекс для колонок вида "Статья-Год". Затем сортируем столбцы и вытаскиваем "ИНН" из индекса в столбец. В конце делаем внешнее соединение второго фрейма с колонкой "ИНН" первого фрейма, чтобы не выпали "пустые" ИНН, т.е. по которым нет данных во втором фрейме.
Основная работа происходит в методе .pivot_table(), все остальное - оформительские штуки.
При необходимости NaNы в итоговом фрейме можно заменить на 0 или '' с помощью .fillna().
Примечание. От первого фрейма я оставил только столбец 'ИНН', остальное не нужно.
df1 = pd.DataFrame({'ИНН': [525715668088, 525715197343, 525714499422]})
df2 = pd.DataFrame({'ИНН': [525715668088, 525715668088, 525714499422], 'Доход': [200000, 100000, 300000],
'Расход': [50000, 50000, 50000], 'Прибыль': [150000, 50000, 250000],
'Дата-сост': ['31.12.2018', '31.12.2019', '31.12.2018']})
df3 = (df2.pivot_table(columns='Дата-сост', values=['Доход', 'Расход', 'Прибыль'], index='ИНН', aggfunc=sum, dropna=False))
df3.columns = [f'{i[0]}-{i[1][-4:]}' for i in df3.columns]
articles_order = {c: str(i) for i, c in enumerate('ДРП')} # словарь для последующей сортировки столбцов в порядке 'Доход' - 'Расход' - 'Прибыль'
df3 = (df3[sorted(df3.columns, key=lambda x: x[-4:] + articles_order[x[0]])].reset_index().merge(df1['ИНН'], how='outer'))
print(df3)
ИНН Доход-2018 Расход-2018 Прибыль-2018 Доход-2019 Расход-2019 Прибыль-2019
0 525714499422 300000.0 50000.0 250000.0 NaN NaN NaN
1 525715668088 200000.0 50000.0 150000.0 100000.0 50000.0 50000.0
2 525715197343 NaN NaN NaN NaN NaN NaN