Python 在数据帧中迭代行减去1
我有一个数据帧,我想从最后一个非空值开始迭代,然后从该值中减去1,用于接下来的所有行Python 在数据帧中迭代行减去1,python,pandas,Python,Pandas,我有一个数据帧,我想从最后一个非空值开始迭代,然后从该值中减去1,用于接下来的所有行 z = pd.DataFrame({'l':range(10),'r':[4,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan]\ ,'gh':[np.nan,np.nan,np.nan,np.nan,15,np.nan,np.nan,np.nan,np.nan,np.nan],\ '
z = pd.DataFrame({'l':range(10),'r':[4,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan]\
,'gh':[np.nan,np.nan,np.nan,np.nan,15,np.nan,np.nan,np.nan,np.nan,np.nan],\
'gfh':[np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,2]})
df = z.transpose().copy()
df.reset_index(inplace=True)
df.drop(['index'],axis=1, inplace=True)
df.columns = ['a','b','c','d','e','f','g','h','i','j']
In [8]: df
Out[8]:
a b c d e f g h i j
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 2
1 NaN NaN NaN NaN 15 NaN NaN NaN NaN NaN
2 0 1 2 3 4 5 6 7 8 9
3 4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
我有上面的数据帧,我希望在最后一列之前,每个数据帧减少1。例如,第2行的值是15,因此我希望后面是14、13、12、11、10。第一行中的2后面不会有任何内容,因为没有列了。另外,最后一行中的4将是3,2,1,0,0,0等
通过执行以下操作,我达到了预期的输出
for index, row in df.iterrows():
df.iloc[index,df.columns.get_loc(df.iloc[index].last_valid_index())+1:] =\
[(df.iloc[index,m.columns.get_loc(df.iloc[index].last_valid_index()):][0]-(x+1)).astype(int) \
for x in range((df.shape[1]-1)-df.columns.get_loc(df.iloc[index].last_valid_index()))]
df[df < 0] = 0
但是。在我的现实世界数据中,我有50K多个列,上面的代码花费的时间太长了
有人能建议我如何让这跑得更快吗?
我相信解决办法是告诉代码,一旦子动作等于零,就转到下一行。但Idk如何做到这一点,因为即使我使用max(0,减法公式),代码仍然会浪费时间进行减法运算
谢谢。我不知道它的速度有多快,但您可以尝试使用
ffill
、fillna
和cumsum
。例如:
>>> df
a b c d e f g h i j
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 2
1 NaN NaN NaN NaN 15 NaN NaN NaN NaN NaN
2 0 1 2 3 4 5 6 7 8 9
3 4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
>>> mask = df.ffill(axis=1).notnull() & df.isnull()
>>> df.where(~mask, df.fillna(-1).cumsum(axis=1).clip_lower(0))
a b c d e f g h i j
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 2
1 NaN NaN NaN NaN 15 10 9 8 7 6
2 0 1 2 3 4 5 6 7 8 9
3 4 3 2 1 0 0 0 0 0 0
这有点棘手。首先,我们通过向前填充最右边的元素并查看它是否为null来确定需要填充哪些单元格(使用last_valid_index测试可能有一种更快的方法,但这是我想到的第一件事) 如果我们用-1填充空白点,我们可以通过向右累积求和得到所需的值:
>>> (df.fillna(-1).cumsum(axis=1))
a b c d e f g h i j
0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -7
1 -1 -2 -3 -4 11 10 9 8 7 6
2 0 1 3 6 10 15 21 28 36 45
3 4 3 2 1 0 -1 -2 -3 -4 -5
很多我们不想要的值,但这没关系,因为我们只插入我们需要的值。但是,我们应该将其剪裁为0:
>>> df.fillna(-1).cumsum(axis=1).clip_lower(0)
a b c d e f g h i j
0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 11 10 9 8 7 6
2 0 1 3 6 10 15 21 28 36 45
3 4 3 2 1 0 0 0 0 0 0
最后,我们可以使用掩码为False的原始值,以及掩码为True的新值:
>>> df.where(~mask, df.fillna(-1).cumsum(axis=1).clip_lower(0))
a b c d e f g h i j
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 2
1 NaN NaN NaN NaN 15 10 9 8 7 6
2 0 1 2 3 4 5 6 7 8 9
3 4 3 2 1 0 0 0 0 0 0
(注意:这假设我们需要填充的行与您的示例中的行相似。如果它们更混乱,我们需要做更多的工作,但同样的技术也适用。)我不知道它会有多快,但您可以尝试使用
ffill
、fillna
和cumsum
。例如:
>>> df
a b c d e f g h i j
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 2
1 NaN NaN NaN NaN 15 NaN NaN NaN NaN NaN
2 0 1 2 3 4 5 6 7 8 9
3 4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
>>> mask = df.ffill(axis=1).notnull() & df.isnull()
>>> df.where(~mask, df.fillna(-1).cumsum(axis=1).clip_lower(0))
a b c d e f g h i j
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 2
1 NaN NaN NaN NaN 15 10 9 8 7 6
2 0 1 2 3 4 5 6 7 8 9
3 4 3 2 1 0 0 0 0 0 0
这有点棘手。首先,我们通过向前填充最右边的元素并查看它是否为null来确定需要填充哪些单元格(使用last_valid_index测试可能有一种更快的方法,但这是我想到的第一件事) 如果我们用-1填充空白点,我们可以通过向右累积求和得到所需的值:
>>> (df.fillna(-1).cumsum(axis=1))
a b c d e f g h i j
0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -7
1 -1 -2 -3 -4 11 10 9 8 7 6
2 0 1 3 6 10 15 21 28 36 45
3 4 3 2 1 0 -1 -2 -3 -4 -5
很多我们不想要的值,但这没关系,因为我们只插入我们需要的值。但是,我们应该将其剪裁为0:
>>> df.fillna(-1).cumsum(axis=1).clip_lower(0)
a b c d e f g h i j
0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 11 10 9 8 7 6
2 0 1 3 6 10 15 21 28 36 45
3 4 3 2 1 0 0 0 0 0 0
最后,我们可以使用掩码为False的原始值,以及掩码为True的新值:
>>> df.where(~mask, df.fillna(-1).cumsum(axis=1).clip_lower(0))
a b c d e f g h i j
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN 2
1 NaN NaN NaN NaN 15 10 9 8 7 6
2 0 1 2 3 4 5 6 7 8 9
3 4 3 2 1 0 0 0 0 0 0
(注意:这假设我们需要填充的行与示例中的行相似。如果它们更混乱,我们需要做更多的工作,但同样的技术也适用。)