Фрейм данных Pandas для прямого заполнения по горизонтали (вдоль строк) без прямого заполнения последнего значения в каждой строке - PullRequest
4 голосов
/ 13 июня 2019

У меня есть фрейм данных Pandas, который я хочу перенаправить заполнением ГОРИЗОНТАЛЬНО, но я не хочу пересылать заполнение после последней записи в каждой строке. Это данные о ценах временных рядов для продуктов, некоторые из которых были прекращены, поэтому я не хочу, чтобы последнее записанное значение было заполнено до текущего.

FWDFILL.apply(lambda series: series.iloc[:,series.last_valid_index()].ffill(axis=1))

^ Код, который я включил, делает то, что я хочу, но он делает это ВЕРТИКАЛЬНО. Это может помочь людям в качестве отправной точки.

>>> print(FWDFILL)

1      1     NaN     NaN     2     NaN  
2     NaN     1      NaN     5     NaN  
3     NaN     3       1     NaN    NaN  
4     NaN    NaN     NaN    NaN    NaN  
5     NaN     5      NaN    NaN     1  

Желаемый вывод:

1      1      1      1     2     NaN  
2     NaN     1      1     5     NaN  
3     NaN     3      1    NaN    NaN  
4     NaN    NaN    NaN   NaN    NaN  
5     NaN     5      5     5      1

Ответы [ 5 ]

3 голосов
/ 13 июня 2019

Вы можете использовать numpy, чтобы найти последние действительные индексы и замаскировать свой ffill. Это позволяет использовать векторизованную ffill и затем векторизованную маску.


u = df.values
m = (~np.isnan(u)).cumsum(1).argmax(1)
df.ffill(1).mask(np.arange(df.shape[0]) > m[:, None])

     0    1    2    3    4
0  1.0  1.0  1.0  2.0  NaN
1  NaN  1.0  1.0  5.0  NaN
2  NaN  3.0  1.0  NaN  NaN
3  NaN  NaN  NaN  NaN  NaN
4  NaN  5.0  5.0  5.0  1.0

Информация

>>> np.arange(df.shape[0]) > m[:, None]
array([[False, False, False, False,  True],
       [False, False, False, False,  True],
       [False, False, False,  True,  True],
       [False,  True,  True,  True,  True],
       [False, False, False, False, False]])
3 голосов
/ 13 июня 2019

Использование bfill и ffill

s1=df.ffill(1)
s2=df.bfill(1)
df=df.mask(s1.notnull()&s2.notnull(),s1)
df
Out[222]: 
     1    2    3    4    5
1  1.0  1.0  1.0  2.0  NaN
2  NaN  1.0  1.0  5.0  NaN
3  NaN  3.0  1.0  NaN  NaN
4  NaN  NaN  NaN  NaN  NaN
5  NaN  5.0  5.0  5.0  1.0

Или просто с помощью interpolate

df.mask(df.interpolate(axis=1,limit_area='inside').notnull(),df.ffill(1))
Out[226]: 
     1    2    3    4    5
1  1.0  1.0  1.0  2.0  NaN
2  NaN  1.0  1.0  5.0  NaN
3  NaN  3.0  1.0  NaN  NaN
4  NaN  NaN  NaN  NaN  NaN
5  NaN  5.0  5.0  5.0  1.0
3 голосов
/ 13 июня 2019

IIUC, вам нужно apply с axis=1, поэтому вы применяете к строкам данных вместо столбцов данных.

df.apply(lambda x: x[:x.last_valid_index()].ffill(), axis=1)

Выход:

     1    2    3    4    5
0                         
1  1.0  1.0  1.0  2.0  NaN
2  NaN  1.0  1.0  5.0  NaN
3  NaN  3.0  1.0  NaN  NaN
4  NaN  NaN  NaN  NaN  NaN
5  NaN  5.0  5.0  5.0  1.0
1 голос
/ 13 июня 2019

Небольшая модификация - Most efficient way to forward-fill NaN values in numpy array решение , решает его здесь -

def ffillrows_stoplast(arr):
    # Identical to earlier solution of forward-filling
    mask = np.isnan(arr)
    idx = np.where(~mask,np.arange(mask.shape[1]),0)
    idx_acc = np.maximum.accumulate(idx,axis=1)
    out = arr[np.arange(idx.shape[0])[:,None], idx_acc]

    # Perform flipped index accumulation to get trailing NaNs mask and
    # accordingly assign NaNs there
    out[np.maximum.accumulate(idx[:,::-1],axis=1)[:,::-1]==0] = np.nan
    return out

Пример запуска -

In [121]: df
Out[121]: 
     A    B    C    D    E
1  1.0  NaN  NaN  2.0  NaN
2  NaN  1.0  NaN  5.0  NaN
3  NaN  3.0  1.0  NaN  NaN
4  NaN  NaN  NaN  NaN  NaN
5  NaN  5.0  NaN  NaN  1.0

In [122]: out = ffillrows_stoplast(df.to_numpy())

In [123]: pd.DataFrame(out,columns=df.columns,index=df.index)
Out[123]: 
     A    B    C    D    E
1  1.0  1.0  1.0  2.0  NaN
2  NaN  1.0  1.0  5.0  NaN
3  NaN  3.0  1.0  NaN  NaN
4  NaN  NaN  NaN  NaN  NaN
5  NaN  5.0  5.0  5.0  1.0
0 голосов
/ 14 июня 2019

Я думаю об использовании where на ffill, чтобы вернуться к NaN, которые были проигнорированы на bfill

df.ffill(1).where(df.bfill(1).notna())    

Out[1623]:
     a    b    c    d    e
1  1.0  1.0  1.0  2.0  NaN
2  NaN  1.0  1.0  5.0  NaN
3  NaN  3.0  1.0  NaN  NaN
4  NaN  NaN  NaN  NaN  NaN
5  NaN  5.0  5.0  5.0  1.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...