Сравнение значений столбца даты в одном кадре даты с двумя столбцами даты в другом кадре данных по строке в Pandas - PullRequest
1 голос
/ 09 января 2020

У меня есть такой фрейм данных с двумя столбцами даты и столбцом quamtity:

     start_date       end_date          qty
1    2018-01-01      2018-01-08         23
2    2018-01-08      2018-01-15         21           
3    2018-01-15      2018-01-22         5
4    2018-01-22      2018-01-29         12

У меня есть второй фрейм данных с просто столбцом, содержащим годовые праздники на пару лет, например:

         holiday
1       2018-01-01 
2       2018-01-27
3       2018-12-25
4       2018-12-26

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

  start_date       end_date          qty         holidays
1    2018-01-01      2018-01-08         23       True
2    2018-01-08      2018-01-15         21       False  
3    2018-01-15      2018-01-22         5        False
4    2018-01-22      2018-01-29         12       True

Когда я пытаюсь сделать это с помощью для l oop, я получаю следующую ошибку:

ValueError: Можно сравнивать только идентично Объекты с метками серии

Ответ будет приветствоваться.

Ответы [ 4 ]

1 голос
/ 09 января 2020

Если вы хотите полностью векторизованное решение, рассмотрите возможность использования базовых массивов numpy:

import numpy as np


def holiday_arr(start, end, holidays):
    start = start.reshape((-1, 1))
    end = end.reshape((-1, 1))
    holidays = holidays.reshape((1, -1))
    result = np.any(
        (start <= holiday) & (holiday <= end),
        axis=1
    )
    return result

Если у вас есть свои кадры данных, как указано выше (называя их df1 и df2), вы можно получить желаемый результат, запустив:

df1["contains_holiday"] = holiday_arr(
    df1["start_date"].to_numpy(),
    df1["end_date"].to_numpy(),
    df2["holiday"].to_numpy()
)

df1, затем выглядит так:

  start_date   end_date  qty  contains_holiday
1 2018-01-01 2018-01-08   23              True
2 2018-01-08 2018-01-15   21             False
3 2018-01-15 2018-01-22    5             False
4 2018-01-22 2018-01-29   12              True
0 голосов
/ 09 января 2020

Я не уверен, почему вы хотите go строка за строкой. Но логическое сравнение будет намного быстрее.

df['holiday'] = ((df2.holiday >= df.start_date) &  (df2.holiday <= df.end_date))

Время

>>> 1000 loops, best of 3: 1.05 ms per loop

Цитирование решения @hchw (строка за строкой)

def _is_holiday(row, df2):
    return ((df2['holiday'] >= row['start_date']) & (df2['holiday'] <= row['end_date'])).any()

df.apply(lambda x: _is_holiday(x, df2), axis=1)
>>> The slowest run took 4.89 times longer than the fastest. This could mean that an intermediate result is being cached.
100 loops, best of 3: 4.46 ms per loop
0 голосов
/ 09 января 2020

Попробуйте IntervalIndex.contains с учетом списка и np.sum

iix = pd.IntervalIndex.from_arrays(df1.start_date, df1.end_date, closed='both')
df1['holidays'] = np.sum([iix.contains(x) for x in df2.holiday], axis=0) >= 1

Out[812]:
  start_date   end_date  qty  holidays
1 2018-01-01 2018-01-08   23      True
2 2018-01-08 2018-01-15   21     False
3 2018-01-15 2018-01-22    5     False
4 2018-01-22 2018-01-29   12      True

Примечание : я предполагаю, что столбцы start_date, end_date, holiday находятся в формат даты и времени. Если это не так, вам нужно преобразовать их перед запуском вышеуказанной команды следующим образом

df1.start_date = pd.to_datetime(df1.start_date)
df1.end_date = pd.to_datetime(df1.end_date)
df2.holiday = pd.to_datetime(df2.holiday)
0 голосов
/ 09 января 2020

попробуй:

def _is_holiday(row, df2):
    return ((df2['holiday'] >= row['start_date']) & (df2['holiday'] <= row['end_date'])).any()

df1.apply(lambda x: _is_holiday(x, df2), axis=1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...