Pandas как получить ближайшую меньшую дату
Дан df:
a = pd.DataFrame([{'b': 'Собака', 'c': 'Кот', 'd': 18.12.2012},
{'b': 'Еж', 'c': 'Птица', 'd': 15.12.2012},
{'b': 'Кот', 'c': 'Еж', 'd': 16.12.2012},
{'b': 'Собака', 'c': 'Кот', 'd': 12.12.2012},
{'b': 'Кот', 'c': 'Собака', 'd': 19.12.2012},
{'b': 'Кот', 'c': 'Собака', 'd': 13.12.2012},
{'b': 'Собака', 'c': 'Еж', 'd': 17.12.2012},
{'b': 'Еж', 'c': 'Собака', 'd': 13.12.2012},
{'b': 'Птица', 'c': 'Еж', 'd': 12.12.2012},
{'b': 'Кот', 'c': 'Собака', 'd': 14.12.2012}])
Не могу понять как добавить новый столбец 'k', в котором бы отображалось количество дней до ближайшей предыдущей даты, в которой в столбце 'b' или 'c' == 'b' из рассматриваемой строки. На примере 4 строки, поясню: берем значение из столбца 'b', оно == 'Кот' и смотрим у него значение из 'd', далее ищем все строки, где либо значение столбца 'b' == 'Кот', либо значение 'с' == 'Кот' и смотрим у них тоже значения столбца 'd', далее из всех вариантов выбираем ближайшую меньшую дату и записываем ее в столбец 'k', то есть на примере 4 строки в нем окажется значение 1, так как самая ближайшая дата 18.12.2012 находится в 1 строке датасета и она на 1 день меньше нашей даты. Если меньшей даты не найдено, то 0.
То есть на выходе должно получится вот такое:
a = pd.DataFrame([{'b': 'Собака', 'c': 'Кот', 'd': 18.12.2012, 'k': 1},
{'b': 'Еж', 'c': 'Птица', 'd': 15.12.2012, 'k': 2},
{'b': 'Кот', 'c': 'Еж', 'd': 16.12.2012, 'k': 2},
{'b': 'Собака', 'c': 'Кот', 'd': 12.12.2012, 'k': 0},
{'b': 'Кот', 'c': 'Собака', 'd': 19.12.2012, 'k': 1},
{'b': 'Кот', 'c': 'Собака', 'd': 13.12.2012, 'k': 1},
{'b': 'Собака', 'c': 'Еж', 'd': 17.12.2012, 'k': 3},
{'b': 'Еж', 'c': 'Собака', 'd': 13.12.2012, 'k': 1},
{'b': 'Птица', 'c': 'Еж', 'd': 12.12.2012, 'k': 0},
{'b': 'Кот', 'c': 'Собака', 'd': 14.12.2012, 'k': 1}])
На сколько я понимаю логика должна быть такой:
- Получаем значение из столбца b - Х и из d - Y
- Далее делаем query("b == Х"), берем все значения из d и вычитаем из даты полученной на предыдущем шаге Y каждое из них - запоминаем минимальное неотрицательное значение и не равное 0 (чтобы исключить нашу строку)
- После делаем тоже самое, но query("с == Х"). Из двух полученных минимальное заносим в столбец k
- если такового нет, то пишем 0
Возможно, есть более простой алгоритм действий, но проблема остается в том, что я не могу даже это написать на pandas..
Ответы (1 шт):
как-то не очень понятно сформулирована задача, а пример данных на выходе ясности не добавляет (почему значения в столбцах таблицы на выходе поменялись?), но, как бы там ни было, возможно предложенный вариант решения натолкнет вас на идею:
# исходный датафрейм
'''
b c d
0 Кот Собака 18.12.2012
1 Еж Птица 15.12.2012
2 Кот Еж 14.12.2012
3 Собака Кот 12.12.2012
4 Кот Собака 12.12.2012
5 Кот Собака 19.12.2012
6 Собака Собака 17.12.2012
7 Еж Собака 15.12.2012
8 Птица Еж 12.12.2012
9 Кот Собака 12.12.2012
'''
a['d'] = pd.to_datetime(a['d'])
k = []
for i,r in a.iterrows():
df = a.drop(i)
k.append(df[(df.b==r.b)|(df.c==r.b)]['d'].apply(lambda x: abs(x - r.d).days).min())
a = a.assign(k=k)
>>> a
# результат
'''
b c d k
0 Кот Собака 2012-12-18 1
1 Еж Птица 2012-12-15 0
2 Кот Еж 2012-12-14 2
3 Собака Кот 2012-12-12 0
4 Кот Собака 2012-12-12 0
5 Кот Собака 2012-12-19 1
6 Собака Собака 2012-12-17 1
7 Еж Собака 2012-12-15 0
8 Птица Еж 2012-12-12 3
9 Кот Собака 2012-12-12 0
UPD (на комментарий)
a['d'] = pd.to_datetime(a['d'])
k = []
for i,r in a.iterrows():
df = a.drop(i)
k.append(df[((df.b==r.b)|(df.c==r.b))&(df.d<r.d)]['d'].apply(lambda x: (r.d-x).days).min())
a = a.assign(k=k).fillna(0)
# результат
'''
b c d k
0 Собака Кот 2012-12-18 1
1 Еж Птица 2012-12-15 2
2 Кот Еж 2012-12-16 2
3 Собака Кот 2012-12-12 0
4 Кот Собака 2012-12-19 1
5 Кот Собака 2012-12-13 1
6 Собака Еж 2012-12-17 3
7 Еж Собака 2012-12-13 1
8 Птица Еж 2012-12-12 0
9 Кот Собака 2012-12-14 1