用上一个有效值的百分比填充nan-s

时间:2019-05-06 09:22:53

标签: python pandas

我有一个数据框,其中的列包含NaN值。我想用值填充这些。我想拥有的方法“ ffill”的Fillna()几乎是我想要的东西,但不完全是。我想用最后一个有效值的120%替换我的NaN。因此,如果NaN之前的最后一个有效值为100.0,那么我希望NaN的位置为120.0。

我知道我可以迭代df,但这将需要很多时间。 (我的df目前大约有100.000行,并将进一步增加)

示例: df是我的初始数据框:

df = pd.DataFrame([[np.nan, 2, np.nan, 0], [3, 4, np.nan, 1], [np.nan, np.nan, np.nan, 5], [np.nan, 3, np.nan, 4], [5, 4, 2, np.nan], [np.nan, 3, np.nan, 4]], columns=list('ABCD'))

>>> df
    A    B    C    D
0  NaN  2.0  NaN  0.0
1  3.0  4.0  NaN  1.0
2  NaN  NaN  NaN  5.0
3  NaN  3.0  NaN  4.0
4  5.0  4.0  2.0  NaN
5  NaN  3.0  NaN  4.0

这就是我想要得到的:

>>> df
    A    B    C    D
0  NaN  2.0  NaN  0.0
1  3.0  4.0  NaN  1.0
2  3.6  NaN  NaN  5.0
3  3.6  3.0  NaN  4.0
4  5.0  4.0  2.0  NaN
5  6.0  3.0  NaN  4.0

因此列“ A”在行num中有两个替换。 2和3,现在的数值均为3.6(3 * 1.2),而不是NaN,加上第5行的更改,其中Nan被替换为6(5 * 1.2) 我一开始并不关心NaN,它们可以留下。我只想在“ A”列中进行更改。

1 个答案:

答案 0 :(得分:0)

我建议您使用部分列,以检查它是否是ffill之前的NaN值

如下:

df['partially_filled_A'] = df['A'].fillna(method='ffill')
df['isNan'] = df['A'].isnull()

df['A_filled'] = np.where((df['isNan']) & (df['partially_filled_A'].isnull() == False), df['partially_filled_A']*1.2, df['A'])

df

我与iteritems作了一些比较,结果如下:

df = pd.concat([df for _ in range(500_000)]) # let's make a df with 3_000_000 rows for the benchmark

使用迭代项

%% time
l = []
last_value = None
for item, frame in df['A'].iteritems():
    if last_value is None:
        if pd.notnull(frame):
            last_value = frame * 1.2
            l.append(frame)
        else:
            l.append(np.nan)
    else:
        if pd.notnull(frame):
            l.append(frame)
            last_value = frame * 1.2
        else:
            l.append(last_value)
df['ans'] = l
# 2.5 seconds

使用np.where

%%time
df['partially_filled_A'] = df['A'].fillna(method='ffill')
df['isNan'] = df['A'].isnull()

df['A_filled'] = np.where((df['isNan']) & (df['partially_filled_A'].isnull() == False), df['partially_filled_A']*1.2, df['A'])
#100 ms

如本快速基准测试所示,我强烈建议您使用np.where