有没有办法创建一个 pandas 数据框,其行是整数,这些整数会增加直到每行达到某个值?
Is there a way to create a pandas dataframe whose rows are integers which increase until a certain value is reached in each row?
例如,假设我有一个整数数组 [5, 3, 7, 6, 4]。我希望找到一种有效的方法来创建一个 pandas 数据框,如下所示:
这应该是数据框中的第一行包含数字 1 到 5,第二行应该包含数字 1 到 3,依此类推。
有没有不用循环实现的方法?
设置 df:
df = pd.DataFrame([[1,2,3,4,5,6,7]]*5)
逐行过滤最大值:
max_row_val = [5, 3, 7, 6, 4]
df.ge(max_row_val, axis=0)
0 1 2 3 4 5 6
0 False False False False False True True
1 False False False True True True True
2 False False False False False False False
3 False False False False False False True
4 False False False False True True True
并且只需在 True
将 df 设置为 nan
df[df.ge(max_row_val, axis=0)] = np.nan
0 1 2 3 4 5 6
0 1 2 3 4.0 5.0 NaN NaN
1 1 2 3 NaN NaN NaN NaN
2 1 2 3 4.0 5.0 6.0 7.0
3 1 2 3 4.0 5.0 6.0 NaN
4 1 2 3 4.0 NaN NaN NaN
对于这个大小的 df,在我的机器上每个循环实现了 0.0003582255399999667s。
您可以使用 .apply() 方法来完成。
但是,如果您需要在大数据帧上执行此操作,性能将非常糟糕。
solution with apply methode
具有range
功能的简单单行
pd.DataFrame(range(1, x+1) for x in [5, 3, 7, 6, 4])
输出
0 1 2 3 4 5 6
0 1.0 2.0 3.0 4.0 5.0 NaN NaN
1 1.0 2.0 3.0 NaN NaN NaN NaN
2 1.0 2.0 3.0 4.0 5.0 6.0 7.0
3 1.0 2.0 3.0 4.0 5.0 6.0 NaN
4 1.0 2.0 3.0 4.0 NaN NaN NaN
使用 numpy 和屏蔽数组提高性能:
a = [5, 3, 7, 6, 4]
n = np.repeat(np.arange(1, max(a)+1)[None, :], len(a), axis=0)
m = n > np.array(a)[:, None]
df = pd.DataFrame(np.ma.array(n, mask=m))
我们首先形成 n
,即 1..max(a)
重复 a
的长度,然后找到 m
掩盖 np.NaN
的适当位置。然后,将掩码数组传递给框架构造函数,
获得
0 1 2 3 4 5 6
0 1.0 2.0 3.0 4.0 5.0 NaN NaN
1 1.0 2.0 3.0 NaN NaN NaN NaN
2 1.0 2.0 3.0 4.0 5.0 6.0 7.0
3 1.0 2.0 3.0 4.0 5.0 6.0 NaN
4 1.0 2.0 3.0 4.0 NaN NaN NaN
时间:
对于给定的设置:
a = [5, 3, 7, 6, 4]
# @Vishnudev's solution
%timeit pd.DataFrame(range(1, x+1) for x in a)
553 µs ± 25.2 µs per loop
# @Tom Mclean's solution (a bit modified for generalization)
%%timeit
df = pd.DataFrame([list(range(1, max(a)+1))]*len(a))
df[df.ge(a, axis=0)] = np.nan
2.14 ms ± 43.9 µs per loop
# This solution
%%timeit
n = np.repeat(np.arange(1, max(a)+1)[None, :], len(a), axis=0)
m = n > np.array(a)[:, None]
pd.DataFrame(np.ma.array(n, mask=m))
139 µs ± 2.22 µs per loop
对于大数组:
a = np.random.randint(3, 10_000, size=5_000)
# @Vishnudev solution
%timeit pd.DataFrame(range(1, x+1) for x in a)
8.12 s ± 76 ms per loop
# @Tom Mclean's solution (a bit modified for generalization)
%%timeit
df = pd.DataFrame([list(range(1, max(a)+1))]*len(a))
df[df.ge(a, axis=0)] = np.nan
15 s ± 199 ms per loop
# This solution
%%timeit
n = np.repeat(np.arange(1, max(a)+1)[None, :], len(a), axis=0)
m = n > np.array(a)[:, None]
pd.DataFrame(np.ma.array(n, mask=m))
583 ms ± 16.1 ms per loop
例如,假设我有一个整数数组 [5, 3, 7, 6, 4]。我希望找到一种有效的方法来创建一个 pandas 数据框,如下所示:
这应该是数据框中的第一行包含数字 1 到 5,第二行应该包含数字 1 到 3,依此类推。
有没有不用循环实现的方法?
设置 df:
df = pd.DataFrame([[1,2,3,4,5,6,7]]*5)
逐行过滤最大值:
max_row_val = [5, 3, 7, 6, 4]
df.ge(max_row_val, axis=0)
0 1 2 3 4 5 6
0 False False False False False True True
1 False False False True True True True
2 False False False False False False False
3 False False False False False False True
4 False False False False True True True
并且只需在 True
df[df.ge(max_row_val, axis=0)] = np.nan
0 1 2 3 4 5 6
0 1 2 3 4.0 5.0 NaN NaN
1 1 2 3 NaN NaN NaN NaN
2 1 2 3 4.0 5.0 6.0 7.0
3 1 2 3 4.0 5.0 6.0 NaN
4 1 2 3 4.0 NaN NaN NaN
对于这个大小的 df,在我的机器上每个循环实现了 0.0003582255399999667s。
您可以使用 .apply() 方法来完成。 但是,如果您需要在大数据帧上执行此操作,性能将非常糟糕。 solution with apply methode
具有range
功能的简单单行
pd.DataFrame(range(1, x+1) for x in [5, 3, 7, 6, 4])
输出
0 1 2 3 4 5 6
0 1.0 2.0 3.0 4.0 5.0 NaN NaN
1 1.0 2.0 3.0 NaN NaN NaN NaN
2 1.0 2.0 3.0 4.0 5.0 6.0 7.0
3 1.0 2.0 3.0 4.0 5.0 6.0 NaN
4 1.0 2.0 3.0 4.0 NaN NaN NaN
使用 numpy 和屏蔽数组提高性能:
a = [5, 3, 7, 6, 4]
n = np.repeat(np.arange(1, max(a)+1)[None, :], len(a), axis=0)
m = n > np.array(a)[:, None]
df = pd.DataFrame(np.ma.array(n, mask=m))
我们首先形成 n
,即 1..max(a)
重复 a
的长度,然后找到 m
掩盖 np.NaN
的适当位置。然后,将掩码数组传递给框架构造函数,
获得
0 1 2 3 4 5 6
0 1.0 2.0 3.0 4.0 5.0 NaN NaN
1 1.0 2.0 3.0 NaN NaN NaN NaN
2 1.0 2.0 3.0 4.0 5.0 6.0 7.0
3 1.0 2.0 3.0 4.0 5.0 6.0 NaN
4 1.0 2.0 3.0 4.0 NaN NaN NaN
时间:
对于给定的设置:
a = [5, 3, 7, 6, 4]
# @Vishnudev's solution
%timeit pd.DataFrame(range(1, x+1) for x in a)
553 µs ± 25.2 µs per loop
# @Tom Mclean's solution (a bit modified for generalization)
%%timeit
df = pd.DataFrame([list(range(1, max(a)+1))]*len(a))
df[df.ge(a, axis=0)] = np.nan
2.14 ms ± 43.9 µs per loop
# This solution
%%timeit
n = np.repeat(np.arange(1, max(a)+1)[None, :], len(a), axis=0)
m = n > np.array(a)[:, None]
pd.DataFrame(np.ma.array(n, mask=m))
139 µs ± 2.22 µs per loop
对于大数组:
a = np.random.randint(3, 10_000, size=5_000)
# @Vishnudev solution
%timeit pd.DataFrame(range(1, x+1) for x in a)
8.12 s ± 76 ms per loop
# @Tom Mclean's solution (a bit modified for generalization)
%%timeit
df = pd.DataFrame([list(range(1, max(a)+1))]*len(a))
df[df.ge(a, axis=0)] = np.nan
15 s ± 199 ms per loop
# This solution
%%timeit
n = np.repeat(np.arange(1, max(a)+1)[None, :], len(a), axis=0)
m = n > np.array(a)[:, None]
pd.DataFrame(np.ma.array(n, mask=m))
583 ms ± 16.1 ms per loop