删除未由 Pandas 中的索引唯一标识的行

Deleting rows not uniquely identified by the index in Pandas

如何从 Pandas DataFrame 中删除(删除)行,其中的行 不是 由索引唯一标识的?
澄清我所说的唯一标识的意思:查询索引时,返回多个值。

我可以制作一个掩码,当它用作 df.loc 的参数时,可以正确地 returns 目标行,但我不能让它与 df.drop 一起使用。

示例代码:

打印函数的输出包含在注释中。

from __future__ import print_function
import numpy as np
import pandas as pd


np.random.seed(0)
df = pd.DataFrame(
    data=np.random.randint(0, 10, size=(7, 3)),
    index=[['u01', 'u01', 'u01', 'u02', 'u02', 'u03', 'u03'], ['C', 'C', 'C', 'C', 'T', 'T', 'T']],
    columns=['foo', 'bar', 'baz'])
df.index.names = ['user', 'comType']

print(df)
#                  foo  bar  baz
#    user comType
#    u01  C          5    0    3
#         C          3    7    9
#         C          3    5    2
#    u02  C          4    7    6
#         T          8    8    1
#    u03  T          6    7    7
#         T          8    1    5

mask = (df.baz > 8) | (df.baz < 2)
print(mask)
#    user  comType
#    u01   C          False
#          C           True
#          C          False
#    u02   C          False
#          T           True
#    u03   T          False
#          T          False
#    Name: baz, dtype: bool


print(df.loc[mask])
#                  foo  bar  baz
#    user comType
#    u01  C          3    7    9
#    u02  T          8    8    1

df2 = df.drop(mask.index[mask.values])  # Drops all rows of user user u01, one row of user u02
print(df2)
#                  foo  bar  baz
#    user comType
#    u02  C          4    7    6
#    u03  T          6    7    7
#         T          8    1    5

df3 = df.drop(mask)  # Doesn't do anything
print(df3)
#                  foo  bar  baz
#    user comType
#    u01  C          5    0    3
#         C          3    7    9
#         C          3    5    2
#    u02  C          4    7    6
#         T          8    8    1
#    u03  T          6    7    7
#         T          8    1    5



一个小提示:如果你想运行你自己机器上的代码,我建议用这些行替换打印函数,否则输出很难辨别形式彼此:

print('df', df, sep=" =\n\n", end="\n"*5)
print('mask', mask, sep=" =\n\n", end="\n"*5)
print('df.loc[mask]', df.loc[mask], sep=" =\n\n", end="\n"*5)
print('df2', df2, sep=" =\n\n", end="\n"*5)
print('df3', df3, sep=" =\n\n", end="\n"*5)

因为您已经有了一个布尔掩码,所以您可以只使用它而不是通过使用一元非 ~:

进行反转来删除
In [199]:
mask

Out[199]:
u01  C    False
     C     True
     C    False
u02  C     True
     T    False
u03  T     True
     T    False
Name: baz, dtype: bool

In [198]:    
df[~mask]

Out[198]:
       foo  bar  baz
u01 C    0    5    8
    C    5    2    7
u02 T    6    7    3
u03 T    6    5    5

drop 获取用于删除的标签值,您传递的是一个完整的布尔掩码,因此没有任何内容被删除,因为所有标签都存在,除了您想要的是索引值,但即使那样它也不会起作用:

In [212]:
df.drop(mask[~mask].index)

Out[212]:
       foo  bar  baz
u02 C    3    7    1

因为您的多索引标签在第一层重复,因此您最终只有一行,掩码就是您所需要的

通过 ~boolean indexing:

使用反转布尔掩码
mask = (df.baz > 8) | (df.baz < 2)
print (mask)
user  comType
u01   C          False
      C           True
      C          False
u02   C          False
      T           True
u03   T          False
      T          False
Name: baz, dtype: bool

print(~mask)
user  comType
u01   C           True
      C          False
      C           True
u02   C           True
      T          False
u03   T           True
      T           True
Name: baz, dtype: bool

print (df[~mask])
              foo  bar  baz
user comType               
u01  C          5    0    3
     C          3    5    2
u02  C          4    7    6
u03  T          6    7    7
     T          8    1    5