Python 如何将第一个有效值向左移动?
我想将按日历年排序的数据帧更改为过去的年份Python 如何将第一个有效值向左移动?,python,pandas,dataframe,Python,Pandas,Dataframe,我想将按日历年排序的数据帧更改为过去的年份 id 2015 2016 2017 2018 2019 0 NaN 7.0 8.0 7.0 3.0 1 NaN 8.0 5.0 7.0 NaN 2 4.0 NaN 5.0 NaN NaN 3 5.0 4.0 3.0 9.0 NaN 4 NaN NaN NaN NaN 1.0 5 4.0 3.0 NaN 4.0 5.0 我需
id 2015 2016 2017 2018 2019
0 NaN 7.0 8.0 7.0 3.0
1 NaN 8.0 5.0 7.0 NaN
2 4.0 NaN 5.0 NaN NaN
3 5.0 4.0 3.0 9.0 NaN
4 NaN NaN NaN NaN 1.0
5 4.0 3.0 NaN 4.0 5.0
我需要将所有有效值左移到第一列
预期结果应如下所示:
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
注意:id是一列,而不是索引。找到每行的移位,然后分组应用移位:
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()
输出:
找到每行的班次,然后分组应用班次:
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()
输出:
让我们尝试np.roll的行应用程序:
不幸的是,np.roll没有矢量化,无法对单独的行执行不同的移位,为了在值之间保留NAN,必须这样做 让我们试试np.roll的行应用程序:
不幸的是,np.roll没有矢量化,无法对单独的行执行不同的移位,为了在值之间保留NAN,必须这样做 您可以使用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]
您可以使用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]
使用第一个有效索引如何:
输出:
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
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
细节
首先,使用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)
输出:
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
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
使用第一个有效索引如何:
输出:
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
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
细节
首先,使用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)
输出:
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
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
实际数字之间应保留空值。id列是索引还是实际列?它是实际列实际数字之间应保留空值。id列是索引还是实际列?它是实际列