bool 取反_Series取反不简单

Series取反·不简单

此篇介绍今天遇到的一个有意思的bug

与bug不期而遇

今天coding完毕,测试代码的时候,下面一段代码出现了错误。

amp_samples = value[value].index.tolist()not_amp_samples = value[~value].index.tolist()

value是一个值为TrueFalseSeries,我想从中分别获取值为TrueFalseindex列表。

代码很简单,pandas中使用~进行条件取反。于是,利用value[value]value[~value]即可进行筛选。

但是出错了。

IndexError                                Traceback (most recent call last)-38-e29c78a5ffe7> ----> 1 value[~value]IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices

index错误。而且很清楚的写明是value[~value]而不是value[value]错误。

复现

第一反应就是~条件取反是不是在Series中不能用。

进入ipython进行测试。

import pandas as pdseries = pd.Series({'R1':True,'R2':False,'R3':False,'R4':True})print(series[series])print(series[~series])

out:

R1    TrueR4    Truedtype: boolR2    FalseR3    Falsedtype: bool

是正常的。

那么第二反应就是,前期的处理导致value出现除了TrueFalse的其他值。取正时非bool值会自动转换,但是条件取反就会失败。

于是,在代码中加print获取value的值。

R1        TrueR2       FalseR3       FalseR4        Truedtype: object

看起来很正常啊。

思考

A FEW MINUTES LATER。

我开始觉得是服务器上的pandas和本地版本不同导致的。于是在服务器上写code,无法复现。

15 MINUTES LATER。

终于,我发现,有那么一丝丝不同。

不知道各位注意到没有,代码输出中的Value最后的dtypeobject,而我的测试代码中的dtypebool。我们知道,objectpandas中的通用类型,虽然它通常用来存储字符串,但也可以存储列表、元组等元素。

print(pd.Series({'R1':'sssimon yang'}))print(pd.Series({'R1':(1,2,3)}))print(pd.Series({'R1':[1,2,3]}))

out:

R1    sssimon yangdtype: objectR1    (1, 2, 3)dtype: objectR1    [1, 2, 3]dtype: object

虽然目前不知道objectbool会不会影响条件取反,但是为什么代码中的valueobject类型呢?

错误之前的代码是这样的。

df['count'] = np.sum(patient_cnv[samples_map.values()],axis=1) #samples_map.values()的结果类似['R1','R2','R3','R4']for index, value in df.iterrows():    value = value[list(samples_map.values())]

可以看出,之前是想算出所有正值的总count,然后遍历每一行。

用示例看一下加一个数值会不会影响类型。

series = pd.Series({'R1':True,'R2':False,'R3':False,'R4':True})print(series)series['count'] = series.sum()print(series)

out:

R1     TrueR2    FalseR3    FalseR4     Truedtype: boolR1       1R2       0R3       0R4       1count    2dtype: int64

啧,直接从bool变为了int。那还是用dataframe模拟吧。

samples = ['R1','R2','R3','R4']df = pd.DataFrame([[True,False,False,True]],columns=samples)print(df)print(df.iloc[0])df['count'] = df[samples].sum(axis=1)print(df)print(df.iloc[0])

out:

     R1     R2     R3    R40  True  False  False  TrueR1     TrueR2    FalseR3    FalseR4     TrueName: 0, dtype: bool     R1     R2     R3    R4  count0  True  False  False  True      2R1        TrueR2       FalseR3       FalseR4        Truecount        2Name: 0, dtype: object

确实是从bool变为了object,因为各列很有可能是不同类型的值,所以内部机制可能是在取行时倾向于使用object

那赶紧取反一下试试。

series = df.iloc[0]series = series[samples]print(series)print(series[series])print(series[~series])

out:

R1     TrueR2    FalseR3    FalseR4     TrueName: 0, dtype: objectR1    TrueR4    TrueName: 0, dtype: objectR2    FalseR3    FalseName: 0, dtype: object

咦,没有错误,不应该啊。

无限逼近

再看原来的代码,里面有个iterrows,复现的不够像?

for index, series in df.iterrows():    series = series[samples]    print(series)    print(series[series])    print(series[~series])

out:

R1     TrueR2    FalseR3    FalseR4     TrueName: 0, dtype: objectR1    TrueR4    TrueName: 0, dtype: object---------------------------------------------------------------------------IndexError                                Traceback (most recent call last)-96-ba90254b282a>       3     print(series)      4     print(series[series])----> 5     print(series[~series])

绝了,iterrowsiloc取出的行类型都是object,一个可以条件取反,一个不能?

知识盲区。

不过既然复现了,那就要看看这神奇的取反结果是什么。

index,series = list(df.iterrows())[0]series = series[samples]print(series)print(~series)

out:

R1     TrueR2    FalseR3    FalseR4     TrueName: 0, dtype: objectR1    -2R2    -1R3    -1R4    -2Name: 0, dtype: object

-2-1,那看来是以True1False0进行的按位取反。

再看iloc中的。

series = df.iloc[0]series = series[samples]print(series)print(~series)

out:

R1     TrueR2    FalseR3    FalseR4     TrueName: 0, dtype: objectR1    FalseR2     TrueR3     TrueR4    FalseName: 0, dtype: object

正常的条件取反。

分析

我们知道在raw python中存在按位取反~1输出-2,所以这种结果看起来是raw python与pandas~使用上的冲突,在iloc结果中还可以保持pandas中的条件取反,但是在iterrows()中,按位取反就被暴露出来了。

按照道理来讲这两个之前不应该有区别,所以我认为这是个pandas中的bug,看能不能提个tissue。

解决起来当然就很简单了,强制转为bool类型就可以了。

value = value.astype(bool)

我是 SSSimon Yang,关注我,用code解读世界

bool 取反_Series取反不简单_第1张图片

你可能感兴趣的:(bool,取反,bool取反,错误:,程序包r2不存在)