2016-08-24 36 views
3

我有一个在各个地方缺失值的数组。在熊猫/ Python中连续插入多个nan?

import numpy as np 
import pandas as pd 
x = np.arange(1,10).astype(float) 
x[[0,1,6]] = np.nan 
df = pd.Series(x) 
print(df) 

0 NaN 
1 NaN 
2 3.0 
3 4.0 
4 5.0 
5 6.0 
6 NaN 
7 8.0 
8 9.0 
dtype: float64 

对于每个NaN,我想利用价值出发了,由两个分的它。然后传播完成,为下一个连续NaN,所以我将结束:

0 0.75 
1 1.5 
2 3.0 
3 4.0 
4 5.0 
5 6.0 
6 4.0 
7 8.0 
8 9.0 
dtype: float64 

我试过df.interpolate(),但似乎不连续的NaN的工作。

+0

即使'interpolate()'确实有效,它也不会做你所需要的。顺便说一下,你的“插值”规则看起来很奇怪。你确定这是你想要做到的吗? –

+0

@ Ev.Kounis我不完全确定这是我想要的方法,但现在我只是复制别人对他们的数据所做的一切。然后我会找出一个更好的方法。实际上,我应该对数据进行曲线拟合,以预测缺失值。 – BobbyJohnsonOG

+1

通常做的是假设缺少的段是直线,并且基于'NaN'之前和之后最接近的可用点计算出一个值。这就是所谓的线性插值(请参阅https://en.wikipedia.org/wiki/Linear_interpolation) –

回答

3

另一种解决方案与fillna与方法ffill,它所相同ffill()功能:

#back order of Series 
b = df[::-1].isnull() 
#find all consecutives NaN, count them, divide by 2 and replace 0 to 1 
a = (b.cumsum() - b.cumsum().where(~b).ffill()).mul(2).replace({0:1}) 

print(a) 
8 1 
7 1 
6 2 
5 1 
4 1 
3 1 
2 1 
1 2 
0 4 
dtype: int32 

print(df.bfill().div(a)) 
0 0.75 
1 1.50 
2 3.00 
3 4.00 
4 5.00 
5 6.00 
6 4.00 
7 8.00 
8 9.00 
dtype: float64 

计时len(df)=9k):

In [315]: %timeit (mat(df)) 
100 loops, best of 3: 11.3 ms per loop 

In [316]: %timeit (jez(df1)) 
100 loops, best of 3: 2.52 ms per loop 

代码定时

import numpy as np 
import pandas as pd 
x = np.arange(1,10).astype(float) 
x[[0,1,6]] = np.nan 
df = pd.Series(x) 
print(df) 
df = pd.concat([df]*1000).reset_index(drop=True) 
df1 = df.copy() 

def jez(df): 
    b = df[::-1].isnull() 
    a = (b.cumsum() - b.cumsum().where(~b).ffill()).mul(2).replace({0:1}) 
    return (df.bfill().div(a)) 

def mat(df): 
    prev = 0 
    new_list = [] 
    for i in df.values[::-1]: 
     if np.isnan(i): 
      new_list.append(prev/2.)  
      prev = prev/2. 
     else: 
      new_list.append(i) 
      prev = i 
    return pd.Series(new_list[::-1]) 

print (mat(df)) 
print (jez(df1)) 
+0

我喜欢这种工作方式!你有理由拥有'mul(2)'和'div(a)'?不想分数? – Mathias711

+0

和*和/一样,取决于编码器,选择什么;) – jezrael

+0

@ Mathias711 - 我忘了 - 谢谢。 – jezrael

2

你可以做这样的事情:

import numpy as np 
import pandas as pd 
x = np.arange(1,10).astype(float) 
x[[0,1,6]] = np.nan 
df = pd.Series(x) 

prev = 0 
new_list = [] 
for i in df.values[::-1]: 
    if np.isnan(i): 
     new_list.append(prev/2.)  
     prev = prev/2. 
    else: 
     new_list.append(i) 
     prev = i 
df = pd.Series(new_list[::-1]) 

它遍历的DF值,在反向。它跟踪以前的值。如果它不是NaN,它会添加实际值,否则为前一个值的一半。

这可能不是最复杂的Pandas解决方案,但您可以很容易地改变行为。