2016-11-15 32 views
1

如果列的子集中的所有值等于0或N(取决于列),我有几个数据集需要放弃观察值。例如:当所有的值都等于多个条件时,在Pandas中放置观察值

df = pd.DataFrame({'one':[0,0,1,2,0], 'two':[0,0,0,0,0], 'three':['N','Y','N','Y','N']}) 
drop_subset = ['one', 'three'] 

In [4]: df 
Out[4]: 
    one three two 
0 0  N 0 
1 0  Y 0 
2 1  N 0 
3 2  Y 0 
4 0  N 0 

我需要看的只是列onethree,然后删除行0和4只。如果它只是一个单一的值,而不是两个或更多的,我会用这样的:

df[~(df[drop_subset] == 0).all(axis=1)] 

而且它会正常工作。但是,当我试图扩大它:

df[~(df[drop_subset] == 0 or df[drop_subset] == 'N').all(axis=1)] 

我得到了可怕的:

ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(),a.item(), a.any() or a.all().

我原本以为对待每一个的使用anyall运营商内部条件......除了逻辑不会这样工作。我不需要知道任何或所有的值是否为0,或者分开确定是否有任何或所有的值都是N.我需要知道的所有的值是N还是0.也就是说,我可以这样做:

In [71]: (df[drop_subset] == 0) 
Out[71]: 
    one three 
0 True False 
1 True False 
2 False False 
3 False False 
4 True False 

不为“N”的值也同时测试。虽然在这个小数据帧上我可以单独测试列one 0和列three'N',但实际上我的drop_subset包括几乎100个列,这三列在三个不同的数据集中是不同的,并且没有手动编码所有的列不知道哪些列会有0,哪些会有'N'。 我所知道的一切是,如果观察有所有 0或'N'跨该子集,那么我需要删除它。

我最后的手段是使用apply lambda,但由于数据的大小会很痛苦。另外,我觉得必须有一种矢量化的方式来表达Panadas中的这种逻辑,这就是我正在寻找的。

回答

3

IIUC您可以使用DataFrame.isin()方法:

In [68]: df[df[drop_subset].isin([0,'N']).all(1)] 
Out[68]: 
    one three two 
0 0  N 0 
4 0  N 0 

In [69]: df[~df[drop_subset].isin([0,'N']).all(1)] 
Out[69]: 
    one three two 
1 0  Y 0 
2 1  N 0 
3 2  Y 0 
+0

就是这样,谢谢。虽然我不得不说这是令人失望的,但这不能用布尔运算符来完成。 – Jeff

+0

@JeffL。,可能有一些NumPy解决方案用于这种比较... – MaxU

+0

那么,你对'isin'的建议是非常干净和快速的,所以没有真正的需要。它看起来像*应该*在Pandas中工作,这并不是真正的问题。 – Jeff

1

我觉得最大钉在他的回答,isin自然是你应该使用什么。

事实上,这是你必须使用,因为df[drop_subset] == 'N'不会不管怎么说工作,你会得到什么:

TypeError: Could not compare ['N'] with block values 

你需要ISIN()这个工作。

我特别想指出的是,你得到的错误“[据帧/系列]的真值不明确”来自于事实,你应该总是使用&代替and,并|而不是or

二元运算符&|将返回一个元素明智的比较,因此将返回一个数组。 andor尝试将其转换为单个布尔值进行比较,该比较不存在。

更多在这里阅读:Logic operator for boolean indexing in Pandas

+0

是的,我实际上首先使用了管道,但遇到了块值错误。但显然这是一个无关的问题。 – Jeff

相关问题