Pandas — Вычислить, между какими датами находится другая дата

#python #pandas #date

#python #pandas #Дата

Вопрос:

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

 date1 date2 date3 date4 date5 date_var result1 result2
jan1  feb1  apr1  sep1  dec1  mar1     apr1    feb1
  

Итак, в основном цель состоит в том, чтобы выяснить, какая из двух дат date_var находится между (здесь февраль-апрель), а затем вытащить меньшую или большую. Если это имеет значение, входные данные уже очищены таким образом, что date1 < date2 < date3 < date4 < date5 для всех дат, хотя есть вероятность, что они будут na.

Мое решение было таким:

 df.loc[df.date_var > date5,'result2'] = date5
df.loc[(df.date_var <= date5) amp; (df.date_var > date4),'result2'] = date4
df.loc[(df.date_var <= date4) amp; (df.date_var > date3),'result2'] = date3
...
  

но это очень медленно. Есть ли более быстрый способ выполнить эту операцию, или это просто что-то, что будет медленным? Спасибо.

Комментарии:

1. Не могли бы вы уточнить, каким должен быть результат для этого примера? Я не вижу, находится ли какой-либо из дней между result1 и result2 для вашего примера. Ответ здесь NA?

2. result1 и result2 являются выходными данными функции, вы можете видеть в примере, что date_var находится между date2 и date3, поэтому эти результаты являются просто значениями этих столбцов: feb1 и apr1.

3. Я вижу. почему бы вам не извлечь даты not na и не вернуть 1 индекс даты в качестве результата1 и -1 индекс в качестве результата два (предполагая, что дни отсортированы, если не отсортировать их и удалить значения na, то сделайте это.).

4. Я не понимаю, можете ли вы указать код, который вы бы использовали? Результат будет зависеть от того, какие две даты date_var находятся между ними, поэтому я пытаюсь выяснить, как сравнивать.

Ответ №1:

Вот мое понимание вопроса.

  • Нам дано 5 дат, таких, что d1 < d2 < d3 < d4 < d5.
  • Нам также указана целевая дата.
  • Найдите i таким, чтобы d_i <= target < d_i 1
  • результат1 равен d_i, а результат2 равен d_i 1

Вот мой подход:

 from collections import namedtuple
import pandas as pd

# create sample data
Record = namedtuple('Record', 'd1 d2 d3 d4 d5 target')

df = pd.DataFrame([
    Record('2019-01-01', '2019-02-01', '2019-04-01', '2019-09-01', '2019-12-01', '2019-03-01'),
    Record('2020-01-01', '2020-02-01', '2020-04-01', '2020-09-01', '2020-12-01', '2020-03-01'),
])
df = df.astype('datetime64[D]')

# define function to find lower, upper bounding dates
def find_bound(s, target, metric='min'):
    assert isinstance(s, pd.Series)
    
    if metric == 'min':
        return s[s <= target].max()
    else:
        return s[s > target].min()

df['min'] = df.apply(lambda x: find_bound(x['d1':'d5'], x['target'], 'min'), axis=1)
df['max'] = df.apply(lambda x: find_bound(x['d1':'d5'], x['target'], 'max'), axis=1)

# verify that lower, upper bounds are correct
df['validate'] = (df['min'] <= df['target']) amp; (df['target'] < df['max'])
print(df.transpose())

                   0           1
d1        2019-01-01  2020-01-01
d2        2019-02-01  2020-02-01
d3        2019-04-01  2020-04-01
d4        2019-09-01  2020-09-01
d5        2019-12-01  2020-12-01
target    2019-03-01  2020-03-01
min       2019-02-01  2020-02-01 <- result 1
max       2019-04-01  2020-04-01 <- result 2
validate        True        True
  

Комментарии:

1. Да, это именно то, что я искал, спасибо. Поиск максимального значения, которое меньше, или минимального значения, которое больше, это должно быть намного быстрее, чем проверка каждого из 4 интервалов, чтобы увидеть, в какой он попадает. Спасибо.