我有一个Pandas Dataframe,每行至少有4个非NaN值, 但位于不同的栏目:
Index Col1 Col2 Col3 Col4 Col5 Col6 Col7 Col8
1991-12-31 100.000 100.000 100.000 89.123 NaN NaN NaN NaN
1992-01-31 98.300 101.530 100.000 NaN 92.342 NaN NaN NaN
1992-02-29 NaN 100.230 98.713 97.602 NaN NaN NaN NaN
1992-03-31 NaN NaN 102.060 93.473 98.123 NaN NaN NaN
1992-04-30 NaN 102.205 107.755 94.529 94.529 NaN NaN NaN
(我只显示前8列)我想把它变成一个数据框,每行有4列。 这些行应仅包含该日期的前四个(从左到右读取)非NaN值。
每一行的顺序都很重要。
答案 0 :(得分:4)
如果订单不重要,您可以沿第一个轴拨打np.sort
。
df = df.set_index('Index') # ignore if `Index` already is the index
pd.DataFrame(np.sort(df.values, axis=1)[:, :4],
columns=np.arange(1, 5)).add_prefix('Col')
Col1 Col2 Col3 Col4
0 89.123 100.000 100.000 100.000
1 92.342 98.300 100.000 101.530
2 97.602 98.713 100.230 NaN
3 93.473 98.123 102.060 NaN
4 94.529 94.529 102.205 107.755
这比我的第二个解决方案快得多,所以如果可以的话,请务必考虑一下。
如果订单有问题,请致电sorted
+ apply
并获取结果的前4列。
df.apply(sorted, key=np.isnan, axis=1).iloc[:, :4]
Col1 Col2 Col3 Col4
Index
1991-12-31 100.000 100.000 100.000 89.123
1992-01-31 98.300 101.530 100.000 92.342
1992-02-29 100.230 98.713 97.602 NaN
1992-03-31 102.060 93.473 98.123 NaN
1992-04-30 102.205 107.755 94.529 94.529
<强>计时强>
以下是 我的答案的时间 -
df = pd.concat([df] * 10000, ignore_index=1)
%timeit df.apply(sorted, key=np.isnan, axis=1).iloc[:, :4]
1 loop, best of 3: 8.45 s per loop
pd.DataFrame(np.sort(df.values, axis=1)[:, :4],
columns=np.arange(1, 5)).add_prefix('Col')
100 loops, best of 3: 4.76 ms per loop
答案 1 :(得分:2)
您可以使用:
#if necessary
#df = df.set_index('Index')
df = df.apply(lambda x: pd.Series(x.dropna().values), axis=1).iloc[:, :4]
print (df)
0 1 2 3
Index
1991-12-31 100.000 100.000 100.000 89.123
1992-01-31 98.300 101.530 100.000 92.342
1992-02-29 100.230 98.713 97.602 NaN
1992-03-31 102.060 93.473 98.123 NaN
1992-04-30 102.205 107.755 94.529 94.529
为了更好地使用性能numpy
- 使用要求每行至少有4个非值:
a = df.values
df = pd.DataFrame(a[~np.isnan(a)].reshape(a.shape[0],-1)[:, :4], index=df.index)
<强>计时强>:
Index Col1 Col2 Col3 Col4 Col5 Col6 Col7 Col8
0 1991-12-31 100.0 100.000 100.000 89.123 NaN NaN NaN NaN
1 1992-01-31 98.3 101.530 100.000 NaN 92.342 NaN NaN NaN
2 1992-02-29 NaN 100.230 98.713 97.602 NaN NaN NaN 1.0
3 1992-03-31 NaN NaN 102.060 93.473 98.123 NaN NaN 1.0
4 1992-04-30 NaN 102.205 107.755 94.529 94.529 NaN NaN NaN
df = df.set_index('Index')
df = pd.concat([df] * 10000, ignore_index=1)
In [260]: %timeit pd.DataFrame(justify(df.values, invalid_val=np.nan, axis=1, side='left')[:,:4])
100 loops, best of 3: 6.78 ms per loop
In [261]: %%timeit a = df.values
...: pd.DataFrame(a[~np.isnan(a)].reshape(a.shape[0],-1)[:, :4], index=df.index)
...:
100 loops, best of 3: 2.11 ms per loop
In [262]: %timeit pd.DataFrame(np.sort(df.values, axis=1)[:, :4], columns=np.arange(1, 5)).add_prefix('Col')
100 loops, best of 3: 5.28 ms per loop
In [263]: %timeit pd.DataFrame(mask_app(df.values)[:,:4])
100 loops, best of 3: 8.68 ms per loop