Matplotlib是一个Python 2D绘图库,可以生成各种硬拷贝格式和跨平台交互式环境的图形。Matplotlib可用于Python脚本,Python和IPython shell,Jupyter笔记本,Web应用程序服务器等。pyplot模块提供类似MATLAB的接口,特别是与IPython结合使用时。 对于高级用户,你可以通过面向对象的界面或通过MATLAB用户熟悉的一组函数完全控制线型,字体属性,轴属性。
一幅图的结构如下:
a = pandas.DataFrame(np.random.rand(4,5), columns = list('abcde'))
a = a.values
#导入依赖库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
'''
'''
#然后依次调用np.arange,np.zeros,np.pi,plt.figure,plt.plot,plt.show等。使用pyplot接口创建图像,然后使用对象方法
#1、生成画图所需数组数据,数据可以直接导入或者是算法,函数的输出等
x = np.arange(0, 10, 0.2)
y = np.sin(x)
#2、创建窗口,子图对象
fig, ax = plt.subplots()
#3、在创建的对应Axes对象(相当于画布)上面利用一些方法进行作画
ax.plot(x, y)
#4、对图进行修饰,使其变的美观(添加子图,注释,文本,等等)
#x轴标签
ax.set_xlabel('y轴', fontsize=15)
#y轴标签
ax.set_ylabel('x轴', fontsize=15)
#标题
ax.set_title('python可视化')
#添加图例
ax.legend()
#添加网格
ax.grid(True)
#5、脚本显示图片
plt.show()
原图如下:
复现的脚本如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#导入依赖库
import xlrd
import numpy as np
import pandas as pd
# print(pd.__version__)
import matplotlib.pyplot as plt
# 这两句代码用来正确显示图中的中文字体,后续都要加上
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
#利用pandas读入大车的单车源强数据
df = pd.read_excel('C:/Users/13109/desktop/单车源强数据2.xlsx','大车',na_vlues=['NA'])
'''
绘图相关
'''
#数据预处理,使用pandas处理
df = df.iloc[:,2:6]
df = df.dropna(how='any')#删除任何带有空值的行
df['声压级(mean)'] = (df['Soundlevel ']+df['Soundlevel_2'])/2
df['大车平均车速(mean)'] = (df['Rear_speed']+df['Radar_speed '])/2
#将pandas的数据帧转化为np数组
dfnp = df.values
x = dfnp[:,5]
x1 = np.log10(x)
y = dfnp[:,4]
x2 = np.linspace(30,110,898)
y1 = 22+36.32*np.log10(x2)
y2 = y1-5
y3 = y1+5
#窗口,对象的生成
fig = plt.figure() #开启一个窗口,同时设置大小,分辨率
ax1 = fig.add_subplot(1,2,1) #通过fig添加子图,参数:行数,列数,第几个。
#绘制第一个子图
# fig, ax1 = plt.subplots()
line1 = ax1.scatter(x, y, label='测试数据',color='#44cef6',s=10)
line2 = ax1.plot(x2,y1,label='规范拟合数据',color='#ffa400',alpha=0.5, linewidth = '5')
line3 = ax1.plot(x2,y2,label='规范拟合数据-5db',color='#00e09e',linestyle='--', linewidth = '5')
line4 = ax1.plot(x2,y3,label='规范拟合数据+5db',color='#493131',linestyle=':', linewidth = '5')
#x轴标签
ax1.set_xlabel('大车车速(km/h)', fontsize=15)
#y轴标签
ax1.set_ylabel('声压级(DB)', fontsize=15)
#标题
ax1.set_title('这是一张大车车速与声压级的关系图')
#添加图例
ax1.legend()
#添加网格
ax1.grid(True)
#在Axes的任意位置添加文本
ax1.text(30,100,'子图',fontsize=14,style='italic',color='red')
#可选箭头在任意位置添加注释 Axes
ax1.annotate(r'$L_(ol)=22+36.32\log(V_l)$', xy=(38, 79), xytext=(45, 73),
arrowprops=dict(facecolor='black', shrink=0.01))
##添加一个子图,rect=[左, 下, 宽, 高],是使用的绝对布局,不和以存在窗口挤占空间
axes1 = plt.axes([.2, .75, .05,.1], facecolor='y')
#在子图上画图
axes1.plot(x2,y1)
#绘制第二个子图
ax2 = fig.add_subplot(1,2,2) #通过fig添加子图,参数:行数,列数,第几个。
ax2.scatter(x1, y, label='测试数据',color='#44cef6',s=10)
ax2.plot(np.log10(x2),y1,label='规范拟合数据',color='#ffa400',alpha=0.5, linewidth = '5')
ax2.plot(np.log10(x2),y3,label='规范拟合数据+5db',color='#493131',linestyle=':', linewidth = '5')
#x轴标签
ax2.set_xlabel('大车车速(log(V))', fontsize=15)
#y轴标签
ax2.set_ylabel('声压级(DB)', fontsize=15)
#标题
ax2.set_title('这是一张大车车速与声压级的关系图')
#添加图例
ax2.legend()
#添加网格
ax2.grid(True)
#在Axes的任意位置添加文本
# ax1.text(30,100,'子图',fontsize=14,style='italic',color='red')
#可选箭头在任意位置添加注释 Axes
ax2.annotate(r'$L_(ol)=22+36.32\log(V_l)$', xy=(1.6, 80), xytext=(1.6, 72),
arrowprops=dict(facecolor='black', shrink=0.01))
##再次添加一个子图,rect=[左, 下, 宽, 高],是使用的绝对布局,不和以存在窗口挤占空间
axes2 = plt.axes([.60, .75, .05,.1], facecolor='y')
#在子图上画图
axes2.plot(np.log10(x2),y1)
plt.show()
plt.close('all')
复现结果打印输出:
需要复现的曲线拟合如下:
step1:首先数据预处理过程中的异常值检测与处理(本文直接删除异常值);
step2:数据分组,并且预处理实现声压级进行能量平均(声压级能量平均算法);
step3: 对预处理之后的样本数据进行一次拟合,并且绘制相关图像;
箱线图基本原理:异常值被定义为大于QU+1.5IQRQU+1.5IQR或小于QL−1.5IQRQL−1.5IQR的值。QUQU是上四分位数,表示全部观察值中有1/4的数据比他大,QLQL是下四分位数,表示全部数据中有1/4的数据比他小。IQR是四分位间距,是QUQU和QLQL的差,其间包含了观察值的一半。
基本的箱线图:
实现的脚本如下:
#依赖导入
import pandas as pd
import matplotlib.pyplot as plt
# 这两句代码用来正确显示图中的中文字体,后续都要加上
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
#读入大车的单车源强数据
df = pd.read_excel('C:/Users/13109/desktop/单车源强数据2.xlsx','大车',na_vlues=['NA'])
#数据初始化,使用pandas处理
df = df.iloc[:,2:6]
df = df.dropna(how='any')#删除任何带有空值的行
df['声压级(mean)'] = (df['Soundlevel ']+df['Soundlevel_2'])/2
df['大车平均车速(mean)'] = (df['Rear_speed']+df['Radar_speed '])/2
#实验样本索引查看
df1 = df.iloc[:,4:6]
#实验数据导出
# df1.to_csv('C:/Users/13109/desktop/df1.csv',encoding="gb2312")
#绘制原始的箱线图,并返回异常值字典
p = df1.plot.box(sym='r+',return_type = 'dict')
!下面的代码和上面的是一个脚本)
'''
异常值处理的常用方法
删除:对于数据量比较小的数据,删除会造成样本不足,减少有用信息。
视为缺失值:用均值、插值等方法进行填补
不处理:将缺失值视为一种特征,统计其缺失个数等信息作为缺失特征。
'''
#大车平均声压级异常数据的获取
x = p['fliers'][0].get_xdata()
y = p['fliers'][0].get_ydata()
y.sort() #从小到大排序
print(y)
#在箱线图上绘制注释异常值注释
for i in range(len(x)):
# print(i)
if y[i]>97:
plt.annotate(y[i], xy = (x[i],y[i]), xytext=(x[i]+0.05,y[i]))
#这里对声压级样本的异常值数据进行删除
'''
删除异常数据样本的第一种方法,双重循环遍历方法,该方法运行效率较低
(用于删除声压级异常样本)
'''
y = list(set(y))#用于数组排序之后删除重复数据
j=0
for i in range(0,897):
for k in range(len(y)):
# if df1.iloc[:, 0][i] >= 96.8 or df1.iloc[:,0][i] <= 76.55:
if y[k] == df1.loc[i,['声压级(mean)']].values[0]:
j += 1
df1.drop(index=i,inplace=True)
break
print('声压级标签异常值一共删除了'+str(j)+'行异常值数据')
'''
删除异常数据样本的第二种方法,利用直接选择索引法,简单实用,pandas还要好好学
'''
def delete_v(y,df1):
j1 = 0
for k in range(len(y)):
j1 += 1
df1.drop(index=df1[df1.iloc[:,1].isin([y[k]])].index[0], inplace = True)
return df1,j1
y1 = p['fliers'][1].get_ydata()
y1.sort() # 从小到大排序
print(y1)
df1,j1 = delete_v(y1,df1)
print('大车平均车速标签异常值一共删除了'+str(j1)+'行异常值数据')
#重建索引,并重新绘制删除异常样本之后的箱线图
df1.index=list(range(len(df1)))
df1.plot.box(sym='r+',return_type = 'dict')
print(df1)
#剔除异常值之后的样本文件导出
# df1.to_excel('C:/Users/13109/desktop/df1.xlsx',encoding="gb2312")
plt.show()
打印输出结果:
[71.9 74.6 74.9 75. 75.25 76.05 76.45 76.55 76.55 97. 97.15 99.25
99.25]
声压级标签异常值一共删除了13行异常值数据
[ 30. 31.65 32.65 33.95 34.25 34.5 91. 91. 92.05 92.55
93. 93.5 94.5 95.75 96. 97. 97. 99.75 99.75 105.
108. ]
大车平均车速标签异常值一共删除了21行异常值数据
声压级(mean) 大车平均车速(mean)
0 91.50 77.35
1 95.05 67.85
2 92.80 65.80
3 88.20 63.80
4 84.15 49.00
.. ... ...
859 91.55 67.00
860 81.95 64.00
861 86.60 65.00
862 81.00 67.00
863 86.50 55.00
[864 rows x 2 columns]
异常值删除之后的箱线图绘制结果如下:
实现的脚本如下:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
# 这两句代码用来正确显示图中的中文字体,后续都要加上
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
#读入剔除异常值之后的数据
df1 = pd.read_excel('C:/Users/13109/desktop/df1.xlsx','Sheet1',na_vlues=['NA'])
'''
数据预处理,从而得到拟合样本
使得测试数据更加具有代表性,将车速以0.1km/h为间隔进行分区,
在该区域内的车速进行算术平均得到 ,并将该区域内对应的声压级进行能量平均
'''
quartiles = pd.cut(df1['大车平均车速(mean)'],250)#数据分组,使用pandas.cut实现分位数分组
# print(quartiles[:])
df2 = df1.groupby(quartiles)
df11 = df2['大车平均车速(mean)'].mean()
df3 = df2['声压级(mean)']
def top(df):
mean=0
for i in range(len(df)):
mean=10**(0.1*df.values[i])+mean
if len(df) == 0:
return 0
else:
x = mean/(len(df))
y = 10*(math.log(x,10))
return y
df12=df3.apply(top)#使用apply方法,使用自定义top函数来对分组数据系列进行聚合
#把两个series变量重新组合成数据帧dataframe格式变量
df = pd.DataFrame({
'大车平均车速(mean)': df11,
'声压级(mean)': df12})
df = df.dropna(how='any')
df.index = range(len(df))
#删除车速小于55,但是声压级大于90的异常值(人为删除)
# df = df.drop(index=df[df['大车平均车速(mean)'] > 50].index[0], inplace = True)
# df.drop(index=df[df.iloc[50:len(df),1]>90].index, inplace=True)
df.drop(index=df[(df['大车平均车速(mean)']<55) & (df['声压级(mean)']>90)].index, inplace = True)
## 数据预处理完毕,进而获取能量平均拟合数据等进行绘制图像
x = df.values[:,0]
y = df.values[:,1]
x2 = np.linspace(40,95,190)
y1 = 22+36.32*np.log10(x2)
x0 = np.log10(x)
#对数据进行一次多项式拟合
z1 = np.polyfit(x0, y, 1)#用一次多项式拟合
p1 = np.poly1d(z1)
print(p1) #在屏幕上打印拟合多项式
yvals=p1(x0)#也可以使用yvals=np.polyval(z1,x)
#绘制图形
fig = plt.figure() #开启一个窗口,同时设置大小,分辨率
ax1 = fig.add_subplot(1,1,1) #通过fig添加子图,参数:行数,列数,第几个。
# fig, ax1 = plt.subplots()
line1 = ax1.scatter(x, y, label='能量平均数据',color='#44cef6',s=10)
line2 = ax1.plot(x2,y1,label='规范拟合曲线',color='#ffa400',alpha=0.5, linewidth = '3')
line3=ax1.plot(x, yvals, color='#493131',label='能量平均数据拟合曲线',linewidth = '3')
#x轴标签
ax1.set_xlabel('大车车速(km/h)', fontsize=15)
#y轴标签
ax1.set_ylabel('声压级(DB)', fontsize=15)
#标题
ax1.set_title('大型车能量平均拟合曲线与规范对比')
#添加图例
ax1.legend()
#添加网格
# ax1.grid(True)
#在Axes的任意位置添加文本
ax1.text(30,100,'子图',fontsize=14,style='italic',color='red')
#可选箭头在任意位置添加注释 Axes
ax1.annotate(r'$L_(ol)=71.43+8.806\log(V_l)$', xy=(80, 88), xytext=(71, 82),
arrowprops=dict(facecolor='black', shrink=0.01))
ax1.annotate(r'$L_(ol)=22+36.32\log(V_l)$', xy=(46.1, 82.4), xytext=(53, 79),
arrowprops=dict(facecolor='black', shrink=0.01))
plt.show()