描述统计概念部分:统计学part2---描述统计 - 掘金 (juejin.cn)
python3.10
pycharm
文件目录介绍
项目文件结构如上图所示,Statistics为总项目文件,包含了pq_stats包和main_descriptive_stats.py文件,pq_stats包用于编写实现功能的函数,main_descriptive_stats.py文件用于测试和使用包里面的函数
基础计算
我们会使用到python的collections库完成下面的内容
具体介绍请移步至:docs.python.org/zh-cn/3/lib…
频数计算
from collections import Counter
if __name__ == '__main__':
# 频数计算
data = [2, 2, 2, 2, 1, 1, 1, 3, 3]
counter = Counter(data)
print(counter.most_common())
可以看见程序输出了三个元组,其中每个元组的第一个元素代表的是我们的数据,第二个元素代表的是对应的数据出现的次数(例:2出现了4次)
频率
下面我们在pq_stats下创建一个名为descriptive_stats.py的文件,并编写一个函数用于计算频率
from collections import Counter
def frequency(data):
"""频率计算"""
counter = Counter(data)
ret = [] # 创建一个空列表储存函数返回值
for point in counter.most_common():
ret.append((point[0], point[1]/len(data)))
return ret
然后在main_descriptive_stats.py中对函数frequency进行测试
from collections import Counter
from pq_stats.descriptive_stats import frequency
if __name__ == '__main__':
# 频率测试
data = [2, 2, 2, 2, 1, 1, 1, 3, 3]
print(frequency(data))
集中趋势指标实现
众数
我们知道,众数的出现可能有三种情况:
- 只有一个众数
- 有多个众数
- 没有众数
所以,在寻找众数前,我们需要对数据出现的次数进行判断,然后根据次数判断的结果找众数
依然是在descriptive_stats.py中进行函数定义
def mode(data):
"""寻找众数"""
counter = Counter(data)
# 对数据出现次数进行判断
if counter.most_common()[0][1] == 1:
return None,None
count = counter.most_common()[0][1] # 获取众数出现的次数
ret = []
for point in counter.most_common():
"""判断每个数据点出现的次数是否与众数出现的次数一致"""
if point[1] == count:
ret.append(point[0])
else:
break
return ret, count
解析:由于我们是按照数据出现次数的从大到小对全部数据进行遍历的,因此,只有遇见的情况,即可说明众数以全部确定,直接退出循环,并将众数列表ret返回,减少函数运行消耗的时间
if counter.most_common()[0][1] == 1:
return None,None
解析:因为Counter.most_common()是按照数据出现的次数从高到低排序的,因此,如果第一个数据的出现次数是1,也就意味着元素最大出现次数是1,说明这组数据中不存在众数,返回None值(第一个None是众数,第二个None是众数出现的次数)
在main_descriptive_stats.py中对函数mode进行测试
from collections import Counter
from pq_stats.descriptive_stats import frequency, mode
if __name__ == '__main__':
data = [2, 2, 2, 2, 1, 1, 1, 3, 3]
# 众数测试
mode_value, mode_count = mode(data)
print(mode_value, mode_count)
更加严谨一点,我们应该先判断众数是否存在,众数不存在的情况下,我们需要给出提升信息
if mode_value:
print(mode_value, mode_count)
else:
print('Mode does not exist!')
中位数
通过概念我们知道,中位数是通过排序后最中间的一个数,或者是最中间两个数的平均数,因此求中位数前我们需要先对数据进行排序,如果对数据的个数进行奇偶性判断
在descriptive_stats.py中进行函数定义
def median(data):
"""中位数"""
sorted_data = sorted(data)
n = len(sorted_data)
if n % 2 == 1:
return sorted_data[n // 2]
return (sorted_data[n // 2 - 1] + sorted_data[n // 2]) / 2
在main_descriptive_stats.py中对函数median进行测试
from collections import Counter
from pq_stats.descriptive_stats import frequency, mode, median
if __name__ == '__main__':
# 中位数测试
data = [2, 3, 1, 9, 6, 7, 5, 8, 4]
print(median(data))
data = [2, 3, 1, 4, 6, 7, 5, 8]
print(median(data))
均值
在descriptive_stats.py中进行函数定义
def mean(data):
return (sum(data) / len(data))
对函数进行测试
from collections import Counter
from pq_stats.descriptive_stats import frequency, mode, median, mean
if __name__ == '__main__':
# 均值测试
data = [2, 3, 1, 9, 6, 7, 5, 8, 4]
print(mean(data))
离散趋势指标实现
极差
极差是一组数据的最大值和最小值的差,我们在descriptive_stats.py中进行函数定义
def rng(data):
"""极差"""
return max(data) - min(data)
对函数进行测试
from collections import Counter
from pq_stats.descriptive_stats import rng
if __name__ == '__main__':
# 极差测试
data = [2,4,6,8,2,3,9,3,0]
print(rng(data))
四分位数
四分位数和中位数相似,同样和数据的长度相关,如果数据个数是偶数的话,我们就分别对中位数左边和右边的个数求中位数,如果数据个数是奇数,我们需要先把中位数进行剔除,然后再求四分位数,在descriptive_stats.py中进行函数定义
def quartile(data):
n = len(data)
q1, q2, q3 = None, None, None
if n >= 4:
sorted_data = sorted(data)
q2 = median(sorted_data) # q2就是中位数,可直接使用求中位数的函数求得
if n % 2 == 1: # 数据长度为奇数
q1 = median(sorted_data[:n // 2])
q3 = median(sorted_data[n // 2 + 1:])
else:
q1 = median(sorted_data[:n // 2])
q3 = median(sorted_data[n//2:])
return q1, q2, q3
if n >= 4:
解析:如果数据的个数小于4,四分位数不存在
对函数进行测试
from collections import Counter
from pq_stats.descriptive_stats import frequency, mode, median, mean,rng, quartile
if __name__ == '__main__':
# 四分位数测试
data = [9,3,6,4,8,1,2,7,5]
print(quartile(data))
方差
方差的计算,我们需要知道数据的增值和数据长度,在descriptive_stats.py中进行函数定义
def variance(data):
"""方差"""
n = len(data)
if n <= 1:
return None
mean_value = mean(data) # 方差的计算需要使用均值
return sum((e - mean_value) ** 2 for e in data) / (n - 1)
if n <= 1:
return None
解析:如果数据为空或只有一个数据,方差也为空
sum((e - mean_value) ** 2 for e in data) / (n - 1)
解析:在方差的数学公式在,我们的被除数是n,但是这个时候我们需要根据实际情况进行判断,如果我们计算的是全部数据,我们的被除数为n,如果我们计算的是样本数据,我们的被除数应该为n-1,在数据分析过程中,我们获取到的数据大多数情况下都是样本数据,因此这里我们把被除数设置为n-1
对函数进行测试
from collections import Counter
from pq_stats.descriptive_stats import frequency, mode, median, mean,rng, quartile, variance
# 方差测试
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(variance(data))
标准差
标准差从定义上来讲,就是对方差进行开根,我们需要在math库在调用开根的函数sqrt(),上面已经对方差进行计算了,下面我们在descriptive_stats.py中进行函数定义
def std(data):
"""标准差"""
return sqrt(variance(data))
对函数进行测试
from collections import Counter
from pq_stats.descriptive_stats import frequency, mode, median, mean,rng, quartile, variance,std
if __name__ == '__main__':
# 方差测试
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(variance(data))
# 标准差测试
print(std(data))