2017-12-26 1 views
3

다음과 같은 시계열 데이터 프레임이 있습니다. 누락 된 값을 이전 값으로 채우고 싶습니다. 그러나 나는 단지 first_valid_index와 last_valid 인덱스 사이의 누락 된 값을 채우기를 원할 것입니다. 그래서 필자가 채우기를 원하는 열은 각 열마다 다를 것이다. 내가 어떻게 할 수 있니?팬더의 특정 열 2 개 사이의 널 (null)을 제거하십시오.

따라서이 데이터 프레임이 주어집니다.

import numpy as np 
import pandas as pd 
df = pd.DataFrame([[1, 2 ,3,np.nan,5], [1, 3 , np.nan , 4 , np.nan], [4, np.nan , 7 , np.nan,np.nan]], columns=[2007,2008,2009,2010,2011]) 

입력 dataframe :

2007 2008 2009 2010 2011 
    1  2  3  NaN  5 
    1  3  NaN 4  NaN 
    4  Nan  7  NaN  NaN  

출력 dataframe는 :

2007 2008 2009 2010 2011 
1  2  3  3  5 
1  3  3  4  NaN 
4  4  7  NaN NaN 

나는 first_valid_index 및 last_valid_index 새로운 열을 만든 다음 .apply()를 사용하여 생각하지만, 내가 어떻게 할 수 행마다 다른 열을 채우시겠습니까?

def fillMissing(x): 
    first_valid = int(x["first_valid"]) 
    last_valid = int(x["last_valid"]) 
    for i in range(first_valid,last_valid + 1): 
     missing.append(i) 
    #What should i do here since the following is not valid 
    #x[missing] = x[missing].fillna(method='ffill', axis=1) 


df.apply(fillMissing , axis=1) 
+0

예제의 각 행마다 다른 열이 표시되지 않습니다. –

+0

@GarbageCollector 감사합니다. 나는 그 예를 편집했다. 그래서 내가 어떻게 첫 번째 행에 2007과 2011 사이에 fillna 싶어요. 하지만 나는 3 행에서 2007 년과 2009 년 사이에 만 칠하고 싶습니다. –

답변

5

당신은 iloc하여이 작업을 수행 할 수 있지만 NumPy와 함께이 작업을 수행하는 것을 선호합니다. 본질적으로 채우기 값을 전달하려면 ffill을 사용하고 NaN 끝까지 마스크합니다.

v = df.values 

mask = np.logical_and.accumulate(
    np.isnan(v)[:, ::-1], axis=1)[:, ::-1] 

df.ffill(axis=1).mask(mask) 

    2007 2008 2009 2010 2011 
0 1.0 2.0 3.0 3.0 5.0 
1 1.0 3.0 3.0 4.0 NaN 
2 4.0 4.0 7.0 NaN NaN 
1

여기 this post에서 영감을, 두 개의 완전히 NumPy와 기반 것들 -

def app1(df): 
    # Same as in the linked post 
    arr = df.values 
    m,n = arr.shape 
    r = np.arange(n) 
    mask = np.isnan(arr) 
    idx = np.where(~mask,r,0) 
    idx = np.maximum.accumulate(idx,axis=1) 
    out = arr[np.arange(m)[:,None], idx] 

    # Additional part to keep the trailing NaN islands and output a dataframe 
    out[(n - mask[:,::-1].argmin(1))[:,None] <= r] = np.nan 
    return pd.DataFrame(out, columns=df.columns) 

def app2(df): 
    arr = df.values 
    m,n = arr.shape 

    r = np.arange(m) 
    mask = np.isnan(arr) 
    idx = np.where(~mask,np.arange(n),0) 

    put_idx = n - mask[:,::-1].argmin(1) 
    v = put_idx < n 
    rv = r[v] 
    idx[rv,put_idx[v]] = idx[rv,(put_idx-1)[v]]+1 
    idx = np.maximum.accumulate(idx,axis=1) 
    out = arr[r[:,None], idx] 
    return pd.DataFrame(out, columns=df.columns) 

샘플 실행 -

- 채워 더 큰 df 50%와 NaN을에

In [246]: df 
Out[246]: 
    2007 2008 2009 2010 2011 
0  1 2.0 3.0 NaN 5.0 
1  1 3.0 NaN 4.0 NaN 
2  4 NaN 7.0 NaN NaN 

In [247]: app1(df) 
Out[247]: 
    2007 2008 2009 2010 2011 
0 1.0 2.0 3.0 3.0 5.0 
1 1.0 3.0 3.0 4.0 NaN 
2 4.0 4.0 7.0 NaN NaN 

In [248]: app2(df) 
Out[248]: 
    2007 2008 2009 2010 2011 
0 1.0 2.0 3.0 3.0 5.0 
1 1.0 3.0 3.0 4.0 NaN 
2 4.0 4.0 7.0 NaN NaN 

런타임 테스트

In [249]: df = pd.DataFrame(np.random.randint(1,9,(5000,5000)).astype(float)) 

In [250]: idx = np.random.choice(df.size, df.size//2, replace=0) 

In [251]: df.values.ravel()[idx] = np.nan 

# @piRSquared's soln 
In [252]: %%timeit 
    ...: v = df.values 
    ...: mask = np.logical_and.accumulate(
    ...:  np.isnan(v)[:, ::-1], axis=1)[:, ::-1] 
    ...: df.ffill(axis=1).mask(mask) 
1 loop, best of 3: 473 ms per loop 

In [253]: %timeit app1(df) 
1 loop, best of 3: 353 ms per loop 

In [254]: %timeit app2(df) 
1 loop, best of 3: 330 ms per loop 
관련 문제