我有一个pandas数据帧,我想从最后一个非Null值迭代,然后从该值中减去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],\
'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,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
这给了我想要的输出
In [13]: df
Out[13]:
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 14 13 12 11 10
2 0 1 2 3 4 5 6 7 8 9
3 4 3 2 1 0 0 0 0 0 0
BUT。在我的真实世界数据中,我有50K以上的列,上面的代码花了太长时间。
任何人都可以建议我如何让这跑得更快? 我相信解决方案是以某种方式告诉代码,一旦子句等于零,就转移到下一行。但Idk怎么做,因为即使我使用max(0,减法公式)代码仍然浪费时间减去。
谢谢。
答案 0 :(得分:0)
我不知道它会有多快,但您可以尝试x <- airquality[ , 1]
fun <- function(x){
for (i in 1: length(x))
y <- sum(x[i,1], x[i+1, 1])
y
}
,ffill
和fillna
。例如:
cumsum
这有点棘手。首先,我们通过向前填充最右边的元素并查看它是否为空来找出我们需要填充的单元格(可能有更快的方式来使用last_valid_index测试,但这是我发生的第一件事)
>>> 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
如果我们用-1填充空白点,我们可以通过累积求和得到我们想要的值:
>>> mask = df.ffill(axis=1).notnull() & df.isnull()
>>> mask
a b c d e f g h i j
0 False False False False False False False False False False
1 False False False False False True True True True True
2 False False False False False False False False False False
3 False True True True True True True True True True
我们不想要的许多价值观,但这没关系,因为我们只会插入我们需要的价值观。我们应该剪辑为0,但是:
>>> (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
最后我们可以使用mask为False的原始值,以及mask为True的新值:
>>> 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
(注意:这假设我们需要填充的行看起来与您示例中的行相似。如果它们变得更加混乱,我们需要做更多的工作,但相同的技术将适用。)