如何在 Python 中查找均值、中值和众数?

Python 数据统计基础:均值、中位数和众数

均值、中位数和众数是统计学中三个至关重要的概念。在 Python 中,无论是否借助外部库,都能轻松地计算它们。

这三者是衡量集中趋势的核心指标。集中趋势能够帮助我们了解数据集中“典型”或“平均”的值。对于数据科学的初学者而言,这是一个很棒的入门教程。

在本教程结束后,您将能够:

  • 掌握均值、中位数和众数的概念。
  • 在 Python 中创建自定义的均值、中值和众数函数。
  • 快速利用 Python 的 statistics 模块进行这些度量计算。

如果您需要此练习的可下载版本,请访问 GitHub 仓库

现在,让我们深入了解计算均值、中位数和众数的不同方法。

Python 中计算均值的方法

均值,又称算术平均数,是最常用的集中趋势度量方法。

请记住,集中趋势代表了一组数据的典型值。

数据集是数据的集合,在 Python 中,它可以是任何内置的数据结构,例如:

  • 列表、元组和集合:一系列对象的集合。
  • 字符串:一系列字符的集合。
  • 字典:一系列键值对的集合。

注意:尽管 Python 中还有其他数据结构,如队列或堆栈,我们在此仅关注内置数据结构。

计算均值的方法是将数据集中所有数值相加,然后除以数值的个数。例如,如果有一个数字列表如下:

[1, 2, 3, 4, 5, 6]

平均数或均值为 3.5,因为列表中所有数字之和是 21,列表的长度为 6。21 除以 6 得 3.5。您可以使用以下公式计算:

(1 + 2 + 3 + 4 + 5 + 6) / 6 = 3.5

在本教程中,我们将使用篮球队队员的数据作为示例。

自定义均值函数

首先,我们来计算篮球队队员的平均年龄。这个球队的名字叫做“Pythonic Machines”。

pythonic_machine_ages = [19, 22, 34, 26, 32, 30, 24, 24]

def mean(dataset):
    return sum(dataset) / len(dataset)

print(mean(pythonic_machine_ages))

代码解析:

  • “pythonic_machine_ages” 是一个包含篮球队员年龄的列表。
  • 我们定义了一个名为 mean() 的函数,该函数返回给定数据集的总和除以其长度。
    • sum() 函数返回可迭代对象(在本例中为列表)的总和。尝试传递数据集作为参数,它将返回 211。
    • len() 函数返回可迭代对象的长度,如果将数据集传递给它,您将得到 8。
  • 我们将篮球队的年龄传递给 mean() 函数并打印结果。

运行代码,您会看到输出:

26.375
# 因为 211 / 8 = 26.375

这个输出代表了篮球队员的平均年龄。请注意,这个数字可能没有出现在数据集中,但它准确地描述了大多数球员的年龄。

使用 Python 统计模块的 mean() 函数

计算集中趋势的度量是很多开发人员的常见操作。正因为如此,Python 的 statistics 模块提供了许多函数来执行这些计算,以及其他基本统计操作。

由于它是 Python 标准库 的一部分,所以你不需要使用 PIP 安装任何外部包。

下面是如何使用这个模块:

from statistics import mean

pythonic_machine_ages = [19, 22, 34, 26, 32, 30, 24, 24]

print(mean(pythonic_machine_ages))

在上面的代码中,您只需要从 statistics 模块导入 mean() 函数,并将数据集作为参数传递给它。这会返回和我们之前自定义函数一样的结果:

26.375

现在您对均值的概念已经非常清楚了,让我们继续讨论中位数的计算。

Python 中查找中位数的方法

中位数 是一个排序数据集中间的值。它也用于提供总体的“典型”值。

在编程中,我们可以将中位数定义为将一个序列分为上下两部分的值。

计算中位数,首先,我们需要对数据集进行排序。可以使用排序算法或者内置函数 sorted()。第二步是判断数据集的长度是奇数还是偶数。 根据不同的情况,执行不同的步骤:

  • 奇数:中位数是数据集的中间值。
  • 偶数:中位数是两个中间值的平均值。

继续使用我们的篮球队数据集,我们来计算队员的平均身高(以厘米为单位):

[181, 187, 196, 196, 198,  203, 207, 211, 215]
# 由于数据集的长度为奇数,我们选择中间值
median = 198

可以看到,由于数据集的长度是奇数,我们可以直接取中间值作为中位数。但是,如果一名队员刚退役,情况会怎么样?

我们需要计算数据集两个中间值的平均值:

[181, 187, 196, 198, 203, 207, 211, 215]
# 我们选择两个中间值,并除以 2
median = (198 + 203) / 2
median = 200.5

自定义中位数函数

让我们把上述概念转化为 Python 函数。

请记住,我们需要遵循三个步骤来获取数据集的中位数:

  • 对数据集进行排序:可以使用 sorted() 函数来实现。
  • 确定它是奇数还是偶数:可以通过获取数据集的长度并使用模运算符 (%) 来实现。
  • 根据不同的情况返回中位数:
    • 奇数:返回中间值。
    • 偶数:返回两个中间值的平均值。

这将生成以下函数:

pythonic_machines_heights = [181, 187, 196, 196, 198, 203, 207, 211, 215]
after_retirement = [181, 187, 196, 198, 203, 207, 211, 215]

def median(dataset):
    data = sorted(dataset)
    index = len(data) // 2

    # 如果数据集的长度为奇数
    if len(dataset) % 2 != 0:
        return data[index]

    # 如果数据集的长度为偶数
    return (data[index - 1] + data[index]) / 2

打印我们数据集的结果:

print(median(pythonic_machines_heights))
print(median(after_retirement))

输出:

198
200.5

注意,我们在函数开始时创建了一个名为 data 的变量,它指向已排序的数据库。 虽然上面的列表是有序的,但我们想创建一个可重用的函数,因此每次调用该函数时都要对数据集进行排序。

索引通过使用整数除法运算符存储数据集的中间值或中上值。例如,如果我们传递“pythonic_machine_heights”列表,它的值为 4。

请记住,在 Python 中,序列索引从零开始,这使得我们能够通过整数除法返回列表的中间索引。

然后我们通过将模运算的结果与任何非零值进行比较来检查数据集的长度是否为奇数。如果条件为真,则返回中间元素,例如,对于 “pythonic_machine_heights” 列表:

>>> pythonic_machine_heights[4]
# 198

另一方面,如果数据集的长度为偶数,则返回中间值的平均值。请注意 data[index – 1] 给出了数据集的下中点,而 data[index] 给出了上中点。

使用 Python 统计模块的 median() 函数

这种方法要简单得多,因为我们使用的是统计模块中已有的函数。

就个人而言,如果已经有现成的东西,我会选择使用它,因为 DRY (Don’t Repeat Yourself) 原则(在这种情况下,不要重复别人的代码)。

您可以使用以下代码计算前面数据集的中位数:

from statistics import median

pythonic_machines_heights = [181, 187, 196, 196, 198, 203, 207, 211, 215]
after_retirement = [181, 187, 196, 198, 203, 207, 211, 215]

print(median(pythonic_machines_heights))
print(median(after_retirement))

输出:

198
200.5

Python 中计算众数的方法

众数是数据集中出现频率最高的值。 我们可以将其视为学校中“最受欢迎”的群体,它可能代表了所有学生的标准。

众数的一个例子可以是科技商店的每日销售额。该数据集的众数将是在特定日期最畅销的产品。

['laptop', 'desktop', 'smartphone', 'laptop', 'laptop', 'headphones']

正如你所看到的,上面数据集的众数是“laptop”,因为它是列表中出现频率最高的值。

众数的美妙之处在于数据集可以不是数字。例如,我们可以使用字符串。

我们再来分析一下一天的销售额:

['mouse', 'camera', 'headphones', 'usb', 'headphones', 'mouse']

上面的数据集有两种众数:“mouse” 和 “headphones”,因为它们的频率都是 2。这意味着它是一个多峰数据集。

如果在数据集中找不到众数,如下所示,怎么办?

['usb', 'camera', 'smartphone', 'laptop', 'TV']

这被称为 均匀分布,基本上,这意味着数据集中没有众数。

现在你已经对众数的概念有了初步的了解,让我们用 Python 来计算它。

自定义众数函数

我们可以将值的频率视为键值对,换句话说,就是一个 Python 字典。

为了扩展篮球的例子,我们可以使用两个数据集:每场比赛的得分,以及一些球员的运动鞋赞助。

为了首先找到众数,我们需要用数据集中存在的每个值创建一个频率字典,然后获取最大频率,并返回具有该频率的所有元素。

让我们将其转化为代码:

points_per_game = [3, 15, 23, 42, 30, 10, 10, 12]
sponsorship = ['nike', 'adidas', 'nike', 'jordan',
               'jordan', 'rebook', 'under-armour', 'adidas']

def mode(dataset):
    frequency = {}

    for value in dataset:
        frequency[value] = frequency.get(value, 0) + 1

    most_frequent = max(frequency.values())

    modes = [key for key, value in frequency.items()
                      if value == most_frequent]

    return modes

检查传递两个列表作为参数的结果:

print(mode(points_per_game))
print(mode(sponsorship))

输出:

[10]
['nike', 'adidas', 'jordan']

如您所见,第一个打印语句为我们提供了一个众数,而第二个则返回了多个众数。

更深入地解释上面的代码:

  • 我们声明一个频率字典。
  • 我们遍历数据集以创建一个 直方图— 一组计数器(或频率)的统计术语 —
    • 如果在字典中找到键,则将值加一。
    • 如果没有找到,我们创建一个值为 1 的键值对。
  • most_frequent 变量存储——具有讽刺意味的是——频率字典的最大值(不是键)。
  • 我们返回众数变量,它由频率字典中频率最高的所有键组成。

请注意变量命名对于编写可读代码的重要性。

使用 Python 统计模块中的 mode() 和 multimode() 函数

统计模块再次为我们提供了一种快速进行基本统计操作的方法。

我们可以使用两个函数:mode()multimode()

from statistics import mode, multimode

points_per_game = [3, 15, 23, 42, 30, 10, 10, 12]
sponsorship = ['nike', 'adidas', 'nike', 'jordan',
               'jordan', 'rebook', 'under-armour', 'adidas']

上面的代码导入了这两个函数并定义了我们一直在使用的数据集。

这里有一个小区别:mode() 函数返回它遇到的第一个众数,而 multimode() 返回一个包含数据集中最频繁的值的列表。

因此,我们可以说我们定义的自定义函数实际上是一个 multimode() 函数。

print(mode(points_per_game))
print(mode(sponsorship))

输出:

10
nike

注意:在 Python 3.8 或更高版本中,mode() 函数返回它找到的第一个众数。如果您使用的是旧版本,则会收到一个 统计错误

使用 multimode() 函数:

print(multimode(points_per_game))
print(multimode(sponsorship))

输出:

[10]
['nike', 'adidas', 'jordan']

总结

恭喜!如果您看到这里,那么您已经学会了如何计算均值、中位数和众数,这三个主要的集中趋势度量指标。

虽然您可以定义自定义函数来查找均值、中位数和众数,但建议使用 statistics 模块,因为它是标准库的一部分,无需安装任何内容即可开始使用。

接下来,请阅读关于 Python 数据分析的友好介绍。