如何迭代一行并相互比较?

How to iterate a row and compare with each other?

例如,如果名称 'Mark' 重复并且 'Age' 值或 'Gender' 值与包含 'Mark' 的其他行相比不同,则必须删除此类列。

创建数据框的代码:

df = pd.DataFrame({'Name' : ['Mark', 'Mark', 'Mark', 'Mark', 'Mark', 'Nick', 'Nick', 'John', 'Sunny', 'Sunny'], 
                  'Age' : ['22', '22', '25', '25', '17', '20', '20', '17', '23', '23'],
                  'Gender' : ['F', 'F', 'F', 'F', 'F', 'F', 'F', 'M', 'M', 'M']})

数据框如下:

       Name   Age   Gender
0      Mark   22    F
1      Mark   22    F
2      Mark   25    F
3      Mark   25    F
4      Mark   17    F
5      Nick   20    F
6      Nick   20    F
7      John   17    M
8      Sunny  23    M
9      Sunny  23    M

预期输出为:

       Name   Age   Gender
0      Nick   20    F
1      Nick   20    F
2      John   17    M
3      Sunny  23    M
4      Sunny  23    M

例如在第1行和第2行,姓名为Mark,年龄为22,性别为F。而在第3行,姓名为Mark,年龄为25,性别为F,我们可以看到Age 有多个值,那么我们必须删除包含 Mark

的行

好的,这很棘手,所以我会解释每一行。

import pandas as pd

df = pd.DataFrame({'Name' : ['Mark', 'Mark', 'Mark', 'Mark', 'Mark', 'Nick', 'Nick', 'John', 'Sunny', 'Sunny'], 
                  'Age' : ['22', '22', '25', '25', '17', '20', '20', '17', '23', '23'],
                  'Gender' : ['F', 'F', 'F', 'F', 'F', 'F', 'F', 'M', 'M', 'M']})

print(df)

# First, drop all the rows that are exact duplicates of each other.

df1 = df.drop_duplicates()
print(df1)

# If any rows that remain have a duplicate name, those need to go.

df2 = df1.duplicated('Name')
print(df2)

# Go build a DF with just the names that were duplicated.

df3 = df1[df2]['Name']
print(df3)

# Find all the rows in the original df that have a name in this list,
# invert that set, and the result is what we want.

df4 = df[~df.Name.isin(df3)]
print(df4)

这些操作中的几个可以组合成一个单行,但我认为这使它更清楚。我添加了空行来分隔输出中的数据帧。

输出:

    Name Age Gender
0   Mark  22      F
1   Mark  22      F
2   Mark  25      F
3   Mark  25      F
4   Mark  17      F
5   Nick  20      F
6   Nick  20      F
7   John  17      M
8  Sunny  23      M
9  Sunny  23      M

    Name Age Gender
0   Mark  22      F
2   Mark  25      F
4   Mark  17      F
5   Nick  20      F
7   John  17      M
8  Sunny  23      M

0    False
2     True
4     True
5    False
7    False
8    False
dtype: bool

2    Mark
4    Mark
Name: Name, dtype: object

    Name Age Gender
5   Nick  20      F
6   Nick  20      F
7   John  17      M
8  Sunny  23      M
9  Sunny  23      M

一行回答:

df[df.Name.isin((s:=df.drop_duplicates().groupby(['Name']).size().eq(1)).index[s])]

结果:

    Name Age Gender
5   Nick  20      F
6   Nick  20      F
7   John  17      M
8  Sunny  23      M
9  Sunny  23      M

也许值得注意:walrus-operator 确实仍然为变量 s 分配内存,Python 的垃圾收集器将 最终 de-分配。如果您需要一个 Series 表示任何 Name 是否具有不同的行,如下所示,那么值得明确分配它。

>>> s
Name
John      True
Mark     False
Nick      True
Sunny     True
dtype: bool

在您的计算中的任何其他地方,可能值得将其显式分配给您维护引用的变量。


解释:

# from the OG df
df[
   # boolean mask if the name is in
   df.Name.isin(
                # walrus-operator to temporarily hold result
                # drop the duplicate rows (duplicates name + age + gender)
                (s:=df.drop_duplicates()
                       # group on Name
                       .groupby(['Name'])
                       # after dropping duplicates, there's only one record
                       # i.e. no different age/gender records for same name
                       .size().eq(1))
                # mask on names where no-duplicates is true, drop names where false
                ).index[s]
               # pass as series to `df.Name.isin`
               )
  ]