如何在python中用null之前的所有前面值和null之后的第一个后续值的平均值填充null值?

Posted

技术标签:

【中文标题】如何在python中用null之前的所有前面值和null之后的第一个后续值的平均值填充null值?【英文标题】:How to fill the null values with the average of all the preceeding values before null and first succeeding value after null in python? 【发布时间】:2020-11-05 11:57:30 【问题描述】:

我有一个包含 5000 条记录的数据框。我希望填充空值:

平均(null 之前的所有 Preceding 值,null 之后的第一个后续值)

data:

Date          gcs     Comp     Clay       WTS
2020-01-01    1550     41      9.41      22.6
2020-01-02    1540     48      9.50      25.8
2020-01-03    NAN      NAN     NAN        NAN
2020-01-04    1542     42      9.30      23.7
2020-01-05    1580     48      9.10      21.2
2020-01-06    NAN     NAN      NAN       NAN
2020-01-07    1520     40      10        20.2
2020-01-08    1523     30      25         19

示例: 对于日期 2020 年 1 月 3 日,我希望 gcs 列中的空值填充为 1544 的平均值(1550,1540,1542)。

1550 和 1540 是 null 之前的前面的值,1542 是我在 null 之后的第一个后续值。

同样,

对于日期 2020-01-06,我希望填充 gcs 列的空值 平均 (1550,1540,1544,1542,1580,1520) 得出 1546。

1550 到 1580 是 null 之前的前面的值,1520 是 null 之后的第一个后续值。

Desired Output:

Date          gcs     Comp     Clay       WTS
2020-01-01    1550     41      9.41      22.6
2020-01-02    1540     48      9.50      25.8
2020-01-03    1544     43.66   9.403     24.03
2020-01-04    1542     42      9.30      23.7
2020-01-05    1580     48      9.10      21.2
2020-01-06    1546     43.77   9.45      22.92
2020-01-07    1520     40      10        20.2
2020-01-08    1523     30      25         19

**编辑:

感谢汤姆的回复。 我将日期列保留为索引并尝试了以下代码:

def foo(row):
    if any(row.isna()):
        df.loc[row.name,row.isna()] = df.expanding().mean().shift(-1).loc[row.name,:]
df.apply(foo, axis=1)

我得到的输出是:

Date
2020-01-01    None
2020-01-02    None
2020-01-03    None
2020-01-04    None
2020-01-05    None
2020-01-06    None
2020-01-07    None
2020-01-08    None
dtype: object


你能帮我找出问题所在吗?

【问题讨论】:

感谢@Tom 的回复。我得到所有空值作为输出,你能帮我找出问题所在,因为我是 python 新手,即使在一些基础知识方面我也可能会犯错误 感谢任何人在此问题上的任何帮助。 您应该在该答案下发布有关该答案的 cmets/问题,jsyk!你在做df = df.apply(foo, axis=1) 还是df.apply(foo, axis=1)。这个操作对于apply b/c 来说有点奇怪,它被修改为df什么都不返回(请注意foo 中没有return)。所以如果你用“=”重新分配df,你会得到一个空的DataFrame。我只是试探一下可能出了什么问题,可能是其他问题 但答案对我有用;虽然我确实将“日期”设置为索引,但我确保数字是float(不是strobject 或其他东西);您可以验证您的“NAN”确实是空值(并被row.isna 接收)。如果您需要对答案进行更多解释,我很乐意发布更多内容 我需要在函数之前定义或提及什么是“行”吗?因为我在函数之前没有任何东西。附上我的代码图像。 @汤姆 【参考方案1】:

以下似乎有效。您为修改 df 的行定义了一个 apply 函数。每次到达一行(具有空值)时,您可以采用 expanding 的平均值为 df(see here),使用 shift 包含下一行。然后使用loc 用新值覆盖df

def foo(row):
    if any(row.isna()):
        df.loc[row.name,row.isna()] = df.expanding().mean().shift(-1).loc[row.name,:]

申请:

>>>df.apply(foo, axis=1)

               gcs       Comp       Clay        WTS
Date                                               
2020-01-01  1550.0  41.000000   9.410000  22.600000
2020-01-02  1540.0  48.000000   9.500000  25.800000
2020-01-03  1544.0  43.666667   9.403333  24.033333
2020-01-04  1542.0  42.000000   9.300000  23.700000
2020-01-05  1580.0  48.000000   9.100000  21.200000
2020-01-06  1546.0  43.777778   9.452222  22.922222
2020-01-07  1520.0  40.000000  10.000000  20.200000
2020-01-08  1523.0  30.000000  25.000000  19.000000

请注意,我将您的 Date 列移动为索引。我认为上面的方法应该适用于缺失值的任何地方,确保从上到下填写值。

我不确定它将如何处理扩展到 5000 行,但您似乎必须使用 apply 或某些循环 b/c,您希望在未来的估算值的计算中包含估算值*。我添加了if 语句 b/c 它似乎大大加快了计算速度:

%%timeit
df.apply(foo, axis=1)
#1.17 ms ± 25.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%%timeit
df.apply(foo_without_if, axis=1)
#16.2 ms ± 201 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

*如果你不想这样做(即你可以只取滚动平均值但忽略前面行中的 NA),你可以这样做:

mask = df.isna()
df[mask] = df.expanding().mean()[mask.shift(1)].shift(-1)

【讨论】:

以上是关于如何在python中用null之前的所有前面值和null之后的第一个后续值的平均值填充null值?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Firebase 数据库,DataSnapshot?如何获取值和键,null 安全

如何在 YML 中用值和子属性表示 Spring 属性?

Hive--对空值和NULL的处理

如何在 DataFrame 中用空值替换数字?

如何在 Python 中的一个函数调用中使用默认值和任意参数?

Python:如何在所有文件、文件夹和子文件夹的名称中用下划线替换空格?