【问题标题】:Drop Duplicate Rows Based on Target Class Conditions根据目标类条件删除重复行
【发布时间】:2021-11-04 12:34:12
【问题描述】:

我有一个包含 3 个目标类的数据集:“是”、“也许”和“否”。

Unique_id       target
111              Yes
111             Maybe
111              No
112              No
112             Maybe
113              No

我想根据 unique_id 删除重复的行。但是“删除重复”通常保留第一行或最后一行,我想根据以下条件保留行:

1) If unique_id has all the 3 classes (Yes, Maybe and No), we’ll keep only the ‘Yes’ class.
2) If unique_id has the 2 classes (Maybe and No), we’ll keep only the ‘Maybe’ class.
3) We’ll keep the ‘No’ class when only ‘No’ will be there.

我尝试了“sort_values”目标类(Yes=1、Maybe=2、No=3),然后删除了重复项。

期望的输出:

Unique_id       target
111               Yes
112              Maybe
113               No

我正在考虑是否有更好的方法来做到这一点。

任何建议将不胜感激。谢谢!

【问题讨论】:

  • 如果我理解你使用整数值 1,2,3 而不是字符串,排序和删除。我认为没关系。一个非常相似的解决方案是使用categorical dataordered=True。您也可以进行 groupby 并取最小值(1,2,3 之间)
  • ID 中的所有行都具有该目标或只是任何一个?
  • 看看您是否需要从下面的答案中进一步澄清。如果没有更多问题,请接受您选择的答案,让我们知道最适合您需求的任何答案。谢谢!

标签: python pandas dataframe data-manipulation drop-duplicates


【解决方案1】:

您可以将pd.CategoricalDtype 的列target 设置为Categorical 数据类型,其顺序为['Yes' < 'Maybe' < 'No'],如下所示:

t = pd.CategoricalDtype(categories=['Yes', 'Maybe', 'No'], ordered=True)
df['target'] = df['target'].astype(t)

然后,您使用.groupby()Unique_id 分组,并使用.GroupBy.min() 在同一组Unique_id 上获取min 上的Unique_id

df.groupby('Unique_id', as_index=False)['target'].min()

结果:

   Unique_id target
0        111    Yes
1        112  Maybe
2        113     No

编辑

案例 1: 如果您有 2 个或更多类似的列(例如 targettarget2)以相同的顺序排序,您只需将代码应用于 2 列。例如,如果我们有以下数据框:

   Unique_id target target2
0        111    Yes      No
1        111  Maybe   Maybe
2        111     No     Yes
3        112     No      No
4        112  Maybe   Maybe
5        113     No   Maybe

可以同时获取2列的最小值,如下:

t = pd.CategoricalDtype(categories=['Yes', 'Maybe', 'No'], ordered=True)
df[['target', 'target2']] = df[['target', 'target2']].astype(t)

df.groupby('Unique_id', as_index=False)[['target', 'target2']].min()

结果:

   Unique_id target target2
0        111    Yes     Yes
1        112  Maybe   Maybe
2        113     No   Maybe

案例 2:如果您想显示数据框中的所有列,而不仅仅是 Unique_idtarget 列,您可以使用更简单的语法,如下所示:

另一个数据框示例:

   Unique_id target  Amount
0        111    Yes     123
1        111  Maybe     456
2        111     No     789
3        112     No    1234
4        112  Maybe    5678
5        113     No      25

然后,要显示带有target 的所有列以及Unique_id 的最小值,您可以使用:

t = pd.CategoricalDtype(categories=['Yes', 'Maybe', 'No'], ordered=True)
df['target'] = df['target'].astype(t)

df.loc[df.groupby('Unique_id')['target'].idxmin()]

结果:

   Unique_id target  Amount
0        111    Yes     123
4        112  Maybe    5678
5        113     No      25

【讨论】:

  • 嗨@SeaBean,谢谢。有用。如果我有很多列呢?
  • @Roy 您的意思是以下哪种情况:1)您有很多列,但只有一列需要按此顺序排序,或者 2)您有 2 列或更多列需要按此顺序排序这个命令 ?如果是情况 2),此解决方案比其他解决方案效果更好。我们可以在 2 列上设置类型,也可以按 2 列分组。如果是情况 1),我们还可以使用 idxmin 来显示目标列已排序的所有列。总之,使用分类数据类型可以显示 2 列,例如 targettarget2,具有相似的排序顺序,同时也可以排序。
  • @Roy 查看我的编辑。然后,您将在此处了解使用分类数据类型的优势。如果您只想显示所有列,我们可以使用更简单的代码df.loc[df.groupby('Unique_id')['target'].idxmin()] 来实现它。如果您希望 2 个相似的列仅获得组中的最小值,我们可以轻松地使用 2 个列的代码。看看吧。
  • 哇,这是一个很棒的方法,@SeaBean。非常感谢:)
【解决方案2】:

使用mapidxmin

t = {'Yes':0, 'Maybe':1, 'No':2}
df.loc[df.assign(tar=df.target.map(t)).groupby('Unique_id')['tar'].idxmin()]

【讨论】:

  • 再次感谢@Pygirl。 idxmin 是个好技巧。
猜你喜欢
  • 1970-01-01
  • 2021-04-02
  • 2023-01-11
  • 2021-12-20
  • 2019-04-19
  • 1970-01-01
  • 1970-01-01
  • 2017-11-23
  • 1970-01-01
相关资源
最近更新 更多