如何像SQL中的 "in "和 "not in "一样,使用 "in "和 "not in "过滤Pandas数据框

python pandas dataframe sql-function


如何实现SQL的 INNOT IN 的等效项?

我有一个列表,里面有要求的值。情况是这样的。

df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = ['UK','China']

# pseudo-code:
df[df['countries'] not in countries]

我目前的做法如下。

df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = pd.DataFrame({'countries':['UK','China'], 'matched':True})

# IN
df.merge(countries,how='inner',on='countries')

# NOT IN
not_in = df.merge(countries,how='left',on='countries')
not_in = not_in[pd.isnull(not_in['matched'])]

但是,这似乎是个可怕的烂摊子。有人能改进一下吗?




Answer 1 DSM


您可以使用 pd.Series.isin

对于“ IN”,请使用: something.isin(somewhere)

或对于“ NOT IN”: ~something.isin(somewhere)

作为一个工作的例子。

>>> df
  countries
0        US
1        UK
2   Germany
3     China
>>> countries
['UK', 'China']
>>> df.countries.isin(countries)
0    False
1     True
2    False
3     True
Name: countries, dtype: bool
>>> df[df.countries.isin(countries)]
  countries
1        UK
3     China
>>> df[~df.countries.isin(countries)]
  countries
0        US
2   Germany



Answer 2 MaxU


使用.query()方法的替代解决方案:

In [5]: df.query("countries in @countries")
Out[5]:
  countries
1        UK
3     China

In [6]: df.query("countries not in @countries")
Out[6]:
  countries
0        US
2   Germany



Answer 3 cs95


如何为pandas DataFrame实现 "在 "和 "不在"?

熊猫提供了两种方法:分别用于Series和DataFrames的 Series.isin DataFrame.isin


根据一个列过滤数据框(也适用于系列)。

最常见的情况是在特定列上应用 isin 条件以过滤DataFrame中的行。

df = pd.DataFrame({'countries': ['US', 'UK', 'Germany', np.nan, 'China']})
df
  countries
0        US
1        UK
2   Germany
3     China

c1 = ['UK', 'China']             # list
c2 = {'Germany'}                 # set
c3 = pd.Series(['China', 'US'])  # Series
c4 = np.array(['US', 'UK'])      # array

Series.isin 接受各种类型的输入。以下是获得所需内容的所有有效方法:

df['countries'].isin(c1)

0    False
1     True
2    False
3    False
4     True
Name: countries, dtype: bool

# `in` operation
df[df['countries'].isin(c1)]

  countries
1        UK
4     China

# `not in` operation
df[~df['countries'].isin(c1)]

  countries
0        US
2   Germany
3       NaN

# Filter with `set` (tuples work too)
df[df['countries'].isin(c2)]

  countries
2   Germany

# Filter with another Series
df[df['countries'].isin(c3)]

  countries
0        US
4     China

# Filter with array
df[df['countries'].isin(c4)]

  countries
0        US
1        UK

多列过滤

有时,你会想在多个列中应用 "中 "的会员制检查,并在多个列中加入一些搜索词。

df2 = pd.DataFrame({
    'A': ['x', 'y', 'z', 'q'], 'B': ['w', 'a', np.nan, 'x'], 'C': np.arange(4)})
df2

   A    B  C
0  x    w  0
1  y    a  1
2  z  NaN  2
3  q    x  3

c1 = ['x', 'w', 'p']

要将 isin 条件应用于列“ A”和“ B”,请使用 DataFrame.isin

df2[['A', 'B']].isin(c1)

      A      B
0   True   True
1  False  False
2  False  False
3  False   True

由此,要保留至少一列为 True 的行,我们可以沿第一个轴使用 any 行:

df2[['A', 'B']].isin(c1).any(axis=1)

0     True
1    False
2    False
3     True
dtype: bool

df2[df2[['A', 'B']].isin(c1).any(axis=1)]

   A  B  C
0  x  w  0
3  q  x  3

请注意,如果你想搜索每一列,你只需省略选择列的步骤,然后进行

df2.isin(c1).any(axis=1)

类似地,要保留ALL True 列为True的行,请以与以前相同的方式使用 all

df2[df2[['A', 'B']].isin(c1).all(axis=1)]

   A  B  C
0  x  w  0

值得注意的是: numpy.isinquery ,列表推导(字符串数据)

除了上述方法之外,您还可以使用numpy等效项: numpy.isin

# `in` operation
df[np.isin(df['countries'], c1)]

  countries
1        UK
4     China

# `not in` operation
df[np.isin(df['countries'], c1, invert=True)]

  countries
0        US
2   Germany
3       NaN

为什么值得考虑?NumPy函数通常比同等的熊猫要快一些,因为它们的开销较低。由于这是不依赖于索引对齐的元素操作,因此在极少数情况下此方法不能适当替代pandas's isin

在处理字符串时,Pandas例程通常是迭代的,因为字符串操作很难向量化。有大量证据表明,这里的列表理解会更快。。我们采取了 in 现在的检查。

c1_set = set(c1) # Using `in` with `sets` is a constant time operation... 
                 # This doesn't matter for pandas because the implementation differs.
# `in` operation
df[[x in c1_set for x in df['countries']]]

  countries
1        UK
4     China

# `not in` operation
df[[x not in c1_set for x in df['countries']]]

  countries
0        US
2   Germany
3       NaN

不过,它的具体化比较麻烦,除非你知道自己在做什么,否则不要用它。

最后,还有这个答案中涉及的 DataFrame.query 。numexpr FTW!




Answer 4 Kos


我通常都是这样做一般的行过滤。

criterion = lambda row: row['countries'] not in countries
not_in = df[df.apply(criterion, axis=1)]



Answer 5 Sam Henderson


我想过滤掉那些有business_ID的dfbc行,而这些行的business_ID也在dfProfilesBusIds的business_ID中。

dfbc = dfbc[~dfbc['BUSINESS_ID'].isin(dfProfilesBusIds['BUSINESS_ID'])]