Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何将第一个有效值向左移动?_Python_Pandas_Dataframe - Fatal编程技术网

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列是索引还是实际列?它是实际列