NumPy - Zipf 分布
什么是 Zipf 分布?
Zipf 分布是一种离散概率分布,用于描述按降序排列的元素频率。
它遵循这样一个原则:元素的频率与其在频率表中的排名成反比,通常在自然语言中可以看到,最常见的词出现的频率是第二常见词的两倍,是第三常见词的三倍,依此类推。
它由参数 "s" 定义,该参数决定了分布的偏度。例如,大型文本语料库中词频的分布往往遵循 Zipf 分布。从数学上讲,Zipf 分布的概率质量函数 (PMF) 表示为:
P(X = k) = (1 / ks) / H(N, s)
这里,k 是排名,s 是表征分布的指数,H(N, s) 是第 N 个广义调和数,用于归一化分布。
在 NumPy 中生成 Zipf 样本
NumPy 提供了 numpy.random.zipf() 函数来从 Zipf 分布中生成随机样本。该函数需要两个主要参数:
- a: 分布参数,也称为指数。
- size: 要生成的样本数量(可选)。
示例:生成 Zipf 样本
以下示例生成 10 个来自指数为 2 的 Zipf 分布的随机样本 −
import numpy as np
# 生成 Zipf 样本
a = 2
samples = np.random.zipf(a, size=10)
print("Generated Zipf samples:", samples)
以下是得到的结果 −
Generated Zipf samples: [1 3 1 2 1 1 1 1 2 1]
Zipf 分布的特性
Zipf 分布具有几个独特的特性,使其适用于建模现实世界现象,它们是 −
- Heavy Tail: 该分布具有长尾特性,即少数事件非常常见,而大多数事件罕见。
- Power Law: 事件的概率与其排名幂次成反比。
- Scale-Invariant: 当测量尺度变化时,分布保持不变。
示例:可视化 Zipf 定律
让我们可视化 Zipf 分布,以更好地理解其特性。我们可以使用 Matplotlib 绘制每个排名的出现频率 −
import numpy as np
import matplotlib.pyplot as plt
# 生成大量样本
a = 2
samples = np.random.zipf(a, size=1000)
# 统计每个排名的出现次数
unique, counts = np.unique(samples, return_counts=True)
# 绘制排名-频率分布图
plt.figure(figsize=(10, 6))
plt.loglog(unique, counts, marker="o")
plt.title("Zipf Distribution")
plt.xlabel("Rank")
plt.ylabel("Frequency")
plt.show()
我们得到一个对数-对数图,显示每个排名的频率,展示了 Zipf 分布的长尾和幂律特性 −

Zipf 分布的应用
Zipf 分布用于各个领域来建模少数项目非常常见而多数项目罕见现象。常见应用包括 −
- 自然语言处理 (NLP): 建模语料库中的词频。
- 人口研究: 分析城市人口和规模。
- 互联网流量: 理解网页访问和点击的分布。
示例:文本中的词频
假设我们有一个文本文档,并想使用 Zipf 分布来建模词频 −
import matplotlib.pyplot as plt
from collections import Counter
# 示例文本
text = "the quick brown fox jumps over the lazy dog the quick brown fox"
# 将文本分割成单词
words = text.split()
# 统计词频
word_counts = Counter(words)
# 获取排名和频率
ranks = range(1, len(word_counts) + 1)
frequencies = [count for word, count in word_counts.most_common()]
# 绘制排名-频率分布图
plt.figure(figsize=(10, 6))
plt.loglog(ranks, frequencies, marker="o")
plt.title("Word Frequency Distribution")
plt.xlabel("Rank")
plt.ylabel("Frequency")
plt.show()
我们得到一个对数-对数图,显示文本中每个词排名的频率,遵循 Zipf 分布 −
估计 Zipf 指数
在实际应用中,我们经常需要估计 Zipf 分布的指数参数。这可以通过各种统计技术来实现。一种简单的方法是对排名与频率的对数-对数图进行直线拟合。
示例:估计指数
在下面的示例中,估计的指数接近实际值 (a = 2),证明了估计方法的准确性 −
import numpy as np
from scipy.stats import linregress
# 生成大量样本
a = 2
samples = np.random.zipf(a, size=1000)
# 统计每个排名的出现次数
unique, counts = np.unique(samples, return_counts=True)
# 对对数-对数图进行线性回归
log_ranks = np.log(unique)
log_counts = np.log(counts)
slope, intercept, r_value, p_value, std_err = linregress(log_ranks, log_counts)
print("Estimated exponent:", -slope)
得到的输出如下所示 −
Estimated exponent: 0.8852106553815038
模拟真实世界场景
让我们使用 Zipf 分布模拟一个真实世界场景。假设我们想建模一个热门新闻网站上网站访问的分布。
示例:网站访问
我们可以从 Zipf 分布生成大量样本,并分析不同页面访问的分布 −
import matplotlib.pyplot as plt
import numpy as np
# 生成 Zipf 样本
a = 1.5
samples = np.random.zipf(a, size=10000)
# 统计每个页面访问的出现次数
unique, counts = np.unique(samples, return_counts=True)
# 绘制排名-频率分布图
plt.figure(figsize=(10, 6))
plt.loglog(unique, counts, marker="o")
plt.title("Website Visits Distribution")
plt.xlabel("Page Rank")
plt.ylabel("Visit Frequency")
plt.show()
我们得到一个对数-对数图,显示网站访问的分布,展示了 Zipf 分布的重尾和幂律特性 −
