如何基于多个条件填充基于前一行的熊猫数据框列的行?

时间:2021-05-07 04:52:09

标签: python pandas dataframe

免责声明:这可能是重复的,但我找不到确切的解决方案。请随时将此问题标记为重复,并在评论中提供指向重复问题的链接。

我仍在学习 python 数据帧操作,这可能有一个我无法弄清楚的非常简单的解决方案。

我有一个带有单列的 python 数据框。现在,如果满足某些条件,我想将每一行的值更改为前一行的值。我已经创建了一个循环解决方案来实现这一点,但我希望有一个更有效的解决方案。

创建初始数据:

import numpy as np
import pandas as pd

data = np.random.randint(5,30,size=20)
df = pd.DataFrame(data, columns=['random_numbers'])

print(df)

    random_numbers
0                6
1               24
2               29
3               18
4               22
5               17
6               12
7                7
8                6
9               27
10              29
11              13
12              23
13               6
14              25
15              24
16              16
17              15
18              25
19              19

现在假设两个条件是 1) 值小于 10 和 2) 值大于 20。在任何这些情况下,将行值设置为前一行值。这已以循环格式实现如下:

for index,row in df.iterrows():
    if index == 0:
        continue;
    if(row.random_numbers<10):
        df.loc[index,'random_numbers']=df.loc[index-1,'random_numbers']
    if(row.random_numbers>20):
        df.loc[index,'random_numbers']=df.loc[index-1,'random_numbers']

    random_numbers
0                6
1                6
2                6
3               18
4               18
5               17
6               12
7               12
8               12
9               12
10              12
11              13
12              13
13              13
14              13
15              13
16              16
17              15
18              15
19              19

请提出一种更有效的方法来实现此逻辑,因为我使用了大量行。

2 个答案:

答案 0 :(得分:5)

您可以将小于 10 的值和大于 20 的值替换为 NaN,然后使用 pandas.DataFrame.ffill() 用前一行值填充 nan。

mask = (df['random_numbers'] < 10) | (df['random_numbers'] > 20)

# Since you escape with `if index == 0:`
mask[df.index[0]] = False

df.loc[mask, 'random_numbers'] = np.nan

df['random_numbers'].ffill(inplace=True)
# Original

    random_numbers
0                7
1               28
2                8
3               14
4               12
5               20
6               21
7               11
8               16
9               27
10              19
11              23
12              18
13               5
14               6
15              11
16               6
17               8
18              17
19               8

# After replaced

    random_numbers
0              7.0
1              7.0
2              7.0
3             14.0
4             12.0
5             20.0
6             20.0
7             11.0
8             16.0
9             16.0
10            19.0
11            19.0
12            18.0
13            18.0
14            18.0
15            11.0
16            11.0
17            11.0
18            17.0
19            17.0

答案 1 :(得分:2)

我们还可以通过将 .mask().ffill() 一起使用并在 [1:] 上切片,以更简单的方式实现,如下所示:

df['random_numbers'][1:] = df['random_numbers'][1:].mask((df['random_numbers'] < 10) | (df['random_numbers'] > 20))

df['random_numbers'] = df['random_numbers'].ffill(downcast='infer')

.mask() 测试条件并在条件为真时替换为 NaN(如果未提供参数 NaN,则默认替换为 other=)。保留条件不满足的行的原始值。

请注意,结果数字保持为 integer,而不是通过在对 {{3} 的调用中提供 float意外地转换为 downcast='infer' 类型}.

我们在第一行使用 [1:] 以确保行 0 上的数据不经过任何转换。

# Original data:  (reusing your sample data)

    random_numbers
0                6
1               24
2               29
3               18
4               22
5               17
6               12
7                7
8                6
9               27
10              29
11              13
12              23
13               6
14              25
15              24
16              16
17              15
18              25
19              19


# After transposition:

    random_numbers
0                6
1                6
2                6
3               18
4               18
5               17
6               12
7               12
8               12
9               12
10              12
11              13
12              13
13              13
14              13
15              13
16              16
17              15
18              15
19              19