0. 引入案例
RIGHT Example:
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()