2015-05-26 2 views
3

Учитывая следующие панда dataframe:Написать определенный пользователь функцию fillna в панде dataframe заполнить np.nan различных значений с условиями

import pandas as pd 

change = [0.475, 0.625, 0.1, 0.2, -0.1, -0.75, 0.1, -0.1, 0.2, -0.2] 
position = [1.0, 1.0, nan, nan, nan, -1.0, nan, nan, nan, nan] 
date = ['20150101', '20150102', '20150103', '20150104', '20150105', '20150106', '20150107', '20150108', '20150109', '20150110'] 
pd.DataFrame({'date': date, 'position': position, 'change': change}) 

Выходы

 date  change  position  
    20150101  0.475   1 
    20150102  0.625   1 
    20150103  0.1   np.nan 
    20150104  0.2   np.nan 
    20150105  -0.1   np.nan 
    20150106  -0.75   -1 
    20150107  0.1   np.nan 
    20150108  -0.1   np.nan 
    20150109  0.2   np.nan 
    20150110  -0.2   np.nan 

Я хочу fillna со следующими правилами :

  1. Для строк, значение «позиции» которых равно np.nan, если значение «change» имеет значение sam e знака последнего ненулевого значения позиции (изменить * положение> 0, например, 0,1 * 1 и 0,2 * 1> 0), мы заполняем последнее ненулевое значение.

  2. Для строк, чье «положение» имеет значение np.nan, если значение «change» имеет тот же знак последнего ненулевого значения значения позиции (change * position < = 0, например -1 * 0,1) , мы заполняем 0.

  3. Как только один np.nan будет заполнен 0, следующий np.nan будет также заполнен 0.

Ниже приведены ожидаемые результаты от кадра выборки данных:

 date  change  position  
    20150101  0.475   1 
    20150102  0.625   1 
    20150103  0.1   1 
    20150104  0.2   1 
    20150105  -0.1   0 
    20150106  -0.75   -1 
    20150107  0.1   0 
    20150108  -0.1   0 
    20150109  0.2   0 
    20150110  -0.2   0 

EDIT:

Метод, который я разработал следующий:

while(any(np.isnan(x['position']))): 
    conditions = [(np.isnan(x['position'])) & (x['position'].shift(1) * x['change'] > 0), 
        (np.isnan(x['position'])) & (x['position'].shift(1) * x['change'] <= 0)] 
    choices = [x['position'].shift(1), 0] 
    x['position'] = np.select(conditions, choices, default=x['position']) 

, но, как вы может показаться, что это не очень удовлетворительно и очень медленно, если у вас есть 80 000 000 строк данных.

Любые предложения? Спасибо за помощь!

+0

Возможно, вам стоит описать, что вы попробовали? – Alexander

+0

просто добавил вещи, которые я пробовал, спасибо – user6396

+0

@ JohnE, только что отредактированный, как вы сказали, спасибо. Мое решение не работает на большом кадре данных, поэтому я все еще ищу помощь. – user6396

ответ

3

Я думаю, что ваш код довольно прочный, основная проблема заключается в том, что вы повторяете его больше раз, чем вам нужно. shift() возвращает только одну строку за раз, но если вы измените ее на fillna(method='ffill'), вы получите практически неограниченное количество смен, но только один раз, а не с несколькими итерациями (сколько итераций будет зависеть от ваших данных).

conditions = [ 
    (np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']>0), 
    (np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']<=0)] 

Но я верю, что вы можете пойти один шаг дальше и устранить while, добавив еще fillna в конце:

conditions = [ 
    (np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']>0), 
    (np.isnan(x['position'])) & (x['position'].fillna(method='ffill')*x['change']<=0)] 

choices=[x['position'].shift(1),0] 
x['position'] = np.select(conditions,choices,default=x['position']) 

x['position'] = x['position'].fillna(method='ffill') 

На ваших выборочных данных, то первое изменение составляет около 2 раза быстрее, чем код , а второй - около 4x. Я получаю те же ответы, что и вы, но, конечно, вы захотите проверить это на реальных данных.

+0

Большое вам спасибо за помощь! волшебство работает. – user6396

+0

Ха-ха, на самом деле не волшебство, просто сводящее к минимуму количество итераций. Ваш код был действительно неплохим, просто так можно сделать его немного лучше ... – JohnE