应用程序的意外行为np.isin公司()在数据帧上

2024-04-20 09:14:10 发布

您现在位置:Python中文网/ 问答频道 /正文

在工作on an answer to another question时,我偶然发现了一个意想不到的行为:

考虑以下数据帧:

df = pd.DataFrame({
    'A':list('AAcdef'),
    'B':[4,5,4,5,5,4],
    'E':[5,3,6,9,2,4],
    'F':list('BaaBbA')
})
print(df)
   A  B  E  F
0  A  4  5  B  #<— row contains 'A' and 5
1  A  5  3  a  #<— row contains 'A' and 5
2  c  4  6  a
3  d  5  9  B
4  e  5  2  b
5  f  4  4  A

如果我们试图找到包含['A', 5]的所有列,我们可以使用jezrael's answer

cond = [['A'],[5]]
print( np.logical_and.reduce([df.isin(x).any(1) for x in cond]) )

它(正确地)产生:[ True True False False False False]

如果我们使用:

cond = [['A'],[5]]
print( df.apply(lambda x: np.isin([cond],[x]).all(),axis=1) )

这将产生:

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

仔细检查第二次尝试发现:

  • np.isin(['A',5],df.loc[0])“错误地”产生array([ True, False]),可能是由于numpy推断出数据类型<U1,因此5!='5'
  • np.isin(['A',5],['A',4,5,'B'])“正确地”产生array([ True, True]),这意味着我们可以(并且应该)在上述.apply()方法中使用df.loc[0].values.tolist()

问题,简化:

为什么我在一种情况下需要指定x.values.tolist(),而在另一种情况下可以直接使用x?你知道吗

print( np.logical_and.reduce([df.isin(x).any(1) for x in cond]) )
print( df.apply(lambda x: np.isin([cond],x.values.tolist()).all(),axis=1 ) )

编辑:

更糟糕的是,如果我们搜索[4,5]

cond = [[4],[5]]
## this returns False for row 0
print( df.apply(lambda x: np.isin([cond],x.values.tolist() ).all() ,axis=1) )
## this returns True for row 0
print( df.apply(lambda x: np.isin([cond],x.values ).all() ,axis=1) )

Tags: andlambdafalsetruedffornpall
2条回答

我认为在DataFrame中是用整数来混合数值的,所以如果loop by rows用混合类型来获得Series,那么numpy强制到strings。你知道吗

可能的解决方案是转换为数组,然后转换为cond中的string值:

cond = [[4],[5]]

print(df.apply(lambda x: np.isin(np.array(cond).astype(str), x.values.tolist()).all(),axis=1))
0     True
1    False
2    False
3    False
4    False
5    False
dtype: bool

不幸的是,对于一般的解决方案(如果可能的话,只有数字列)需要同时转换-condSeries

f = lambda x: np.isin(np.array(cond).astype(str), x.astype(str).tolist()).all()
print (df.apply(f, axis=1))

或所有数据:

f = lambda x: np.isin(np.array(cond).astype(str), x.tolist()).all()
print (df.astype(str).apply(f, axis=1))

如果在纯python中使用set,那么它工作起来很好:

print(df.apply(lambda x: set([4,5]).issubset(x),axis=1) )
0     True
1    False
2    False
3    False
4    False
5    False
dtype: bool

print(df.apply(lambda x: set(['A',5]).issubset(x),axis=1) )
0     True
1     True
2    False
3    False
4    False
5    False
dtype: bool

因为

  1. ^{}适用于pd.Series^{}不适用。你知道吗
  2. ^{}返回pd.Series。你知道吗
  3. 要将pd.Series转换为array-like,您的x.values.tolist()应该可以工作。你知道吗

相关问题 更多 >