如何在熊猫数据框的每一行中找到选定列中的两个最低值?

Posted

技术标签:

【中文标题】如何在熊猫数据框的每一行中找到选定列中的两个最低值?【英文标题】:How do I find the two lowest values across selected columns in each row of a pandas dataframe? 【发布时间】:2020-10-26 23:29:13 【问题描述】:

在计算成绩时,我会去掉每个学生的两个最低作业分数。此处显示了一个示例数据框:

df=pd.DataFrame([[10, 9, 10, 5, 7], [8, 7, 9, 9, 4], [10, 10, 7, 0, 8],
                [5, 9, 7, 6, 3], [10, 5, 0, 8, 10], [8, 9, 10, 10, 10]],
               columns=['HW1', 'HW2', 'HW3', 'HW4', 'HW5'],
               index=['Aaron', 'Bridget', 'Charles', 'Donna', 'Evan', 'Francesca'])

df

实际的数据框包含比这更多的列(用于测试、报告等),但这是家庭作业,我需要找到每条记录的两个最低分数。

我想在数据框中添加两列 ['Lowest'] 和 ['Second_Lowest'],并在这些列中分别指示每个学生的最低分数和次低分数。

我尝试了以下代码,使用 .min() 方法获取最小值,但出现错误:

df['Lowest_HW'] = df[['HW1', 'HW2', 'HW3', 'HW4', 'HW5']].min()

df.head()

所以对于 Aaron,Lowest 的值为 5,Second_Lowest 的值为 7;对于 Francesca,Lowest 为 8,Second_Lowest 为 9。

显然,.min() 方法的代码不正确,我完全不知道要找到第二低的值。

对我如何处理这些步骤有什么建议吗?

【问题讨论】:

您的最低代码几乎是正确的,但是您需要.min(axis=1)min 应用于行而不是列。 @ALollz:这是个好问题。我想要单独列中的最低值的原因是因为我要创建一个总作业分数列,该列将是所有 5 个作业列的总和,减去 Lowest 和 Second_Lowest,所以我确实想调出它们的两个最低作业值. 【参考方案1】:

您可以使用 np.sort 并仅选择前 2 列来同时创建最低的两列:

df['lowest'], df['second_lowest'] = np.sort(df, axis=1)[:, :2].T
print (df)
           HW1  HW2  HW3  HW4  HW5  lowest  second_lowest
Aaron       10    9   10    5    7       5              7
Bridget      8    7    9    9    4       4              7
Charles     10   10    7    0    8       0              7
Donna        5    9    7    6    3       3              5
Evan        10    5    0    8   10       0              5
Francesca    8    9   10   10   10       8              9

但是如果你的意思是在没有这两个最低值的情况下得到总和,那么不要创建上面的列并做

df['sum_without_2lowest'] = np.sort(df, axis=1)[:, 2:].sum(1)
print (df)
           HW1  HW2  HW3  HW4  HW5  sum_without_2lowest
Aaron       10    9   10    5    7                   29
Bridget      8    7    9    9    4                   26
Charles     10   10    7    0    8                   28
Donna        5    9    7    6    3                   22
Evan        10    5    0    8   10                   28
Francesca    8    9   10   10   10                   30

【讨论】:

【参考方案2】:

又是另一种方法,使用nsmallest。这次它直接从DataFrame中移除了两个最低等级

df[df.apply(lambda x: x.nsmallest(2), axis=1).isna()]

            HW1   HW2   HW3   HW4   HW5
Aaron      10.0   9.0  10.0   NaN   NaN
Bridget     8.0   NaN   9.0   9.0   NaN
Charles    10.0  10.0   NaN   NaN   8.0
Donna       NaN   9.0   7.0   6.0   NaN
Evan       10.0   NaN   NaN   8.0  10.0
Francesca   NaN   NaN  10.0  10.0  10.0

正如您在 cmets 中提到的,您想要获得所有成绩的总和减去两个最低成绩的总和,这可以轻松解决问题!

df[df.apply(lambda x: x.nsmallest(2), axis=1).isna()].sum(axis=1)

Aaron        29.0
Bridget      26.0
Charles      28.0
Donna        22.0
Evan         28.0
Francesca    30.0
dtype: float64

【讨论】:

【参考方案3】:

您可以使用apply 来执行此操作,对列进行排序并选择第一个和第二个值。

columns = [c for c in df.columns if c.startswith('HW')]
df[['lowest', '2nd_lowest']] = df[columns].apply(lambda x: sorted(x)[0:2], axis=1, result_type='expand')


           HW1  HW2  HW3  HW4  HW5  lowest  2nd_lowest
Aaron       10    9   10    5    7       5           7
Bridget      8    7    9    9    4       4           7
Charles     10   10    7    0    8       0           7
Donna        5    9    7    6    3       3           5
Evan        10    5    0    8   10       0           5
Francesca    8    9   10   10   10       8           9

【讨论】:

以上是关于如何在熊猫数据框的每一行中找到选定列中的两个最低值?的主要内容,如果未能解决你的问题,请参考以下文章

从熊猫字典列表中提取元素

如何为熊猫数据框中的每一行映射/替换列中的多个值

从 Python 数据框的一列中的每一行中删除前 x 个字符

如何将一个熊猫数据框的一列与另一个数据框的每一列相加?

如何使用点绘制熊猫数据框的两列

熊猫在巨大的csv的每一列中找到独特元素的数量