pandas слияние с условным агрегированием - PullRequest
2 голосов
/ 28 мая 2020

Я хочу объединить два фрейма данных на основе составного ключа. Второй фрейм данных имеет дублированные строки с учетом ключа. Обратите внимание, что ключ не является уникальным и в первом фрейме данных, потому что на самом деле существует множество других столбцов в реальных данных. Мне нужно объединить агрегированные (товарные) значения во втором фрейме данных, но с условием дат. Строки для агрегирования должны иметь дату ниже, чем дата строки из первого фрейма данных.

Вот пример:

df1 = pd.DataFrame({
    'Code': ['Code1', 'Code1', 'Code1', 'Code2', 'Code3', 'Code4'],
    'SG': ['SG1', 'SG1', 'SG1', 'SG2', 'SG3', 'SG3'],
    'Date':
    ['2020-02-01', '2020-02-01', '2020-03-01', '2020-01-01', '2020-02-01', '2020-02-01']
})



print(df1)
    Code   SG        Date
0  Code1  SG1  2020-02-01
1  Code1  SG1  2020-02-01
2  Code1  SG1  2020-03-01
3  Code2  SG2  2020-01-01
4  Code3  SG3  2020-02-01
5  Code4  SG3  2020-02-01

df2 = pd.DataFrame({
    'Code': ['Code1', 'Code1', 'Code2', 'Code3'],
    'SG': ['SG1', 'SG1', 'SG2', 'SG3'],
    'Date': ["2019-01-01", "2020-02-25", "2020-01-13", "2020-01-25"],
    'Coef': [0.5, 0.7, 0.3, 0.3]
})

print(df2)

    Code   SG        Date  Coef
0  Code1  SG1  2019-01-01   0.5
1  Code1  SG1  2020-02-25   0.7
2  Code2  SG2  2020-01-13   0.3
3  Code3  SG3  2020-01-25   0.3

Мне нужен следующий результат: Вторая строка имеет агрегированный коэффициент 0,5x0,7 = 0,35, так как все df2.Date для соответствующего ключа меньше, чем df1.Date

    Code   SG        Date  Coef
0  Code1  SG1  2020-02-01  0.50
1  Code1  SG1  2020-02-01  0.50
2  Code1  SG1  2020-03-01  0.35
3  Code2  SG2  2020-01-01   NaN
4  Code3  SG3  2020-02-01  0.30
5  Code4  SG3  2020-02-01   NaN

Спасибо за помощь.

1 Ответ

1 голос
/ 28 мая 2020

Хорошо, наконец-то я понял!

Объединение (LEFT JOIN) по коду и SG

df_group = pd.merge(df1,df2, on=['Code','SG'], how='left', suffixes=('','_result'))

Создание фильтра для более низких дат

df_group['lower_date_mask'] = df_group['Date_result'] <= df_group['Date']

Фильтрация столбец Coef с NaN.

df_group.loc[df_group['lower_date_mask'] == False,'lower_date_mask'] = np.nan
df_group['Coef'] = df_group['Coef'] * df_group['lower_date_mask']

Здесь мы назначаем бесконечное значение True, чтобы избежать ошибки Pandas при выполнении функции .prod() с NaN

df_group.loc[df_group['lower_date_mask'] == 1.0,'lower_date_mask'] = np.inf

Проблема Github по поводу функции агрегирования с nan: https://github.com/pandas-dev/pandas/issues/20824

Агрегирование с помощью .prod ()

df_group = df_group.groupby(['Code','SG','Date']).prod()

Создание окончательного фрейма данных

df_group.reset_index(inplace = True)
df_group.loc[df_group['lower_date_mask'] == 1.0,'Coef'] = np.nan
df_group.drop(columns = ['lower_date_mask'],inplace = True)

Окончательный вывод

    Code    SG  Date    Coef
    0   Code1   SG1 2020-02-01  0.50
    1   Code1   SG1 2020-03-01  0.35
    2   Code2   SG2 2020-01-01  NaN
    3   Code3   SG3 2020-02-01  0.30
    4   Code4   SG3 2020-02-01  NaN

Стоит сказать, что вы можете добиться этого с помощью функции .apply(), однако это замедлит вас, если ваш DataFrame станет больше.

Надеюсь, я смогу помочь! Мне потребовалось буквально два часа, чтобы продумать этот код!

EDIT :

Как упоминал @codesensei, в его базе данных есть другие столбцы, которые составляют комбинацию ['Code','SG','Date'] не уникальный. В этом случае есть два возможных способа справиться с этим. Во-первых, если в df1 или df2 есть другие столбцы, которые делают комбинацию уникальной, просто добавьте их в группу, например:

df_group = df_group.groupby(['Code','SG','Date','column_of_interest']).prod()

Во-вторых, если проще сделать комбинацию уникальной каким-то образом идентификатора, скажем, индекса df1, вы можете сделать:

df1.reset_index(inplace = True)
# merge dataframes and follow the other steps as stated earlier in this answer
df_group = df_group.groupby(['Code','SG','Date','index']).prod()

Если хотите, вы можете переименовать 'index' во что-нибудь другое, просто чтобы сделать его более явным.

Надеюсь, что смогу помочь!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...