2016-03-29 85 views
3

我有一个非常大的熊猫数据集,其中的数据看起来像如何加快替换Pandas中每个groupby组的缺失值?

df = pd.DataFrame({'group1' : ['A', 'A', 'A', 'A', 
         'B', 'B', 'B', 'B'], 
        'group2' : ['C', 'C', 'C', 'D', 
         'E', 'E', 'F', 'F'], 
        'B' : ['one', np.NaN, np.NaN, np.NaN, 
         np.NaN, 'two', np.NaN, np.NaN], 
        'C' : [np.NaN, 1, np.NaN, np.NaN, 
         np.NaN, np.NaN, np.NaN, 4]})  




df 
Out[64]: 
    B C group1 group2 
0 one NaN  A  C 
1 NaN 1  A  C 
2 NaN NaN  A  C 
3 NaN NaN  A  D 
4 NaN NaN  B  E 
5 two NaN  B  E 
6 NaN NaN  B  F 
7 NaN 4  B  F 

在这里,您可以看到,为group1group2每一个独特的组合,列BC包含最多一个非缺失变量。

在每个groupby(['group1','group2'])中,如果该值存在,则使用该唯一的非缺失值(在该组中)替换所有缺少的值。

为此,我使用groupby之后可用的first函数,它传播为B或C的第一非缺失值的每个组中的缺失值的其余部分在该组中:

df[['B','C']]=df.groupby(['group1','group2']).transform('first')  



df 
Out[62]: 
    B C group1 group2 
0 one 1  A  C 
1 one 1  A  C 
2 one 1  A  C 
3 NaN NaN  A  D 
4 two NaN  B  E 
5 two NaN  B  E 
6 NaN 4  B  F 
7 NaN 4  B  F 

不幸的是,这是在我非常大的数据集上痛苦地缓慢。你看到有什么方法可以提高速度吗?我在考虑fillna,但似乎我需要申请两次(ffillbfill)...有什么想法?

UPDATE下面ajcr提出的非常有效的解决方案是否适用于由几列定义的组?在这种情况下,map不起作用。也许merge

回答

3

在我的机器,它可以快了近100倍使用groupby然后map

g = df.groupby('group', sort=False).first() 

df['B'] = df['group'].map(g['B']) 
df['C'] = df['group'].map(g['C']) 

这是一个测试数据帧与1000组和10000行:

df = pd.DataFrame({'group': np.repeat(np.arange(1000), 10), 
        'B': np.nan, 
        'C': np.nan}) 

df.ix[4::10, 'B':'C'] = 5 # every 4th row of a group is non-null 

而且计时:

%%timeit 

df2 = df.copy() 

g = df2.groupby('group', sort=False).first() 

df2['B'] = df2['group'].map(g['B']) 
df2['C'] = df2['group'].map(g['C']) 

返回100 loops, best of 3: 2.29 ms per loop

transform方法较慢,近100倍:

%%timeit 

df3 = df.copy() 

df3[['B','C']] = df3.groupby('group').transform('first') 

这将返回1 loops, best of 3: 205 ms per loop


关于您使用以下

df['B'] = df.groupby(['group1','group2']).B.transform('first') 
df['C'] = df.groupby(['group1','group2']).C.transform('first') 

的更新,在注释中使用多个组,@杰夫的建议涉及的问题比一气呵成转化两个栏快约50倍。这是因为目前transform对于Series来说性能要高得多,尽管有一个newly-created issue也可以提高DataFrame上的操作速度。

+0

。让我试试这个解决方案 –

+0

你能解释一下在这里做的“map”吗? –

+1

我玩的是类似'a [['B','C']] = a.apply(lambda x:g.loc [x.group,['B','C']],axis = 1)',但速度要慢得多。因此,为您的解决方案+1投票 – MaxU

1

让我们加快速度一点点:

In [130]: a = df.copy() 

In [131]: %timeit a['B'],a['C'] = a.B.fillna(method='ffill'), a.C.fillna(method='bfill') 
1000 loops, best of 3: 538 µs per loop 

In [132]: a = df.copy() 

In [133]: %timeit a[['B','C']]=a.groupby('A').transform('first') 
100 loops, best of 3: 3 ms per loop 
+0

非常感谢maxU,但我们不知道每组中的非缺失值究竟在哪里。换句话说,在B上做一个'ffill'可能行不通。这就是为什么我在每列提到双重“ffill”和“bfill”... –

+1

@诺比,你能否相应地更新你的样本DF? – MaxU

+0

确定一秒 –

1

,如果你去这个怎么样不同的,并没有尝试,并填写,而是重建?

unique_df = df.drop_duplicates() 

bVal = unique_df.drop(['B'],axis = 1).dropna().set_index(['A']) 
cVal = unique_df.drop(['C'],axis = 1).dropna().set_index(['A']) 

colVals = pd.merge(bVal,cVal, how = 'outer',left_index = True, right_index = True) 
output = pd.merge(df[['A']],colVals, how = 'left',left_on = 'A',right_index = True) 

收缩的DF下降到独特的部分,发现在较小的数据帧中的唯一行,然后合并回到重建更大的框架 - 更快?