【问题标题】:Replace negative numbers, NaN and 0s with mean of next and previous positive number用下一个和上一个正数的平均值替换负数、NaN 和 0
【发布时间】:2021-12-26 12:12:36
【问题描述】:

我想用同一列的下一个和上一个正数的平均值替换负数、NaN 和 0。

原始数据框

    a   c
0   1   1
1   2   2
2   0   5
3   -3  NaN
4   -1  5
5   3   3

预期的输出数据帧是

    a    c
0   1     1
1   2     2
2   2.5   5    #In Col a --> Mean of 2 and 3 is 2.5 hence 0 replaced by 2.5
3   2.75  5  #In Col a --> Mean of 2.5 and 3 is 2.75 hence negative no. replaced by 2.75
4   2.875 5    #In Col a --> Mean of 2.75 and 3 is 2.875 hence negative no. replaced by 2.875
5   3     3

我尝试了另一种策略来处理否定号。 Nan 和 0 用前 3 个值的平均值替换它

m = df['a'] < 1
new = (df.loc[~m, 'a'].astype(float)
         .rolling(2, min_periods=1).mean()
         .reindex(df.index, method='ffill'))

df['a'].mask(m, new)

导致

0    1.0
1    2.0
2    1.5
3    1.5
4    1.5
5    2.0
Name: a, dtype: float64

但是我正在努力实施新策略(被问到)。

【问题讨论】:

  • 我没有投反对票,但我想这是因为你没有展示你尝试过和失败的东西。在要求其他人也考虑您的问题之前,很高兴表明您自己已经对问题进行了充分的思考
  • 感谢@CallumDA!我已经实施了问题中添加的另一个策略,但是为了提高模型的准确性,我需要帮助来实施第二个策略。
  • 好多了。现在看起来是一个的问题。我相应地投了赞成票

标签: python python-3.x pandas replace time-series


【解决方案1】:

我编辑了我的答案以更好地解决您的问题。但是请注意,5 和 5 的平均值是 5,而不是您在预期结果中写的 2.5。

这个新答案基于下面 hpchavaz 的答案。

# Replace 0 and negative values with NaN
df = df.mask(df<=0)

# Compute rank of consecutive NaN values
rank = df.isnull().astype('int')
rank = rank.cumsum() - rank.cumsum().where(rank==0).ffill().fillna(0)
print(rank)

     a    b
0  0.0  0.0
1  0.0  0.0
2  1.0  0.0
3  2.0  1.0
4  3.0  0.0
5  0.0  0.0

# Compute first and last non null value before NaN range
first = df.ffill()
last = df.bfill()

# Finally, compute final df
df = last - (last-first)/2**(rank)
print(df)

       a    b
0  1.000  1.0
1  2.000  2.0
2  2.500  5.0
3  2.750  5.0
4  2.875  5.0
5  3.000  3.0

上一个答案

您可以调用mask 将空值和负值替换为NaN,然后​​调用interpolate

不太确定为什么您希望将第二列中的 NaN 替换为 2.5 而不是 5...

>>> df.mask(df<=0).interpolate()
      a    b
0  1.00  1.0
1  2.00  2.0
2  2.25  5.0
3  2.50  5.0
4  2.75  5.0
5  3.00  3.0

【讨论】:

  • 这不会产生预期的输出,因为问题不要求插值。
  • 你是对的,但是由于它们的预期结果与 OP 所说的他们想要的不一致,我有点假设插值可以满足他们的需要
  • 我不明白你为什么坚持认为 5 和 5 的平均值是 2.5。只是不是。也许你需要在你的输出数据框中有这个 2.5 的值,但这不是平均值。 (5+5)/2 = 5
  • @YoannQuenachdeQuivillic 你是对的!谢谢!
  • @YoannQuenachdeQuivillic 我赞成你的回答。
【解决方案2】:

大量编辑的版本

定义一个函数以返回一个系列的更正版本

  • 建立一个面具:米
  • 通过 NaN 修改系列设置以替换要替换的值
  • 使用 0:1: 校正从掩码构建系列
  • 为每个要纠正的序列建立一系列排名:sequence_ranks
  • 使用 ffill 和 bfill 构建下限值和上限值系列:“lower_bound_values”和“upper_bound_values”
  • 使用 'lower_bound_values' 'upper_bound_values 计算结果
def correct_series_values(ser):
    m = (ser<=0) | ser.isna()
    ser[m] = np.nan
    tocorrect = m.astype('int')
    sequence_ranks = tocorrect.cumsum() - tocorrect.cumsum().where(tocorrect==0).ffill().fillna(0)
    lower_bound_values, upper_bound_values = ser.ffill(), ser.bfill()
    ser[m] = (lower_bound_values[m] - upper_bound_values[m]) / 2**(sequence_ranks[m]) + upper_bound_values[m]
    return ser

df['a'] = correct_series_values(df['a'])
df['c'] = correct_series_values(df['c'])

DF:

        a     c
0   1.000   1.0
1   2.000   2.0
2   2.500   5.0
3   2.750   5.0
4   2.875   5.0
5   3.000   3.0

【讨论】:

  • @Suhas_Pote 已更新。
  • @Suhas_Pote :正如 Yohann 所说,5 和 5 的平均值是 5。您可能需要进行其他更正,并且您应该在这种情况下修改函数。但我很想知道这与“a”列的更正值如何保持一致。
  • 你是对的!谢谢:)
  • 我赞成你的回答。
猜你喜欢
  • 2014-09-04
  • 2023-03-23
  • 2020-05-15
  • 2019-10-07
  • 1970-01-01
  • 2016-10-03
  • 2013-04-01
  • 2021-12-10
  • 1970-01-01
相关资源
最近更新 更多