Как объединить два кадра данных со столбцом в перекрывающемся диапазоне даты и времени - PullRequest
1 голос
/ 29 сентября 2019

Исходя из этого вопроса Как объединить два кадра данных, для которых значения столбцов находятся в определенном диапазоне? .Но мой столбец диапазона даты и времени может перекрываться друг с другом.

Например:

>>>df_1

  timestamp              A           B
0 2019-07-14 05:31:00    0.020228    0.026572
1 2019-07-14 06:32:00    0.057780    0.175499
2 2019-07-14 07:02:00    0.076623    0.875499

>>>df_2

  start                  end                    event
0 2019-07-14 05:30:00    2019-07-14 06:30:00    E1
1 2019-07-14 06:00:00    2019-07-14 07:00:00    E2
2 2019-07-14 06:30:01    2019-07-14 07:30:00    E3
3 2019-07-14 07:30:01    2019-07-14 08:30:00    E4

Я хочу найти A из df_1 в интервале для df_2.Результат, который я ожидаю, следующий:

  start                  end                    event timestamp             A
0 2019-07-14 05:30:00    2019-07-14 06:30:00    E1    2019-07-14 05:31:00    0.020228
1 2019-07-14 06:00:00    2019-07-14 07:00:00    E2    2019-07-14 06:32:00    0.057780
2 2019-07-14 06:30:01    2019-07-14 07:30:00    E3    2019-07-14 06:32:00    0.057780
3 2019-07-14 06:30:01    2019-07-14 07:30:00    E3    2019-07-14 07:02:00    0.076623

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

KeyError: 'indexer не пересекает уникальный набор интервалов'

Может кто-нибудь помочьменя?Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 29 сентября 2019

это также может быть сделано с использованием numy широковещательной и булевой индексации, как показано ниже

## load sample data
df1 = pd.DataFrame([('0', '2019-07-14 05:31:00', '0.020228', '0.026572'), ('1', '2019-07-14 06:32:00', '0.057780', '0.175499'), ('2', '2019-07-14 07:02:00', '0.076623', '0.875499')], columns=('id', 'timestamp', 'A', 'B'))
df2 = pd.DataFrame([('0', '2019-07-14 05:30:00', '2019-07-14 06:30:00', 'E1'), ('1', '2019-07-14 06:00:00', '2019-07-14 07:00:00', 'E2'), ('2', '2019-07-14 06:30:01', '2019-07-14 07:30:00', 'E3'), ('3', '2019-07-14 07:30:01', '2019-07-14 08:30:00', 'E4')], columns=('id', 'start', 'end', 'event'))

df1["timestamp"] = pd.to_datetime(df1["timestamp"])
df2["start"] = pd.to_datetime(df2["start"])
df2["end"] = pd.to_datetime(df2["end"])

Решение

## df2[["start"]] is a column vector of size m and df1.timestamp.values is row 
## vector of size n then broad cast will result matrix of shape m,n which is 
## result of comparing each pair of m and n
compare = (df2[["start"]].values<df1.timestamp.values) & (df2[["end"]].values>df1.timestamp.values)

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


## calculate row and column index from cell number
pd.concat([df2.iloc[ind//len(df1)].reset_index(drop=True), df1.iloc[ind%len(df1)].reset_index(drop=True)], axis=1, sort=False)

Результат

    start               end                event    timestamp             A  B
0   2019-07-14 05:30:00 2019-07-14 06:30:00 E1  2019-07-14 05:31:00 0.020228    0.026572
1   2019-07-14 06:00:00 2019-07-14 07:00:00 E2  2019-07-14 06:32:00 0.057780    0.175499
2   2019-07-14 06:30:01 2019-07-14 07:30:00 E3  2019-07-14 06:32:00 0.057780    0.175499
3   2019-07-14 06:30:01 2019-07-14 07:30:00 E3  2019-07-14 07:02:00 0.076623    0.875499
1 голос
/ 29 сентября 2019

Этот ответ делает нечто очень похожее на то, что вам нужно.Ниже показано, как я адаптирую это решение к вашей проблеме, но могут быть и лучшие реализации:

bins = list(zip(df2['start'],df2['end']))
def overlapping_bins(x):
    return pd.Series([l for l in bins if l[0] <= x <= l[1]])

df3=pd.concat([df1, df1.timestamp.apply(overlapping_bins).stack().reset_index(1, drop=True)], 
     axis=1).rename(columns={0: 'bins'})

 #Create start and end columns and drop bins
 df3.loc[:, 'start'] = df3.bins.map(lambda x: x[0])
 df3.loc[:, 'end'] = df3.bins.map(lambda x: x[1])
 df3.drop('bins',axis=1,inplace=True)

 #Merge df2 with df3 on the common columns
 df4=df2.merge(df3).drop('B',axis=1)

Вот результат, который я получил:

                start                 end event           timestamp         A
0 2019-07-14 05:30:00 2019-07-14 06:30:00    E1 2019-07-14 05:31:00  0.020228
1 2019-07-14 06:00:00 2019-07-14 07:00:00    E2 2019-07-14 06:32:00  0.057780
2 2019-07-14 06:30:01 2019-07-14 07:30:00    E3 2019-07-14 06:32:00  0.057780
3 2019-07-14 06:30:01 2019-07-14 07:30:00    E3 2019-07-14 07:02:00  0.076623
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...