Pandas使用groupby结果修改列,同时忽略某些值

时间:2016-04-08 21:39:02

标签: python pandas

我正在尝试使用Pandas使用groupby操作的结果修改庞大的数据集。 我需要的是找到数据组的最小值,同时忽略零,但如果它是组中的唯一值,则返回相同的零。

考虑这个虚拟数据:

>>> a=pd.DataFrame(dict(item_id=[1,1,1,2,2,2], pos_id=[3,7,7,7,7,7], target='T1 T2 T3 T1 T2 T3'.split(), val=[8,0,0,41,0,55]))
>>> a
   item_id  pos_id target  val
0        1       3     T1    8
1        1       7     T2    0
2        1       7     T3    0
3        2       7     T1   41
4        2       7     T2    0
5        2       7     T3   55

对于pos_id == 7和target =='T2'中的每个item_id,我想获得整个组中最小的非零val(忽略目标),并用它代替它!

所以,我想最终得到这个:

   item_id  pos_id target  val
0        1       3     T1    8  <-- this row has the wrong pos_id and is ignored
1        1       7     T2    0  <-- this one maintains zero (all group has zeros)
2        1       7     T3    0
3        2       7     T1   41
4        2       7     T2   41  <-- this one gets the smallest of item_id group
5        2       7     T3   55

我试过这个:

>>> a.ix[(a.pos_id == 7) & (a.target == 'T2'), 'val'] = a.ix[a.pos_id == 7].groupby('item_id').val.min().values

但它不起作用,因为零不被忽略。而且我不能简单地忽略它们,因为作业两侧的系列将有不同的大小!

>>> a.ix[(a.pos_id == 7) & (a.target == 'T2'), 'val'].size, a.ix[(a.pos_id == 7) & (a.val != 0)].groupby('item_id').val.min().values.size
(2, 1)

我也尝试在这些零中加入一个高值,所以第一个几乎会成功:

>>> a.ix[(a.pos_id == 7) & (a.val == 0), 'val'] = 9999
>>> a
   item_id  pos_id target   val
0        1       3     T1     8
1        1       7     T2  9999
2        1       7     T3  9999
3        2       7     T1    41
4        2       7     T2  9999
5        2       7     T3    55

可是:

>>> a.ix[(a.pos_id == 7) & (a.target == 'T2'), 'val'] = a.ix[a.pos_id == 7].groupby('item_id').val.min().values
>>> a
   item_id  pos_id target   val
0        1       3     T1     8
1        1       7     T2  9999  <-- this one should maintain zero...
2        1       7     T3  9999
3        2       7     T1    41
4        2       7     T2    41  <-- this one works!
5        2       7     T3    55

但是现在我必须将不应修改的值归还为零... 哦,它必须是更好的方式!

请问,如何在一个更简单的步骤中使用groupby忽略某些值来设置这个值?并且还请考虑性能很重要,因为数据集有几千兆字节......

谢谢!

1 个答案:

答案 0 :(得分:1)

我认为您可以使用条件numpy.where来检查all值是0,然后输出是0否则min没有0使用transform代替apply

的值
a=pd.DataFrame(dict(item_id=[1,1,1,2,2,2], 
                    pos_id=[3,7,7,7,7,7], 
                    target='T1 T2 T3 T1 T2 T3'.split(), 
                    val=[8,0,0,41,0,55]))
print a
   item_id  pos_id target  val
0        1       3     T1    8
1        1       7     T2    0
2        1       7     T3    0
3        2       7     T1   41
4        2       7     T2    0
5        2       7     T3   55

a.ix[(a.pos_id == 7) & (a.target == 'T2'), 'val'] = 
a.ix[a.pos_id == 7].groupby('item_id').val.transform(lambda x: np.where((x == 0).all(), 
                                                                        0, 
                                                                        x[x!=0].min()))
print a
   item_id  pos_id target  val
0        1       3     T1    8
1        1       7     T2    0
2        1       7     T3    0
3        2       7     T1   41
4        2       7     T2   41
5        2       7     T3   55