Создать новый средний столбец на основе предыдущей строки в pandas

#python #pandas

#python #pandas

Вопрос:

У меня есть набор данных, как показано ниже:

 import pandas as pd 

df = pd.DataFrame({
        'ID':  ['27459', '27459', '27459', '27459', '27459', '27459', '27459', '48002', '48002', '48002'],
        'Invoice_Date': ['2020-06-26', '2020-06-29', '2020-06-30', '2020-07-14', '2020-07-25', 
                         '2020-07-30', '2020-08-02', '2020-05-13', '2020-06-20', '2020-06-28'],
        'Delay': [2,-2,0,1,2,9,12,29,0,1],
        'Difference_Date': [0,3,1,14,11,5,3,0,38,8],
        })
 

Мне нужно создать два новых столбца, которые являются средним значением Delay и Difference_Date за 30 дней с даты предыдущего столбца. Данные основаны на данных клиента, поэтому их необходимо сортировать и группировать ID .

Мой ожидаемый результат:

 
    ID  Invoice_Date    Delay   Difference_Date  Avg_Delay   Avg_Difference_Date
27459   2020-06-26       2      0                0.00        0.000000
27459   2020-06-29      -2      3                2.00        0.000000
27459   2020-06-30       0      1                0.00        1.500000
27459   2020-07-14       1      14               0.00        1.333333
27459   2020-07-25       2      11               0.25        4.500000
27459   2020-07-30       9      5                0.60        5.800000
27459   2020-08-02       12     3                4.00        10.000000
48002   2020-05-13       29     0                0.00        0.000000
48002   2020-06-20       0      38               29.00       0.000000
48002   2020-06-28       1      8                0.00        38.000000
 

Ответ №1:

Вам нужно использовать rolling подход, указав 30 дней («30D»), а затем shift учитывать только прошедшие дни (не включая сам день):

 df['Invoice_Date'] = pd.to_datetime(df['Invoice_Date'])
df = df.set_index('Invoice_Date')

df[['Avg_Delay', 'Avg_Difference_Date']] = (
    df.groupby('ID').transform(lambda x: x.rolling('30D').mean())
    .shift().fillna(0)
)

# Rearrange columns to exact match to output:
df = df.reset_index().iloc[:, [1,0]   list(range(2, df.shape[1] 1))]
 

Вывод:

       ID Invoice_Date  Delay  Difference_Date  Avg_Delay  Avg_Difference_Date
0  27459   2020-06-26      2                0       0.00             0.000000
1  27459   2020-06-29     -2                3       2.00             0.000000
2  27459   2020-06-30      0                1       0.00             1.500000
3  27459   2020-07-14      1               14       0.00             1.333333
4  27459   2020-07-25      2               11       0.25             4.500000
5  27459   2020-07-30      9                5       0.60             5.800000
6  27459   2020-08-02     12                3       4.00            10.000000
7  48002   2020-05-13     29                0       6.00             8.250000
8  48002   2020-06-20      0               38      29.00             0.000000
9  48002   2020-06-28      1                8       0.00            38.000000
 

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

1. Спасибо, это действительно мне очень помогает. У меня есть один вопрос: что, если в моем наборе данных есть другой столбец, который не может быть агрегирован. Например, дата или любые другие строковые столбцы. Есть ли какое-либо обходное решение, кроме rolling ?

2. Конечно! Допустим, у вас есть целевые столбцы в виде списка в вызываемой переменной cols . Таким образом , вам просто нужно указать столбцы между groupby и transform , вот так df[cols] = df.groupby('ID')[cols].transform ... .