使用二级索引复制 DataFrame 中的 n 行?
Duplicating n rows in a DataFrame using 2nd level index?
我有一个 pandas DataFrame,例如看起来像这样。
df
Values
Timestamp
2020-02-01 A
2020-02-02 B
2020-02-03 C
我想(为了简化之后要完成的处理)保留 n 行的 window 并为每个时间戳复制它,并使用本地 int 索引创建二级索引。
当 n=2 时,这将给出:
df_new
Values
Timestamp 2nd_level_index
2020-02-01 0 NaN
1 A
2020-02-02 0 A
1 B
2020-03-03 0 B
1 C
是否有任何类型的 pandas 内置函数可以帮助我做到这一点?
具有固定大小 (n) 的滚动 window 似乎是开始,但是我如何复制 window 并使用二级索引为每一行存储它?
在此先感谢您的帮助!
最佳,
编辑 04/05
采用建议代码并稍微更改输出格式,我将其调整为 2 列 DataFrame。
我最终得到了以下代码。
import pandas as pd
import numpy as np
from random import seed, randint
def transpose_n_rows(df: pd.DataFrame, n_rows: int) -> pd.DataFrame:
array = np.concatenate((np.full((len(df.columns),n_rows-1), np.nan), df.transpose()), axis=1)
shape = array.shape[:-1] + (array.shape[-1] - n_rows + 1, n_rows)
strides = array.strides + (array.strides[-1],)
array = np.lib.stride_tricks.as_strided(array, shape=shape, strides=strides)
midx = pd.MultiIndex.from_product([df.columns, range(n_rows)], names=['Data','Position'])
transposed = pd.DataFrame(np.concatenate(array, axis=1), index=df.index, columns=midx)
return transposed
n = 4
start = '2020-01-01 00:00+00:00'
end = '2020-01-01 12:00+00:00'
pr2h = pd.period_range(start=start, end=end, freq='2h')
seed(1)
values1 = [randint(0,10) for ts in pr2h]
values2 = [randint(20,30) for ts in pr2h]
df2h = pd.DataFrame({'Values1' : values1, 'Values2': values2}, index=pr2h)
df2h_new = transpose_n_rows(df2h, n)
这给出了。
In [29]:df2h
Out[29]:
Values1 Values2
2020-01-01 00:00 2 27
2020-01-01 02:00 9 30
2020-01-01 04:00 1 26
2020-01-01 06:00 4 23
2020-01-01 08:00 1 21
2020-01-01 10:00 7 27
2020-01-01 12:00 7 20
In [30]:df2h_new
Out[30]:
Data Values1 Values2
Position 0 1 2 3 0 1 2 3
2020-01-01 00:00 NaN NaN NaN 2.0 NaN NaN NaN 27.0
2020-01-01 02:00 NaN NaN 2.0 9.0 NaN NaN 27.0 30.0
2020-01-01 04:00 NaN 2.0 9.0 1.0 NaN 27.0 30.0 26.0
2020-01-01 06:00 2.0 9.0 1.0 4.0 27.0 30.0 26.0 23.0
2020-01-01 08:00 9.0 1.0 4.0 1.0 30.0 26.0 23.0 21.0
2020-01-01 10:00 1.0 4.0 1.0 7.0 26.0 23.0 21.0 27.0
2020-01-01 12:00 4.0 1.0 7.0 7.0 23.0 21.0 27.0 20.0
但是,我在 for 循环中为大量数据帧调用此函数 transpose_n_rows
。第一次使用让我有点担心性能问题。
我读到应该避免多次调用 np.concatenate 或 pd.concat,在这里,我有 2 个可能可以绕过的用途?
请问,如果可能的话,有什么建议可以摆脱它们吗?
提前感谢您的帮助!最佳,
我认为 pandas 中没有内置方法。
strides 生成滚动二维数组的可能解决方案:
n = 2
#added Nones for first values of 2d array
x = np.concatenate([[None] * (n-1), df['Values']])
def rolling_window(a, window):
shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
strides = a.strides + (a.strides[-1],)
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
a = rolling_window(x, n)
print (a)
[[None 'A']
['A' 'B']
['B' 'C']]
然后通过 MultiIndex.from_product
and flatten values of array by numpy.ravel
创建 MultiIndex
:
mux = pd.MultiIndex.from_product([df.index, range(n)], names=('times','level1'))
df = pd.DataFrame({'Values': np.ravel(a)}, index=mux)
print (df)
Values
times level1
2020-02-01 0 None
1 A
2020-02-02 0 A
1 B
2020-02-03 0 B
1 C
如果值为数字,则添加缺失值:
print (df)
Values
Timestamp
2020-02-01 1
2020-02-02 2
2020-02-03 3
n = 2
x = np.concatenate([[np.nan] * (n-1), df['Values']])
def rolling_window(a, window):
shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
strides = a.strides + (a.strides[-1],)
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
a = rolling_window(x, n)
print (a)
[[nan 1.]
[ 1. 2.]
[ 2. 3.]]
mux = pd.MultiIndex.from_product([df.index, range(n)], names=('times','level1'))
df = pd.DataFrame({'Values': np.ravel(a)}, index=mux)
print (df)
Values
times level1
2020-02-01 0 NaN
1 1.0
2020-02-02 0 1.0
1 2.0
2020-02-03 0 2.0
1 3.0
我有一个 pandas DataFrame,例如看起来像这样。
df
Values
Timestamp
2020-02-01 A
2020-02-02 B
2020-02-03 C
我想(为了简化之后要完成的处理)保留 n 行的 window 并为每个时间戳复制它,并使用本地 int 索引创建二级索引。
当 n=2 时,这将给出:
df_new
Values
Timestamp 2nd_level_index
2020-02-01 0 NaN
1 A
2020-02-02 0 A
1 B
2020-03-03 0 B
1 C
是否有任何类型的 pandas 内置函数可以帮助我做到这一点? 具有固定大小 (n) 的滚动 window 似乎是开始,但是我如何复制 window 并使用二级索引为每一行存储它?
在此先感谢您的帮助! 最佳,
编辑 04/05
采用建议代码并稍微更改输出格式,我将其调整为 2 列 DataFrame。
我最终得到了以下代码。
import pandas as pd
import numpy as np
from random import seed, randint
def transpose_n_rows(df: pd.DataFrame, n_rows: int) -> pd.DataFrame:
array = np.concatenate((np.full((len(df.columns),n_rows-1), np.nan), df.transpose()), axis=1)
shape = array.shape[:-1] + (array.shape[-1] - n_rows + 1, n_rows)
strides = array.strides + (array.strides[-1],)
array = np.lib.stride_tricks.as_strided(array, shape=shape, strides=strides)
midx = pd.MultiIndex.from_product([df.columns, range(n_rows)], names=['Data','Position'])
transposed = pd.DataFrame(np.concatenate(array, axis=1), index=df.index, columns=midx)
return transposed
n = 4
start = '2020-01-01 00:00+00:00'
end = '2020-01-01 12:00+00:00'
pr2h = pd.period_range(start=start, end=end, freq='2h')
seed(1)
values1 = [randint(0,10) for ts in pr2h]
values2 = [randint(20,30) for ts in pr2h]
df2h = pd.DataFrame({'Values1' : values1, 'Values2': values2}, index=pr2h)
df2h_new = transpose_n_rows(df2h, n)
这给出了。
In [29]:df2h
Out[29]:
Values1 Values2
2020-01-01 00:00 2 27
2020-01-01 02:00 9 30
2020-01-01 04:00 1 26
2020-01-01 06:00 4 23
2020-01-01 08:00 1 21
2020-01-01 10:00 7 27
2020-01-01 12:00 7 20
In [30]:df2h_new
Out[30]:
Data Values1 Values2
Position 0 1 2 3 0 1 2 3
2020-01-01 00:00 NaN NaN NaN 2.0 NaN NaN NaN 27.0
2020-01-01 02:00 NaN NaN 2.0 9.0 NaN NaN 27.0 30.0
2020-01-01 04:00 NaN 2.0 9.0 1.0 NaN 27.0 30.0 26.0
2020-01-01 06:00 2.0 9.0 1.0 4.0 27.0 30.0 26.0 23.0
2020-01-01 08:00 9.0 1.0 4.0 1.0 30.0 26.0 23.0 21.0
2020-01-01 10:00 1.0 4.0 1.0 7.0 26.0 23.0 21.0 27.0
2020-01-01 12:00 4.0 1.0 7.0 7.0 23.0 21.0 27.0 20.0
但是,我在 for 循环中为大量数据帧调用此函数 transpose_n_rows
。第一次使用让我有点担心性能问题。
我读到应该避免多次调用 np.concatenate 或 pd.concat,在这里,我有 2 个可能可以绕过的用途?
请问,如果可能的话,有什么建议可以摆脱它们吗?
提前感谢您的帮助!最佳,
我认为 pandas 中没有内置方法。
strides 生成滚动二维数组的可能解决方案:
n = 2
#added Nones for first values of 2d array
x = np.concatenate([[None] * (n-1), df['Values']])
def rolling_window(a, window):
shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
strides = a.strides + (a.strides[-1],)
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
a = rolling_window(x, n)
print (a)
[[None 'A']
['A' 'B']
['B' 'C']]
然后通过 MultiIndex.from_product
and flatten values of array by numpy.ravel
创建 MultiIndex
:
mux = pd.MultiIndex.from_product([df.index, range(n)], names=('times','level1'))
df = pd.DataFrame({'Values': np.ravel(a)}, index=mux)
print (df)
Values
times level1
2020-02-01 0 None
1 A
2020-02-02 0 A
1 B
2020-02-03 0 B
1 C
如果值为数字,则添加缺失值:
print (df)
Values
Timestamp
2020-02-01 1
2020-02-02 2
2020-02-03 3
n = 2
x = np.concatenate([[np.nan] * (n-1), df['Values']])
def rolling_window(a, window):
shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
strides = a.strides + (a.strides[-1],)
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
a = rolling_window(x, n)
print (a)
[[nan 1.]
[ 1. 2.]
[ 2. 3.]]
mux = pd.MultiIndex.from_product([df.index, range(n)], names=('times','level1'))
df = pd.DataFrame({'Values': np.ravel(a)}, index=mux)
print (df)
Values
times level1
2020-02-01 0 NaN
1 1.0
2020-02-02 0 1.0
1 2.0
2020-02-03 0 2.0
1 3.0