如何在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
(不是str
或object
或其他东西);您可以验证您的“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 安全