2016-07-28 50 views
2

我有关于上 在熊猫DataFrame填充NaN值有条件地非NaN列的值的问题。为了说明:灌装NaN值在一个数据帧熊猫有条件地对非NaN的列的值

import numpy as np 
import pandas as pd 
print pd.__version__ 

0.18.1 

df = pd.DataFrame({'a': [1, 0, 0, 0, 1], 
        'b': [0, 1, 0, 0, 0], 
        'c': [0, 0, 1, 1, 0], 
        'x': [0.5, 0.2, 0, 0.2, 0], 
        'y': [0, 0, 0, 1, 0], 
        'z': [0.1, 0.1, 0.9, 0, 0.4]}) 

df.ix[[2,4], ['x','y','z']] = np.nan 

print df 

    a b c x y z 
0 1 0 0 0.5 0.0 0.1 
1 0 1 0 0.2 0.0 0.1 
2 0 0 1 NaN NaN NaN 
3 0 0 1 0.2 1.0 0.0 
4 1 0 0 NaN NaN NaN 

现在假设我有一些默认值,依赖于前三列:

default_c = pd.Series([0.5, 0.5, 0.5], index=['x', 'y', 'z']) 
default_a = pd.Series([0.2, 0.2, 0.2], index=['x', 'y', 'z']) 

换句话说,我想default_c粘贴在NaN值第2行,并在4排为此default_a贴,我想出了下面的有些不雅的解决方案:

nan_x = np.isnan(df['x']) 
is_c = df['c']==1 
nan_c = nan_x & is_c 

print nan_c 

0 False 
1 False 
2  True 
3 False 
4 False 
dtype: bool 

df.ix[nan_c, default_c.index] = default_c.values 

print df 

    a b c x y z 
0 1 0 0 0.5 0.0 0.1 
1 0 1 0 0.2 0.0 0.1 
2 0 0 1 0.5 0.5 0.5 
3 0 0 1 0.2 1.0 0.0 
4 1 0 0 NaN NaN NaN 

有没有更好的办法ŧ o使用fillna()函数执行此操作吗?

例如,下面是不行的,我猜是因为我填补了DataFrame切片:

df.loc[df['a']==1].fillna(default_a, inplace=True) 

print df 

    a b c x y z 
0 1 0 0 0.5 0.0 0.1 
1 0 1 0 0.2 0.0 0.1 
2 0 0 1 0.5 0.5 0.5 
3 0 0 1 0.2 1.0 0.0 
4 1 0 0 NaN NaN NaN 

但这长线做:

df.loc[df['a']==1] = df.loc[df['a']==1].fillna(default_a) 

print df 

    a b c x y z 
0 1 0 0 0.5 0.0 0.1 
1 0 1 0 0.2 0.0 0.1 
2 0 0 1 0.5 0.5 0.5 
3 0 0 1 0.2 1.0 0.0 
4 1 0 0 0.2 0.2 0.2 

不管怎么说,只是寻求如何使代码尽可能简单的建议。

回答

1

您可以将a, b, c列设置为多索引并使用熊猫combine_first

首先,您需要一个默认框架。在你的设置,可以这样:

df0 = pd.concat([default_a, default_c], axis=1).T 
df0.index = pd.Index([(1, 0, 0), (0, 0, 1)], names=list("abc")) 
df0 
Out[148]: 
     x y z 
a b c    
1 0 0 0.2 0.2 0.2 
0 0 1 0.5 0.5 0.5 

然后设置一个多指数DF1,应用combine_first,并重置索引:

df1 = df.set_index(['a', 'b', 'c']) 
>>> df1 
Out[151]: 
     x y z 
a b c    
1 0 0 0.5 0.0 0.1 
0 1 0 0.2 0.0 0.1 
    0 1 NaN NaN NaN 
    1 0.2 1.0 0.0 
1 0 0 NaN NaN NaN 

df1.combine_first(df0) 
Out[152]: 
     x y z 
a b c    
0 0 1 0.5 0.5 0.5 
    1 0.2 1.0 0.0 
    1 0 0.2 0.0 0.1 
1 0 0 0.5 0.0 0.1 
    0 0.2 0.2 0.2 

df1.combine_first(df0).reset_index() 
Out[154]: 
    a b c x y z 
0 0 0 1 0.5 0.5 0.5 
1 0 0 1 0.2 1.0 0.0 
2 0 1 0 0.2 0.0 0.1 
3 1 0 0 0.5 0.0 0.1 
4 1 0 0 0.2 0.2 0.2 

副作用是输出的不同排序顺序。为了保持顺序,我们可以使用原始索引(如果它是单调的和唯一的,否则使用额外的临时列代替):

df2 = df.reset_index().set_index(['a', 'b', 'c']) 
>>> df2 
Out[156]: 
     index x y z 
a b c      
1 0 0  0 0.5 0.0 0.1 
0 1 0  1 0.2 0.0 0.1 
    0 1  2 NaN NaN NaN 
    1  3 0.2 1.0 0.0 
1 0 0  4 NaN NaN NaN 

df2.combine_first(df0).reset_index().set_index('index').sort_index() 
Out[160]: 
     a b c x y z 
index       
0  1 0 0 0.5 0.0 0.1 
1  0 1 0 0.2 0.0 0.1 
2  0 0 1 0.5 0.5 0.5 
3  0 0 1 0.2 1.0 0.0 
4  1 0 0 0.2 0.2 0.2 
+0

不错!无需循环遍历解决方案中的列。 – hobgreenson

相关问题