У меня есть такой фрейм данных:

import pandas as pd

data = [['A', '2022-09-01', False, 2], ['A', '2022-09-02', False, 4], ['A', '2022-09-03', True, 5],
        ['A', '2022-09-05', False, 1], ['A', '2022-09-06', False, 2], ['A', '2022-09-07', False, 5],
        ['A', '2022-09-17', False, 3], ['A', '2022-09-19', True, 2], ['A', '2022-09-20', False, 2],
        ['B', '2022-09-04', False, 4], ['B', '2022-09-06', True, 1], ['B', '2022-09-16', False, 6],
        ['B', '2022-09-17', False, 2], ['B', '2022-09-18', True, 4], ['B', '2022-09-19', False, 2]]
df = pd.DataFrame(data = data, columns = ['group', 'date', 'indicator', 'value'])

   group        date  indicator  value
0      A  2022-09-01      False      2
1      A  2022-09-02      False      4
2      A  2022-09-03       True      5
3      A  2022-09-05      False      1
4      A  2022-09-06      False      2
5      A  2022-09-07      False      5
6      A  2022-09-17      False      3
7      A  2022-09-19       True      2
8      A  2022-09-20      False      2
9      B  2022-09-04      False      4
10     B  2022-09-06       True      1
11     B  2022-09-16      False      6
12     B  2022-09-17      False      2
13     B  2022-09-18       True      4
14     B  2022-09-19      False      2

Я хотел бы добавить столбец с именем diff_days, который показывает разницу в днях со строками, содержащими indicator = True, и остальными для каждой группы. Обратите внимание, что в некоторых группах может быть две строки с indicator = True, поэтому я хотел бы иметь разницу в днях с ближайшими строками. Здесь вы можете увидеть желаемый результат:

data = [['A', '2022-09-01', False, 2, -2], ['A', '2022-09-02', False, 4, -1], ['A', '2022-09-03', True, 5, 0],
        ['A', '2022-09-05', False, 1, 2], ['A', '2022-09-06', False, 2, 3], ['A', '2022-09-07', False, 5, 4],
        ['A', '2022-09-17', False, 3, -2], ['A', '2022-09-19', True, 2, 0], ['A', '2022-09-20', False, 2, 1],
        ['B', '2022-09-04', False, 4, -2], ['B', '2022-09-06', True, 1, 0], ['B', '2022-09-16', False, 6, -2],
        ['B', '2022-09-17', False, 2, -1], ['B', '2022-09-18', True, 4, 0], ['B', '2022-09-19', False, 2, 1]]
df_desired = pd.DataFrame(data = data, columns = ['group', 'date', 'indicator', 'value', 'diff_days'])

   group        date  indicator  value  diff_days
0      A  2022-09-01      False      2         -2
1      A  2022-09-02      False      4         -1
2      A  2022-09-03       True      5          0
3      A  2022-09-05      False      1          2
4      A  2022-09-06      False      2          3
5      A  2022-09-07      False      5          4
6      A  2022-09-17      False      3         -2
7      A  2022-09-19       True      2          0
8      A  2022-09-20      False      2          1
9      B  2022-09-04      False      4         -2
10     B  2022-09-06       True      1          0
11     B  2022-09-16      False      6         -2
12     B  2022-09-17      False      2         -1
13     B  2022-09-18       True      4          0
14     B  2022-09-19      False      2          1

Как видите, это зависит от того, насколько близко date в днях к date, где indicator = True. Поэтому мне было интересно, знает ли кто-нибудь, как рассчитать разницу в днях с ближайшими днями с условием на группу?

1
Quinten 27 Сен 2022 в 21:11

1 ответ

Вы можете использовать merge_asof. выполните это на df только со строками с True в столбце индикатора. Затем вы можете рассчитать разницу в днях внутри одной группы с ближайшей истинной датой группы.

# need datetime column
df['date'] = pd.to_datetime(df['date'])

res = (
    pd.merge_asof(df.sort_values('date'), 
                  df.loc[df['indicator'], ['group','date']].sort_values('date')
                    .assign(diff_days=lambda x: x['date']), 
                  by='group', on='date', direction='nearest')
      .assign(diff_days=lambda x: (x['date']-x['diff_days']).dt.days)
      .sort_values(['group','date'])
      .reset_index(drop=True)
)
print(res)
#    group       date  indicator  value  diff_days
# 0      A 2022-09-01      False      2         -2
# 1      A 2022-09-02      False      4         -1
# 2      A 2022-09-03       True      5          0
# 3      A 2022-09-05      False      1          2
# 4      A 2022-09-06      False      2          3
# 5      A 2022-09-07      False      5          4
# 6      A 2022-09-17      False      3         -2
# 7      A 2022-09-19       True      2          0
# 8      A 2022-09-20      False      2          1
# 9      B 2022-09-04      False      4         -2
# 10     B 2022-09-06       True      1          0
# 11     B 2022-09-16      False      6         -2
# 12     B 2022-09-17      False      2         -1
# 13     B 2022-09-18       True      4          0
# 14     B 2022-09-19      False      2          1
1
Ben.T 27 Сен 2022 в 21:32