Панды, повторяйте ряды со сдвигом

#python #pandas #dataframe

Вопрос:

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

 random.seed(42)
N = 4
date_0 = datetime.datetime(2020, 1, 1, 0, 0, 0, 0)
dates = [date_0   datetime.timedelta(seconds=random.uniform(0, 120)) for i in range(N)]
dates.sort()
speeds = [random.uniform(1, 10) for i in range(N)]
speeds.sort()
pressures = [i**2   random.normalvariate(0, 30) for i in speeds]
data = [speeds, pressures]
df = pd.DataFrame(data=list(zip(speeds, pressures)), columns=['speed', 'pressure'], index=dates)
 

какие результаты:

                                 speed   pressure
2020-01-01 00:00:03.001291  1.782449  -0.964646
2020-01-01 00:00:26.785289  7.090295  20.997679
2020-01-01 00:00:33.003518  7.628241  75.141566
2020-01-01 00:01:16.731216  9.029616  46.504617
 

Теперь мне нужно получить следующий кадр данных, который повторяет со сдвигом значения столбцов «скорость» и «давление» (здесь сдвиг равен 3).:

                          index     speed   pressure
0  2020-01-01 00:00:03.001291  1.782449  -0.964646
1  2020-01-01 00:00:03.001291       NaN        NaN
2  2020-01-01 00:00:03.001291       NaN        NaN
3  2020-01-01 00:00:26.785289  7.090295  20.997679
4  2020-01-01 00:00:26.785289  1.782449  -0.964646
5  2020-01-01 00:00:26.785289       NaN        NaN
6  2020-01-01 00:00:33.003518  7.628241  75.141566
7  2020-01-01 00:00:33.003518  7.090295  20.997679
8  2020-01-01 00:00:33.003518  1.782449  -0.964646
9  2020-01-01 00:01:16.731216  9.029616  46.504617
10 2020-01-01 00:01:16.731216  7.628241  75.141566
11 2020-01-01 00:01:16.731216  7.090295  20.997679
 

Это можно получить с помощью цикла, но он слишком медленный для больших кадров данных:

 n = 3
df_rpt = df.reindex(np.repeat(df.index.values, n), method='bfill')
df_rpt.reset_index(inplace=True)
Col = ['speed', 'pressure']
for c in Col:
    for i in range(0, n   1):
        df.loc[:, c   '_shift'   str(i)] = df.loc[:, c].shift(i)
df_s = df_rpt.copy()
for i in df_rpt.index:
    for c in Col:
        df_s.loc[i, c] = df.loc[df_s.iloc[i]['index'], c   '_shift'   str(i % n)]
 

Есть ли более быстрый способ сделать это ?

Ответ №1:

Попробуй:

 N = 3

df.speed = list(map(list, zip(*[df.speed.shift(x) for x in range(N)])))
df.pressure = list(map(list, zip(*[df.pressure.shift(x) for x in range(N)])))

df_out = df.explode("speed")
df_out.pressure = df.pressure.explode()
print(df_out)
 

С принтами:

                                speed   pressure
2020-01-01 00:00:03.001291  1.782449  -0.964646
2020-01-01 00:00:03.001291       NaN        NaN
2020-01-01 00:00:03.001291       NaN        NaN
2020-01-01 00:00:26.785289  7.090295  20.997679
2020-01-01 00:00:26.785289  1.782449  -0.964646
2020-01-01 00:00:26.785289       NaN        NaN
2020-01-01 00:00:33.003518  7.628241  75.141566
2020-01-01 00:00:33.003518  7.090295  20.997679
2020-01-01 00:00:33.003518  1.782449  -0.964646
2020-01-01 00:01:16.731216  9.029616  46.504617
2020-01-01 00:01:16.731216  7.628241  75.141566
2020-01-01 00:01:16.731216  7.090295  20.997679
 

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

1. Очень милый. 1 @AndrejKesely

2. Очень эффективно.