0. 引入案例
:
names = ['孙悟空', '李元芳', '白起', '狄仁杰', '达摩'] courses = ['语文', '数学', '英语'] import random scores = [[random.randrange(60, 101) for _ in range(3)] for _ in range(5)] print(scores) # [[100, 97, 76], [91, 79, 66], [84, 78, 71], [87, 81, 96], [73, 71, 88]] def mean(nums): """求均值""" return sum(nums) / len(nums) def variance(nums): """求方差""" mean_value = mean(nums) return mean([(num - mean_value) ** 2 for num in nums]) def stddev(nums): """求标准差""" return variance(nums) ** 0.5 # 统计每个学生的平均考试成绩 for idx, name in enumerate(names): temp = scores[idx]
avg_score = mean(temp)
print(f'{
name}考试平均分为:{
avg_score:.1f}分')
''' 孙悟空考试平均分为:91.0分 李元芳考试平均分为:78.7分 白起考试平均分为:77.7分 狄仁杰考试平均分为:88.0分 达摩考试平均分为:77.3分 '''
# 统计每门课的最高分、最低分、标准差
for idx, course in enumerate(courses):
temp = [scores[i][idx] for i in range(len(names))]
max_score, min_score = max(temp), min(temp)
print(f'{
course}成绩最高分:{
max_score}分')
print(f'{
course}成绩最低分:{
min_score}分')
print(f'{
course}成绩标准差:{
stddev(temp):.1f}分')
''' 语文成绩最高分:100分 语文成绩最低分:73分 语文成绩标准差:8.8分 数学成绩最高分:97分 数学成绩最低分:71分 数学成绩标准差:8.6分 英语成绩最高分:96分 英语成绩最低分:66分 英语成绩标准差:11.1分 '''
# 将学生及其考试成绩以行的方式输出(按平均分从高到低排序)
results = {
name: temp for name, temp in zip(names, scores)}
sorted_keys = sorted(results, key=lambda x: mean(results[x]), reverse=True)
for key in sorted_keys:
verbal, math, english = results[key]
print(f'{
key}:\t{
verbal}\t{
math}\t{
english}')
''' 孙悟空: 100 97 76 狄仁杰: 87 81 96 李元芳: 91 79 66 白起: 84 78 71 达摩: 73 71 88 '''
1. 感性认知
Python数据分析三大神器
- Numpy - Numerical Python - ndarray - 保存数据,完成批量的运算和处理
- pandas - Panel Data Set - Series(一维数据) / DataFrame(二维数据) - 封装了数据分析需要的各种方法
- matplotlib - 绘制统计图表
1.1 Numpy
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 将list处理成ndarray对象
scores = np.array(scores)
print(scores)
''' array([[100, 97, 76], [ 91, 79, 66], [ 84, 78, 71], [ 87, 81, 96], [ 73, 71, 88]]) '''
# 查看数据类型
type(scores)
# numpy.ndarray
# 按横向(学生)求平均值
np.round(scores.mean(axis=1), 1)
# array([91. , 78.7, 77.7, 88. , 77.3])
# 按竖向(学科)求最高分、最低分、标准差
scores.max(axis=0)
# array([100, 97, 96])
scores.min(axis=0)
# array([73, 71, 66])
np.round(scores.std(axis=0), 1)
# array([ 8.8, 8.6, 11.1])
1.2 pandas
scores_df = pd.DataFrame(data=scores, columns=courses, index=names)
scores_df
效果图:
# 计算平均分
np.round(scores_df.mean(axis=1), 1)
''' 孙悟空 91.00000 李元芳 78.66875 白起 77.66875 狄仁杰 88.00000 达摩 77.33125 dtype: float64 '''
# 添加平均分列到表中
scores_df['平均分']= scores_df.mean(axis=1)
scores_df
效果图:
# 写入Excel文件
scores_df.to_excel('考试成绩.xlsx')
# 改plt字体
plt.rcParams['font.sans-serif'] = ['KaiTi']
plt.rcParams['axes.unicode_minus'] = False
# 将生成的图表改成矢量图
%config InlineBackend.figure_format='svg'
# 生成柱状图
scores_df.plot(kind='bar', y=['语文','数学','英语'])
# 旋转横轴的刻度
plt.xticks(rotation=0)
# 保存图表
plt.savefig('成绩柱状图.svg')
# 显示图表
plt.show()
效果图:
# 求学科最高分、最低分、平均分
scores_df.max()
''' 语文 100.0 数学 97.0 英语 96.0 平均分 91.0 dtype: float64 '''
scores_df.min()
''' 语文 73.0 数学 71.0 英语 66.0 平均分 77.3 dtype: float64 '''
scores_df.std()
''' 语文 9.874209 数学 9.602083 英语 12.361230 平均分 6.461656 dtype: float64 '''
2. Numpy
2.1 创建一维数组
# 方法一:通过array函数将list处理成ndarray对象
array1 = np.array([1, 2, 10, 20, 100])
array1
# array([ 1, 2, 10, 20, 100])
type(array1)
# numpy.ndarray
# 方法二:指定一个范围创建数组对象
array2 = np.arange(1, 100, 2)
array2
''' array([ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33,35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99]) '''
# 方法三:指定范围和元素的个数创建数组对象
array3 = np.linspace(-5, 5, 101)
array3
''' array([-5. , -4.9, -4.8, -4.7, -4.6, -4.5, -4.4, -4.3, -4.2, -4.1, -4. , -3.9, -3.8, -3.7, -3.6, -3.5, -3.4, -3.3, -3.2, -3.1, -3. , -2.9, -2.8, -2.7, -2.6, -2.5, -2.4, -2.3, -2.2, -2.1, -2. , -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1. , -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4. , 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5. ]) '''
# 方法四:用随机生成元素的方法创建数组对象
# 随机小数
array4 = np.random.random(10)
array4
''' array([0.74861994, 0.80263292, 0.54287411, 0.99088428, 0.27465232, 0.4421258 , 0.34908231, 0.39729076, 0.11863797, 0.37728455]) '''
# 随机整数
array5 = np.random.randint(1, 10)
array5
# 5
# 随机正态分布
array6 = np.random.normal(0, 1, 50000)
array6
''' array([-1.24165108, -0.07314869, -1.37729185, ..., -1.00691177, 0.19568883, 0.43887128]) '''
# 生成直方图
plt.hist(array6, bins=24)
plt.show()
效果图:
2.2 创建二维数组
# 方法一:通过array函数将嵌套列表处理成二维数组 array8 = np.array(([1, 2, 3], [4, 5, 5], [7, 8, 9])) array8 ''' array([[1, 2, 3], [4, 5, 5], [7, 8, 9]]) ''' # 方法二:通过对一维数组调形变成二维数组 temp= np.arange(1, 11) array9 = temp.reshape((5, 2)) array9 ''' array([[ 1, 2], [ 3, 4], [ 5, 6], [ 7, 8], [ 9, 10]]) ''' # 方法三;通过生成随机元素创建二维数组 array10 = np.random.randint(60, 101, (5, 3)) array10 ''' array([[71, 91, 67], [95, 71, 96], [90, 91, 92], [67, 83, 74], [95, 78, 60]]) ''' # 方法四:创建全0、全1、指定值的二维数组 array11 = np.zeros((5, 4), dtype='i8') array11 ''' array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], dtype=int64) ''' array12 = np.ones((5, 4), dtype='i8') array12 ''' array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], dtype=int64) ''' array13 = np.full((5, 4), 100) array13 ''' array([[100, 100, 100, 100], [100, 100, 100, 100], [100, 100, 100, 100], [100, 100, 100, 100], [100, 100, 100, 100]]) ''' # 方法五:创建单位
矩阵 array14 = np.eye(5) array14 ''' array([[1., 0., 0., 0., 0.], [0., 1., 0., 0., 0.], [0., 0., 1., 0., 0.], [0., 0., 0., 1., 0.], [0., 0., 0., 0., 1.]]) '''
2.3 数组的索引和切片
2.3.1 普通用法
array10
''' array([[71, 91, 67], [95, 71, 96], [90, 91, 92], [67, 83, 74], [95, 78, 60]]) '''
# 取指定元素
array10[1][2]
# 96
array10[1, 2]
# 96
# 取部分元素
array10[:3, :2]
''' array([[71, 91], [95, 71], [90, 91]]) '''
总结:对多维数组的操作中,每做一次索引降一次维,而做切片不会降维。
2.3.2 特殊索引
# 花式索引(fancy index)
array2[[0, 1, 2, -3, -2, -1, -10]]
# array([ 1, 3, 5, 95, 97, 99, 81])
array10[[0, 1, 4], [0, 1, 2]]
# array([71, 71, 60])
# 布尔索引
array1[[False, True, False, True, False]]
# array([ 2, 20], dtype=uint64)
array2[array2 > 80]
# array([81, 83, 85, 87, 89, 91, 93, 95, 97, 99])
array16 = np.arange(1, 10)
array16[array16 % 2 !=0]
# array([1, 3, 5, 7, 9])
array16[(array16 > 5) & (array16 % 2 != 0)]
# array([7, 9])
array16[(array16 > 5) | (array16 % 2 != 0)]
# array([1, 3, 5, 6, 7, 8, 9])
array16[(array16 > 5) | ~(array16 % 2 != 0)]
# array([2, 4, 6, 7, 8, 9])
array10[array10 > 80]
# array([91, 95, 96, 90, 91, 92, 83, 95])
2.5 ndarray对象的方法
array1 = np.random.randint(10, 50, 10)
array1
# 求和
array1.sum
np.sum(array1)
# 求平均
array1.mean()
np.mean(array1)
# 求中位数
np.median(array1)
# 求最大值最小值
array1.max()
np.amax(array1)
array1.min()
np.amin(array1)
# 求极差(全距)
array1.ptp()
np.ptp(array1)
# 求方差
array1.var
np.var(array1)
# 求标准差
array1.std
np.std(array1)
# 求累计和
array1.cumsum()
np.cumsum(array1)
2.5.1 对上述描述性统计方法的补充说明:
2.5.2 用Excel实现上述功能
2.5.3 分位点和找异常值
def outliers_by_iqr(t_array, lower_points = 0.25, upper_points = 0.75, whis = 1.5):
"""iqr找异常值"""
q1, q3 = np.quantile(t_array, [lower_points, upper_points])
iqr = q3 - q1
return t_array[(t_array < q1 - whis * iqr)|(t_array > q3 + whis * iqr)]
# 测试
array2[-1] = 15
outliers_by_iqr(array2)
# array([15])
2.5.4 Z-score找异常值
def outliers_by_zscore(array, threshold=3):
"""Z-score判定法检测离群点"""
mu, sigma = array.mean(), array.std()
return array[np.abs((array - mu) / sigma) > threshold]
# 把数组改长点,以使500显得突兀
# repeat()(会把相同元素放在一起)和tile()(按原本的顺序重复)
temp = np.repeat(array2[:-1], 100)
# append()和insert()添加
temp = np.append(temp, array2[-1])
temp = np.insert(temp, 0, array2[-1])
temp
outliers_by_zscore(temp)
# array([500, 500])
2.6 其他方法
2.6.1 all()/any
判断数组中是否所有元素都是True/判断数组是否有True的元素。
2.6.2 astype()方法
拷贝数组,并将数组中的元素转换为指定的类型。
array5 = array3.astype(np.float64)
array5.dtype
# dtype('float64')
2.6.3 dump()和load()方法
保存数组到文件中,可以通过NumPy中的load()函数从保存的文件中家在数据创建数组。
序列化:把对象处理成字符串(str)或字节串(bytes) —> 串行化/腌咸菜
反序列化:把字符串或字节串还原成对象 —> 反串行化
-
json模块:dump / dumps / load / loads —> 通用,跨语言
-
pickle模块:dump / dumps / load / loads —> 私有协议,其他语言无法反序列化
# 保存
with open('array3', 'wb') as file:
array3.dump(file)
# 读取
with open('array3', 'rb') as file:
array6 = np.load(file, allow_pickle=True)
array6
2.6.4 fill()方法
向数组中填充指定的元素。即数组中元素全部变成指定元素。
2.6.5 flatten()方法
将多维数组扁平化成一维数组
array7 = np.arange(1, 11).reshape(5, 2)
array7
''' array([[ 1, 2], [ 3, 4], [ 5, 6], [ 7, 8], [ 9, 10]]) '''
array7.flatten('C')
# array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
array7.flatten('F')
# array([ 1, 3, 5, 7, 9, 2, 4, 6, 8, 10])
2.6.6 nonzero()方法
返回非0元素的索引
2.6.7 round()方法
对数组中的元素做四舍五入操作。
2.6.8 sort()方法
array8 = np.random.randint(1, 100, 10)
array8
# array([55, 98, 48, 98, 38, 5, 35, 36, 39, 87])
# 返回排序后的新数组
np.sort(array8)
# array([ 5, 35, 36, 38, 39, 48, 55, 87, 98, 98])
array8
# array([55, 98, 48, 98, 38, 5, 35, 36, 39, 87])
# 在原始数组上就地排序
array8.sort()
# 无返回值
array8
# array([ 8, 10, 12, 27, 28, 43, 45, 57, 65, 98])
2.6.9 transpose()和swapaxes()方法
交换数组指定的轴。
# 对于二维数组,transpose相当于实现了矩阵的转置
array7.transpose()
''' array([[ 1, 3, 5, 7, 9], [ 2, 4, 6, 8, 10]]) '''
# swapaxes交换指定的两个轴,顺序无所谓
array7.swapaxes(0, 1)
''' array([[ 1, 3, 5, 7, 9], [ 2, 4, 6, 8, 10]]) '''
2.6.10 tolist()方法
将数组转成Python中的list。不改变原数组。
array7.tolist()
# [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
2.7 其他常用函数
2.7.1 np.unique()
去重。
array9 = np.array([1,1,1,1,2,2,2,3,3,3])
array9
# array([1, 1, 1, 1, 2, 2, 2, 3, 3, 3])
np.unique(array9)
# array([1, 2, 3])
2.7.2 stack堆叠
array10 = np.array([[1,1,1], [2,2,2]])
array10
''' array([[1, 1, 1], [2, 2, 2]]) '''
array11 = np.array([[3,3,3,], [4,4,4,]])
array11
''' array([[3, 3, 3], [4, 4, 4]]) '''
# 水平方向(沿着1轴方向)的堆叠
np.hstack((array10, array11))
''' array([[1, 1, 1, 3, 3, 3], [2, 2, 2, 4, 4, 4]]) '''
# 垂直方向(沿着0轴方向)的堆叠
np.vstack((array10, array11))
''' array([[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]) '''
# 沿着指定轴堆叠并升维
np.stack((array10, array11), axis=0)
''' array([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]]) '''
np.stack((array10, array11), axis=1)
''' array([[[1, 1, 1], [3, 3, 3]], [[2, 2, 2], [4, 4, 4]]]) '''
2.7.3 concatenate合并
array12 = np.concatenate((array10, array11), axis=0)
array12
''' array([[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]) '''
array13 = np.concatenate((array10, array11), axis=1)
array13
''' array([[1, 1, 1, 3, 3, 3], [2, 2, 2, 4, 4, 4]]) '''
2.7.4 split拆分
# 垂直方向(沿着0轴方向)的拆分
np.vsplit(array12, 2)
''' [array([[1, 1, 1], [2, 2, 2]]), array([[3, 3, 3], [4, 4, 4]])] '''
np.vsplit(array12, 4)
''' [array([[1, 1, 1]]), array([[2, 2, 2]]), array([[3, 3, 3]]), array([[4, 4, 4]])] '''
# 水平方向(沿着1轴方向)的拆分
np.hsplit(array12, 3)
''' [array([[1], [2], [3], [4]]), array([[1], [2], [3], [4]]), array([[1], [2], [3], [4]])] '''
# 沿着指定轴拆分
np.split(array13, 2)
''' [array([[1, 1, 1, 3, 3, 3]]), array([[2, 2,