pd.merge_asof (), основанный на разнице во времени, не объединяющей все значения - Панды - PullRequest
0 голосов
/ 30 сентября 2019

У меня есть два кадра данных, один с новостями, а другой с курсом акций. Оба кадра данных имеют столбец «Дата». Я хочу объединить их с интервалом в 5 дней.

Допустим, мой информационный фрейм новостей df1, а другой ценовой фрейм df2.

Мой df1 выглядит так:

News_Dates             News
2018-09-29     Huge blow to ABC Corp. as they lost the 2012 tax case
2018-09-30     ABC Corp. suffers a loss
2018-10-01     ABC Corp to Sell stakes
2018-12-20     We are going to comeback strong said ABC CEO
2018-12-22     Shares are down massively for ABC Corp.

Мой df2 выглядит следующим образом:

  Dates             Price
2018-10-04           120
2018-12-24           131

Первый метод слияния, который я делаю, это:

pd.merge_asof(df1_zscore.sort_values(by=['Dates']), df_n.sort_values(by=['News_Dates']), left_on=['Dates'], right_on=['News_Dates'] \
              tolerance=pd.Timedelta('5d'), direction='backward')

Полученный df:

  Dates       News_Dates   News                                     Price
2018-10-04    2018-10-01  ABC Corp to Sell stakes                    120
2018-12-24    2018-12-22  Shares are down massively for ABC Corp.    131

Второй способ слияния, который я делаю, это:

pd.merge_asof(df_n.sort_values(by=['Dates']), df1_zscore.sort_values(by=['Dates']), left_on=['News_Dates'], right_no=['Dates'] \
              tolerance=pd.Timedelta('5d'), direction='forward').dropna()

И полученный df как:

News_Dates            News                                                Dates      Price
2018-09-29     Huge blow to ABC Corp. as they lost the 2012 tax case    2018-10-04    120
2018-09-30     ABC Corp. suffers a loss                                 2018-10-04    120 
2018-10-01     ABC Corp to Sell stakes                                  2018-10-04    120
2018-12-22     Shares are down massively for ABC Corp.                  2018-12-24    131

Оба слияния приводят к отдельным dfs, однако в обоих случаях есть значения, которыеотсутствуют, как во втором случае по цене 4 октября, новости от 29, 30 сентября должны были быть объединены. И в случае 2 за 24 декабря цена 20 декабря также должна была быть объединена.

Так что я не совсем могу понять, где я ошибаюсь.

PS Моя цель - объединитьцена df с новостями df, пришедшими за последние 5 дней с даты цены.

Ответы [ 2 ]

2 голосов
/ 30 сентября 2019

Вы можете поменять местами левый и правый кадры:

df = pd.merge_asof(
        df1,
        df2,
        left_on='News_Dates',
        right_on='Dates',
        tolerance=pd.Timedelta('5D'),
        direction='nearest'
    )

df = df[['Dates', 'News_Dates', 'News', 'Price']]
print(df)

        Dates News_Dates                                               News Price
0 2018-10-04 2018-09-29  Huge blow to ABC Corp. as they lost the 2012 t... 120
1 2018-10-04 2018-09-30                           ABC Corp. suffers a loss 120
2 2018-10-04 2018-10-01                            ABC Corp to Sell stakes 120
3 2018-12-24 2018-12-20       We are going to comeback strong said ABC CEO 131
4 2018-12-24 2018-12-22            Shares are down massively for ABC Corp. 131
0 голосов
/ 30 сентября 2019

Вот мое решение с использованием numpy

df_n = pd.DataFrame([('2018-09-29', 'Huge blow to ABC Corp. as they lost the 2012 tax case'), ('2018-09-30', 'ABC Corp. suffers a loss'), ('2018-10-01', 'ABC Corp to Sell stakes'), ('2018-12-20', 'We are going to comeback strong said ABC CEO'), ('2018-12-22', 'Shares are down massively for ABC Corp.')], columns=('News_Dates', 'News'))
df1_zscore = pd.DataFrame([('2018-10-04', '120'), ('2018-12-24', '131')], columns=('Dates', 'Price'))

df_n["News_Dates"] = pd.to_datetime(df_n["News_Dates"])
df1_zscore["Dates"] = pd.to_datetime(df1_zscore["Dates"])
n_dates = df_n["News_Dates"].values
p_dates = df1_zscore[["Dates"]].values

## substract each pair of n_dates and p_dates and create a matrix
mat_date_compare = (p_dates - n_dates).astype('timedelta64[D]')

## get matrix of boolean for which difference is between 0 and 5 day
## to be used as index for original array
comparision =  (mat_date_compare <= pd.Timedelta("5d")) & (mat_date_compare >= pd.Timedelta("0d"))

## get cell numbers which is in range 0 to matrix size which meets the condition
ind = np.arange(len(n_dates)*len(p_dates))[comparision.ravel()]


## calculate row and column index from cell number to index the df
pd.concat([df1_zscore.iloc[ind//len(n_dates)].reset_index(drop=True), 
           df_n.iloc[ind%len(n_dates)].reset_index(drop=True)], sort=False, axis=1)

Результат

Dates   Price   News_Dates  News
0   2018-10-04  120 2018-09-29  Huge blow to ABC Corp. as they lost the 2012 t...
1   2018-10-04  120 2018-09-30  ABC Corp. suffers a loss
2   2018-10-04  120 2018-10-01  ABC Corp to Sell stakes
3   2018-12-24  131 2018-12-20  We are going to comeback strong said ABC CEO
4   2018-12-24  131 2018-12-22  Shares are down massively for ABC Corp.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...