我想将按日历年排序的数据框更改为过去的几年。
id Y1 Y2 Y3 Y4 Y5
0 7.0 8.0 7.0 3.0 NaN
1 8.0 5.0 7.0 NaN NaN
2 4.0 NaN 5.0 NaN NaN
3 5.0 4.0 3.0 9.0 NaN
4 1.0 NaN NaN NaN NaN
5 4.0 3.0 NaN 4.0 5.0
我需要将所有有效值都移到第一列。
预期结果应如下所示:
print(type(vector[0][0]))
注意:“ id”是一列,而不是索引。
答案 0 :(得分:5)
您可以使用ogrid
和索引对基础的numpy数组进行操作。
u = df.set_index('id').values
x, y = u.shape
r, c = np.ogrid[:x, :y]
m = (~np.isnan(u)).argmax(1)
cix = c + m[:, None]
cix[cix >= y] -= y
u[r, cix]
array([[ 7., 8., 7., 3., nan],
[ 8., 5., 7., nan, nan],
[ 4., nan, 5., nan, nan],
[ 5., 4., 3., 9., nan],
[ 1., nan, nan, nan, nan],
[ 4., 3., nan, 4., 5.]])
答案 1 :(得分:4)
让我们尝试np.roll
的逐行应用程序:
df = df.set_index('id')
# using @user3483203's argmax trick to optimize
df.apply(lambda x: np.roll(x, -(~np.isnan(x)).argmax()), axis=1, raw=True)
2015 2016 2017 2018 2019
id
0 7.0 8.0 7.0 3.0 NaN
1 8.0 5.0 7.0 NaN NaN
2 4.0 NaN 5.0 NaN NaN
3 5.0 4.0 3.0 9.0 NaN
4 1.0 NaN NaN NaN NaN
5 4.0 3.0 NaN 4.0 5.0
不幸的是,np.roll
未被向量化以对单独的行执行不同的移位,并且为了保留值之间的NaN,必须这样做。
答案 2 :(得分:3)
找到每一行的班次,然后按组应用班次:
df = df.set_index('id')
# Required shift for each row
n = df.isnull()
s = (n*n.cumprod(1)).sum(1)*-1
for shift, idx in s.groupby(s).groups.items():
df.loc[idx, :] = df.loc[idx].shift(shift, axis=1)
df.columns = [f'Y{i+1}' for i in range(df.shape[1])]
df = df.reset_index()
id Y1 Y2 Y3 Y4 Y5
0 0 7.0 8.0 7.0 3.0 NaN
1 1 8.0 5.0 7.0 NaN NaN
2 2 4.0 NaN 5.0 NaN NaN
3 3 5.0 4.0 3.0 9.0 NaN
4 4 1.0 NaN NaN NaN NaN
5 5 4.0 3.0 NaN 4.0 5.0
答案 3 :(得分:3)
如何使用first_valid_index
:
df = df.set_index('id')
df.apply(lambda x: x.shift(-x.index.get_loc(x.first_valid_index())), axis=1)
输出:
2015 2016 2017 2018 2019
id
0 7.0 8.0 7.0 3.0 NaN
1 8.0 5.0 7.0 NaN NaN
2 4.0 NaN 5.0 NaN NaN
3 5.0 4.0 3.0 9.0 NaN
4 1.0 NaN NaN NaN NaN
5 4.0 3.0 NaN 4.0 5.0
首先,apply
使用axis=1
,这将在每行上应用一个函数。
使用first_valid_index
查找pd.Series中第一个非空值的索引。请记住,在这种情况下,pd.Series是数据帧的每一行。
接下来,使用get_loc
确定该索引的整数位置。
最后,使用shift
将pd.Series的值向后移动pd.Series索引中的整数位置。
而且,您可以添加第二行以重命名列
df.apply(lambda x: x.shift(-x.index.get_loc(x.first_valid_index())), axis=1)\
.set_axis(['Y'+str(i) for i in range(1, df.shape[1]+1)], axis=1, inplace=False)
输出:
Y1 Y2 Y3 Y4 Y5
id
0 7.0 8.0 7.0 3.0 NaN
1 8.0 5.0 7.0 NaN NaN
2 4.0 NaN 5.0 NaN NaN
3 5.0 4.0 3.0 9.0 NaN
4 1.0 NaN NaN NaN NaN
5 4.0 3.0 NaN 4.0 5.0