Страницы

Поиск по вопросам

понедельник, 23 декабря 2019 г.

Как эффективно объединить 2 DataFrame с добавлением результата вычислений в новую колонку только для строк по условию?

#python #python_3x #pandas #dataframe


Есть два DataFrame с временными затратами за день и на отдельные задачи: 

d = [('20190601', 7.0), ('20190602', 8.0)]
t = [('20190601', 'task1', 5.0), ('20190601', 'task2', 1.0), ('20190602', 'task1',
4.0), ('20190602', 'task2', 3.0)]

ddf = pd.DataFrame(d, columns=['date', 'fact'])
tdf = pd.DataFrame(t, columns=['date', 'task', 'fact'])


Подсчитываю сумму времнных затрат всех задач за день:

sumdf = tdf.groupby([tdf.date]).fact.sum().reset_index()

       date  fact
0  20190601   6.0
1  20190602   7.0


Потом пытаюсь объединить в конечный DataFrame:

df = pd.concat([ddf, tdf], axis=0, ignore_index=True, sort=False)
df.sort_values(['date', 'task'], na_position='first', inplace=True)

       date  fact   task
0  20190601   7.0    NaN
2  20190601   5.0  task1
3  20190601   1.0  task2
1  20190602   8.0    NaN
4  20190602   4.0  task1
5  20190602   3.0  task2


Но не совсем понимаю, как лучше добавить также и суммы из sumdf, чтобы получилось:

       date  fact   task  calc
0  20190601   7.0    NaN   6.0
2  20190601   5.0  task1   NaN
3  20190601   1.0  task2   NaN
1  20190602   8.0    NaN   7.0
4  20190602   4.0  task1   NaN
5  20190602   3.0  task2   NaN


То есть, суммы за день должны оказаться в новой колонке calc только для строк где
task=NaN.

Как выполнить такое объединение наиболее эффективно? По возможности, без промежуточного
подсчета сумм за день.
    


Ответы

Ответ 1



Как-то так: res = (pd.concat((tdf, ddf.merge(tdf.groupby("date") ["fact"] .sum() .reset_index(name="calc"), on="date")), ignore_index=True, sort=False) .sort_values(['date', 'task'], na_position='first')) результат: In [33]: res Out[33]: date task fact calc 4 20190601 NaN 7.0 6.0 0 20190601 task1 5.0 NaN 1 20190601 task2 1.0 NaN 5 20190602 NaN 8.0 7.0 2 20190602 task1 4.0 NaN 3 20190602 task2 3.0 NaN

Ответ 2



Сначала выделяем строки из df, которым нужно подставить значение: temp1 = df.loc[df['task'].isna()] Затем достаём нужные значения из sumdf: temp2 = temp1.merge(sumdf, on='date', how='left', indicator=True) Остаётся лишь создать новый столбец: df['calc'] = np.NaN И подставить полученные значения в нужных местах: df.loc[df['task'].isna(), 'calc'] = temp2['fact_y'] Результат: date fact task calc 0 20190601 7.0 NaN 6.0 2 20190601 5.0 task1 NaN 3 20190601 1.0 task2 NaN 1 20190602 8.0 NaN 7.0 4 20190602 4.0 task1 NaN 5 20190602 3.0 task2 NaN

Комментариев нет:

Отправить комментарий