python数据分析的三大神器 numpy pandas matplotlib
0.热身任务
用随机的方式生成5个学生3门课程的(百分制)成绩,保存在一个嵌套列表中。
【学生的名字和课程的名称自行拟定】
```python
[[90,98,75],
[85,100,92],
[65,76,55],
[90,80,70],
[92,88,79]]
```
1.统计每个学生的平均分。
2.统计每门课的最高分、最低分和标准差。
3.按学生平均分从高到低输出学生的成绩信息。
补充:总体方差:$ \sigma^{2} = \frac{1}{N} \sum_{i=1}^{N}(x_{i} - \mu)^{2} $
标准差:$ \sigma = \sqrt{\frac{1}{N} \sum_{i=1}^{N}(x_{i} - \mu)^{2}} $
# 随机生成分数
import random
names = ["祝蔚兰","王茂城","尹亮","周美玲","刘炽"]
courses = ["语文","数学","英语"]
scores = [[random.randrange(60,101) for _ in range(3)] for _ in range(5)] # 匿名函数
# print(scores)
# [[98, 75, 71], [69, 93, 71], [92, 88, 78], [95, 70, 86], [60, 62, 70]]
# 将计算的公式放在函数中
# 求平均值
def mean(nums):
return sum(nums)/len(nums)
# 求方差
def var(nums):
mean_num = mean(nums)
return mean([(x - mean_num)**2 for x in nums])
# 求标准差
def stddev(nums):
return var(nums)**0.5
import statistics as stats # numpy自带的数学公式方法
# 1.统计每个学生的平均分。(enumerate可以用来遍历获取元素和下标,详情可以见循环笔记)
for i,name in enumerate(names):
print(f'{name}的平均分:{stats.mean(scores[i]):.1f}分')
祝蔚兰的平均分:81.3分
王茂城的平均分:77.7分
尹亮的平均分:86.0分
周美玲的平均分:83.7分
刘炽的平均分:64.0分
#2.统计每门课的最高分、最低分和标准差。
for j,course in enumerate(courses):
temp = [scores[i][j] for i in range(len(names))] #较长重复的代码可以用变量保存
print(f'{course}的最高分:{max(temp)}分')
print(f'{course}的最低分:{min(temp)}分')
# print(f'{course}的标准差:{stddev(temp)}')
#使用python内置函数
print(f'{course}的标准差:{stats.pstdev(temp)}')
语文的最高分:98分
语文的最低分:60分
语文的标准差:15.328405005087777
数学的最高分:93分
数学的最低分:62分
数学的标准差:11.429785649783637
英语的最高分:86分
英语的最低分:70分
英语的标准差:6.11228271597445
# 3.按学生平均分从高到低输出学生的成绩信息。
scores_dict = {name:temp for name,temp in zip(names,scores)}
#zip压缩
sorted_keys = sorted(scores_dict,key=lambda x:sum(scores_dict[x]),reverse=True)
print('姓名\t语文\t数学\t英语')
for key in sorted_keys:
verbal,math,english = scores_dict[key]
print(f'{key}\t{verbal}\t{math}\t{english}')
姓名 语文 数学 英语
尹亮 92 88 78
周美玲 95 70 86
祝蔚兰 98 75 71
王茂城 69 93 71
刘炽 60 62 70
1.理解三大神器
1.numpy——封装了多维数组(ndarray类型)以及操作数据的函数和方法。
2.pandas【panel data set】——底层使用numpy保存和处理数据,封装了做数据分析需要的数据类型、方法、函数。
3.matplotlib——封装了绘制统计图表需要的类型、方法、函数。
1.1 numpy
# 使用魔法指令安装数据分析的三大神器
%pip install numpy pandas matplotlib openpyxl
# 导入库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
注意:可以根据查看版本看是否安装成功
np.__version__
pd.__version__
# 创建一个数组对象
scores = np.array(scores)
scores
```array([[81, 61, 81],
[84, 82, 90],
[84, 64, 83],
[69, 83, 91],
[71, 82, 78]])```
#查看数据类型
type(scores)
#numpy.ndarray
#每个学生的平均分(沿着1轴求平均)
# round(1)保留一位小数
scores.mean(axis=1).round(1)
#78.93333333333334
# 每门课的最高分(沿着0轴找最大)
scores.min(axis=0)
# 每门课的最低分(沿着0轴找最小)
scores.max(axis=0)
# 标准差
scores.std(axis=0)
1.2 pandas
# 查看分数dataframe
df = pd.DataFrame(scores,columns=courses,index=names)
df
df["平均分"]=df.mean(axis=1).round(1)
df
df.max()
df.min()
# ddof=0不要做自由度校正
df.std(ddof=0)
1.2.1 写入文件
#将数据写入excel文件
df.to_excel("成绩表.xlsx")
# 将数据写入csv
df.to_csv("成绩表.csv")
1.2.2 画图
# parameter
# 配置参数
plt.rcParams['font.sans-serif'].insert(0, 'SimHei')
plt.rcParams['axes.unicode_minus'] = False
# 画图 kind画图的;类型
plt.figure(figsize = (8,4),dpi=200) # 定制画布,8,4英寸,dpi像素度200最合适
#df.plot(kind = "bar",figsize = (8,4))
df.plot(ax=plt.gca(),kind = "bar",y=courses) # 先获取当前的坐标系 ax=plt.gca()获取当前画布
#df.plot(kind = "barh")横着展示
plt.legend(loc='lower right') # 图标右下角显示
plt.xticks(rotation=0) # 横轴刻度
plt.savefig('01.png') # 保存图片
plt.show()
补充:
判断是否是衬线字体:就是看有没有笔锋
2.Numpy详解
numpy的核心是名为”ndarray“的数据类型,它代表多维数组,封装了操作数据的运算和方法。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'].insert(0, 'SimHei') #字体
plt.rcParams['axes.unicode_minus'] = False #坐标轴负号正常显示
2.1创建数组对象
#方法一:通过array的函数将list转化成数组对象
array1 = np.array([1,2,3,4,5],dtype='i8')
array1
# 查看类型
type(array1)
# 二维数组 -将列表转化为数组
array2 = np.array([[1,2,3,4,5],[6,7,8,9,10]])
array2
# 方法二:通过arange函数指定范围和跨度创建数组对象
array3 = np.arange(1,100,2) # 2相当于步长
array3
# 方法三:通过linspace函数生成等差数列的数组
array4 = np.linspace(-5,5,10) # 取-5到5之间的十个元素
array4
# 方法四:通过logspace函数生成等比数列的数组
array5 = np.logspace(1,10,base=2,num=10) # base的值默认为10,num是取多少个数
# 从2的一次方到2的十次方取十个等比数列
array5
#注意:等⽐数列的起始值是2的一次方,等⽐数列的终⽌值是2的十次方,num是元素的个数,base就是底数。
# 方法五:通过fromstring函数从字符串中获取数据创建数组对象
array6 = np.fromstring("1,2,3",sep=",",dtype="i8") #类型为8个字节的整数
array6
#方法六: 读文件方法:fromfile从文件中读取数据创建数组对象
array8 = np.fromfile("res/prime.txt",dtype="i8",sep="\n")
array8
# 方法七:通过fromiter函数从迭代器中获取数据创建数组对象
array9 = np.fromiter(gen,dtype="i8")
array9
# 方法八:生成随机元素创建数组对象
array11 = np.random.randint(1,100,size = 20) # 1_100之间的随机数,取20个
array11
array12 = np.random.randint(1,100,size=(5,4)) # 1_100之间的随机数,取五行四列
array12
array13 = np.random.random(20) # 随机20个小数
# array13 = np.random.random(20) * 100 # 随机20个100以内的整数
# array13 = np.random.random(size = (5,3)) #随机五行三列的数
array13
# 正态分布
array14 = np.random.normal(0,1,size = 5000)
array14
#画正态分布的图
plt.hist(array14,bins=10,density=True)
plt.show()
# 二项分布
import math
for k in range(0,11):
print(k,math.comb(10,k) * 0.5 ** 10)
# 二项分布随机数
array15 = np.random.binomial(10,0.5,size = 1000)
#画二项分布图
plt.hist(array15,bins=10,density=True)
plt.show()
#方法九:通过ones函数创建全1的数组对象
array16 = np.ones((1,0))
array16
#方法十:通过zeros函数创建全0的数组对象
array17 = np.zeros(10)
array17
#方法十一:通过full函数制定一个值创建数组对象
array18 = np.full((5,3),100)
array18
# 方法十二:通过eye函数创建单位矩阵
array19 = np.eye(5)
array19
# 方法十三:加载图片可以创建三维数组对象 - image
array20 = plt.imread("res/1.jpg")
array20
案例:
# 案例:将100以内的质数输出到一个文件中
import os
def is_prime(num):
for i in range(2, int(num ** 0.5) +1):
if num % i == 0:
return False
return True
if not os.path.exists("res"): #创建文件夹
os.makedirs("res")
with open("res/prime.txt","w") as file: #写入文件
for num in range(2,100):
if is_prime(num):
file.write(str(num) + "\n") # \n换行符
# print(num,file=file) # 也可以使用print,重定向
#读文件方法1:
with open('res/prime.txt',"r") as file:
array7 = np.fromstring(file.read(),sep="\n",dtype="i8") #需要指定分隔符sep="\n"
array7
# 读文件方法2:fromfile从文件中读取数据创建数组对象
array8 = np.fromfile("res/prime.txt",dtype="i8",sep="\n")
array8
# 迭代器——实现了迭代器协议的对象,迭代器协议是两个魔术方法:__iter__/__next__
# 生成器是迭代器的语法简化版本
def fib(n):
a,b = 0,1
for _ in range(n):
a,b = b,a +b
yield a
gen = fib(40)
gen
2.2数组对象属性
# 数组的形状
array1.shape
# 数组的元素个数
array20.size
# 数组的维度
array20.ndim
# 数据元素的数据类型
array20.dtype
# 数组元素占用内存空间的大小
array20.itemsize
# 整个数组占用内存空间的大小
array20.nbytes
2.3数组对象的索引
2.3.1普通索引
# 一维
array21 = np.random.randint(1,100,10)
array21
array21[0] #取第一个数
array21[-10] #负向取第一个数
array21[0] = 99 # 将第一个数重新赋值
# 二维
array22 = np.random.randint(60,101,(5,3))
array22
array22[0] # 取第一行
array22[0][0] # 取第一行第一个数
array22[0,0] # 取第一行第一个数
array22[3,2] # 取第四行第三个数
array22[-2,-1] #正向和负向都是可以的
array22[3,2]=100 # 将第四行第三个数重新赋值
2.3.2花式索引
用列表或数组充当数组的索引
array21[[2,4,5,-1,9,-8]] #列表里面有列表,相当于是取第三,第五,第六等个数
array21[np.arange(5)] # 前五个元素充当新的数组
array22[[1,2]] #取得是第2,3行
array22[[1,2],[0,2]] # 取的是第2行的第一个元素,第3行的第三个元素
array22[[1,2,-1],[0,2,-2]] # 取的是第2行的第一个元素,第3行的第三个元素,最后一行的倒数第二个元素
2.3.3布尔索引
用保存布尔值的数组或列表充当数组的索引
array21
# array([99, 28, 85, 91, 32, 1, 71, 5, 23, 93])
#将随机出来的数,大于60的为TRUE,小于60的为FALSE
array21[[True,False,True,True,False,False,True,False,False,True]]
array21 >= 60
# array([ True, False, True, True, False, False, True, False, False,True])
array21[array21 >= 60]
#array([99, 85, 91, 71, 93])
#与或非
# 一维
# & -- 取两个数组对应的布尔值做and运算
array21[(array21 >= 60) & (array21 % 2 == 0)]
# | -- 取两个数组对应的布尔值做or运算
array21[(array21 >= 60) | (array21 % 2 == 0)]
# ~ -- 取两个数组对应的not运算
array21[~(array21 >= 60 | array21 % 2 == 0)]
#二维
array22
# array([[ 89, 70, 64],
[ 81, 71, 86],
[ 91, 97, 60],
[ 95, 67, 100],
[ 96, 97, 84]])
array22 >= 80
# array([[ True, False, False],
[ True, False, True],
[ True, True, False],
[ True, False, True],
[ True, True, True]])
#不取false的话那就会导致维度坍塌,多维变一维
array22[array22 >= 80]
#array([ 89, 81, 86, 91, 97, 95, 100, 96, 97, 84])
2.3.3 切片索引
# 一维
array21
# array([99, 28, 85, 91, 32, 1, 71, 5, 23, 93])
array21[2:7]
#array([85, 91, 32, 1, 71])
#二维
array22
#array([[ 89, 70, 64],
[ 81, 71, 86],
[ 91, 97, 60],
[ 95, 67, 100],
[ 96, 97, 84]])
array22[1:3,:2] # 取的是第二行到第三行的第一二列
#array([[81, 71],
[91, 97]])
array22[::2,::2] # 取得第一行和第三行和第五行的第一三列
#array([[89, 64],
[91, 60],
[96, 84]])
#三维:对图片这种三维度的切片处理效果
#图片三维:红,绿,蓝
# 读取图片
p_image = plt.imread("res/1.jpg")
p_image.shape
plt.imshow(p_image)
plt.imshow(p_image[:,:,0]) # 灰度图
plt.imshow(p_image[::-1]) # 图片翻转,图片垂直镜像
plt.imshow(p_image[:,::-1]) # 图片水平镜像
plt.imshow(p_image[:,:,::-1]) #颜色翻转,交换红色和蓝色的值
plt.imshow(p_image[::25,::25]) # 丢失信息,降采样
# 补充:
# 专门处理图像的三方库
from PIL import Image
from PIL import ImageFilter
Image.fromarray(p_image[:,:,0]).show()
Image.fromarray(p_image).filter(ImageFilter.EMBOSS).show() # 给图片加滤镜
#随机产生图片
plt.imshow(np.random.randint(0,256,(100,100,3)))
2.4 数组对象的方法
2.4.1获取描述统计信息
看数据的离散程度
array21
#array([99, 28, 85, 91, 32, 1, 71, 5, 23, 93])
# 算术平均
array21.mean()
np.mean(array21) # 52.8
# 中位数
np.median(array21)
#50%分位数,其中 quantitle 函数的第⼆个参数设置为0.5表示计算50%分位数,也就是中位数
np.quantile(array21,0.5)
np.quantile(array21,[0.25,0.5,0.75])
# Q1_下四分位数
# Q3_上四分位数
# Q2_二分之一
# IQR = Q3-Q1
#排序
np.sort(array21)
# 最大值
array21.max()
np.amax(array21)
## 最小值
array21.min()
np.amin(array21)
# 极差(全距) —— peak to peak
array21.ptp()
np.ptp(array21)
# 四分位距离(IQR)距离越集中,箱子越小,箱子越大,数据越分散
q1,q3 = np.quantile(array21,[0.25,0.75])
q3-q1
# 总体方差
array21.var()
np.var(array21)
# 样本方差
# ddof默认值为0,不进行自由度矫正
np.var(array21,ddof=1)
array21.var(ddof=1)
# 总体标准差
array21.std()
np.std(array21)
#样本标准差
array21.std(ddof=1)
np.std(array21,ddof=1)
# 变异系数:【标准差/均值】变异系数越大,波动越大,变异系数越小,波动越小
array21.std()/array21.mean()
array22
#array([[ 89, 70, 64],
[ 81, 71, 86],
[ 91, 97, 60],
[ 95, 67, 100],
[ 96, 97, 84]])
array22.mean(axis=0) #按照列来求
#array([90.4, 80.4, 78.8])
array22.mean(axis=1).round(2)
array22.max(axis=0)
array22.max(axis=1)
array22.std(axis=0)
array22.std(axis=1)
# 箱线图
# 一维
plt.boxplot(array21,showmeans= True)
plt.show()
# 二维
# 二维,沿着0轴画
plt.boxplot(array22,showmeans= True)
plt.show()
# 直箱图
plt.hist(array21,bins=10)
案例:
channel_x = np.array([225, 249, 282, 235, 221, 239, 254, 225, 265, 255, 268, 230, 289, 219])
channel_y = np.array([146, 130, 331, 382, 369, 127, 374, 130, 272, 369, 173, 206, 112, 335])
channel_z = np.array([228, 124, 258, 198, 190, 295, 209, 255, 281, 257, 291, 290, 305, 275])
#样本方差
print(channel_x.var(ddof = 1))
print(channel_y.var(ddof = 1))
print(channel_z.var(ddof = 1))
# 集中趋势
print(channel_x.mean())
print(channel_y.mean())
print(channel_z.mean())
# 二维数组
channels = np.array([[225, 249, 282, 235, 221, 239, 254, 225, 265, 255, 268, 230, 289, 219],
[146, 130, 331, 382, 369, 127, 374, 130, 272, 369, 173, 206, 112, 335],
[228, 124, 258, 198, 190, 295, 209, 255, 281, 257, 291, 290, 305, 275]])
channels
# 多维需要指定axis的值
channels.mean(axis = 1)
channels.var(axis = 1,ddof =1)
# 交换轴
channels.swapaxes(0,1)
# 转置
channels.transpose()
#箱线图
plt.boxplot(channels.swapaxes(0,1),showmeans=True)
plt.show()
# 第二组波动最大,阔以优化掉
补充:
from scipy import stats
print(np.mean(array21)) # 算术平均值
print(stats.gmean(array21)) # ⼏何平均值
print(stats.hmean(array21)) # 调和平均值
print(stats.tmean(array21, [10, 90])) # 去尾平均值
print(stats.variation(array21)) # 变异系数
print(stats.skew(array21)) # 偏态系数
print(stats.kurtosis(array21)) # 峰度系数
补充:魔法指令
#### 魔法指令——将以上代码存入prep.py中
%save prep.py
#### 魔法指令——将执行的代码加载代码到单元格,需要在次执行一遍
%load prep.py
# 魔法指令——配置matplotlib后台渲染矢量图
%config InlineBackend.figure_format = 'svg'
# 使用魔法指令安装数据分析的三大神器
%pip install numpy pandas matplotlib openpyxl