#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. Очень эффективно.