У меня есть эти минимальные образцы данных:
import pandas as pd
from pandas import Timestamp
data = pd.DataFrame({'Client': {0: "Client_1", 1: "Client_2", 2: "Client_2", 3: "Client_3", 4: "Client_3", 5: "Client_3", 6: "Client_4", 7: "Client_4"},
'Id_Card': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8},
'Type': {0: 'A', 1: 'B', 2: 'C', 3: np.nan, 4: 'A', 5: 'B', 6: np.nan, 7: 'B'},
'Loc': {0: 'ADW', 1: 'ZCW', 2: 'EWC', 3: "VWQ", 4: "OKS", 5: 'EQW', 6: "PKA", 7: 'CSA'},
'Amount': {0: 10.0, 1: 15.0, 2: 17.0, 3: 32.0, 4: np.nan, 5: 51.0, 6: 38.0, 7: -20.0},
'Net': {0: 30.0, 1: 42.0, 2: -10.0, 3: 15.0, 4: 98, 5: np.nan, 6: 23.0, 7: -10.0},
'Date': {0: Timestamp('2018-09-29 00:00:00'), 1: Timestamp('1996-08-02 00:00:00'), 2: np.nan, 3: Timestamp('2020-11-02 00:00:00'), 4: Timestamp('2008-12-27 00:00:00'), 5: Timestamp('2004-12-21 00:00:00'), 6: np.nan, 7: Timestamp('2010-08-25 00:00:00')}})
data
Я пытаюсь агрегировать эту группировку данных по столбцу Client
. Подсчет Id_Card
для каждого клиента, объединение Type
, Loc
, разделенных ;
(например, значения A;B
и ZCW;EWC
для Client_2
, НЕ A;ZCW
B;EWC
), суммирование Amount
, Net
для каждого клиента и получение минимального Date
для каждого клиента. Однако я сталкиваюсь с некоторыми проблемами:
aggregate
и функцию apply
:Пример кода:
data.groupby("Client").agg({"Id_Card": "count", "Amount":"sum", "Date": "min"})
data.groupby('Client')['Loc'].apply(';'.join).reset_index()
Пример кода:
data.groupby('Client')['Type'].apply(';'.join).reset_index()
TypeError: sequence item 0: expected str instance, float found
Пример кода:
cols_to_sum = ["Amount", "Net"]
data.groupby("Client").agg({"Id_Card": "count", cols_to_sum:"sum", "Date": "min"})
cols_to_join = ["Type", "Loc"]
data.groupby('Client')[cols_to_join].apply(';'.join).reset_index()
В (3) я поставил только Amount
и Net
, и я мог бы поместить их отдельно в агрегатную функцию, но я ищу более эффективный способ, поскольку я работаю с большим количеством столбцов.
Ожидаемый результат — тот же фрейм данных, но объединенный с условиями, изложенными в начале.
Идите шаг за шагом и подготовьте три разных фрейма данных, чтобы объединить их позже.
Первый фрейм данных предназначен для простых функций, таких как count,sum,mean
df1 = data.groupby("Client").agg({"Id_Card": "count", "Amount":"sum", "Net":sum, "Date": "min"}).reset_index()
Затем вы имеете дело с Type
и Loc
соединением, мы используем fill na для работы со значениями nan.
df2=data[['Client', 'Type']].fillna('').groupby("Client")['Type'].apply(
';'.join).reset_index()
df3=data[['Client', 'Loc']].fillna('').groupby("Client")['Loc'].apply(
';'.join).reset_index()
И, наконец, вы объединяете результаты вместе:
data_new = df1.merge(df2, on='Client').merge(df3, on='Client')
data_new вывод:
Для выполнения соединения вам придется отфильтровать значения NaN. Поскольку присоединиться к вам нужно в двух местах, я создал отдельную функцию
def join_non_nan_values(elements):
return ";".join([elem for elem in elements if elem == elem]) # elem == elem will fail for Nan values
data.groupby("Client").agg({"Id_Card": "count", "Type": join_non_nan_values,
"Loc": join_non_nan_values, "Amount":"sum", "Net": "sum", "Date": "min"})