数据分析处理快速上手教程matplotlib+numpy+pandas(基础讲解)
文章目录
python数据挖掘
主要参考资料:
API reference — pandas 1.4.1 documentation (pydata.org)
哔哩哔哩网课
走在小路上 笔记
一、数据挖掘基础环境安装与使用
1.1 库的安装
-
pip install
-
集合到requirements.txt文件中集成安装
matplotlib==2.2.2 numpy==1.14.2 pandas==0.20.3 TA-Lib==0.4.16 技术指标库 tables==3.4.2 hdf5 jupyter==1.0.0 数据分析与展示的平台
pip install -r requirments.txt
1.2 Jupyter Notebook使用
1.2.1 Jupyter Notebook介绍
- web版的ipython
- 名字缘由ju – Julia
py – Python
ter – R
Jupiter 木星 宙斯 - 编程、写文档、记笔记、展示
- 文件是.ipynb
1.2.2 为什么使用Jupyter Notebook?
- 画图方面的优势
- 数据展示方面的优势
1.2.3 Jupyter Notebook的使用-helloworld
-
界面启动、创建文件
在终端输入jupyter notebook / ipython notebook
注意可以是pycharm中的终端,也可以直接是windows终端,不过要将路径调整到你的项目路径
如图
然后点击网址即可
快速上手的方法:
快捷键
运行代码 shift + enter -
cell操作
cell:一对In Out会话被视作一个代码单元,称为cell
编辑模式:enter 鼠标直接点
命令模式:esc 鼠标在本单元格之外点一下
快捷键操作
执行代码,并跳转到下一单元:shift + Enter
执行本单元代码,留在本单元:ctrl+Enter
命令模式:
Y:cell切换到code模式
M:cell切换到markdown模式
A:在当前cell的上面添加cell
B:在当前cell的下面添加cell
双击D:删除当前cell
编辑模式:
多光标操作:Ctrl键点击鼠标(Mac:CMD+点击鼠标)
回退:Ctrl+Z(Mac:CMD+Z)
补全代码:变量、方法后跟Tab键
为一行或多行代码添加/取消注释:Ctrl+/(Mac:CMD+/)
-
markdown演示
# 一级标题 – 缩进
二、Matplotlib
2.1 Matplotlib
2.1.1 什么是Matplotlib – 画二维图表的python库
mat – matrix 矩阵, 二维数据 – 二维图表
plot – 画图
lib – library 库
matlab 矩阵实验室
mat – matrix
lab 实验室
2.1.2 为什么要学习Matplotlib – 画图
数据可视化 – 帮助理解数据,方便选择更合适的分析方法
js库 – D3 和echarts能实现一些比较酷炫的3D效果
奥卡姆剃刀原理 – 如无必要勿增实体
2.1.3 实现一个简单的Matplotlib画图
import matplotlib.pyplot as plt
plt.figure()
plt.plot([1,2,3],[4,5,6])
plt.show()
2.1.4 拓展知识点:Matplotlib三层结构
容器层 : 画板层Canvas 画布层Figure 绘图区/坐标系 x、y轴张成的区域
容器层主要由Canvas、Figure、Axes组成。
Canvas是位于最底层的系统层,在绘图的过程中充当画板的角色,即放置画布(Figure)的工具。
Figure是Canvas.上方的第一层,也是需要用户来操作的应用层的第一层,在绘图的过程中充当画布的角色。
Axs是应用层的第二层,在绘图的过程中相当于画布上的绘图区的角色。
Figure:指整个图形可以通过plt.figure0设置画布的大小和分辨率等)
Axes(坐标系):数据的绘图区域
Axs(坐标轴):坐标系中的一条轴,包含大小限制、刻度和刻度标签
特点为:
一个figure(画布)可以包含多个axes(坐标系/绘图区),但是一个axes只能属于一个figure.
一个axes(坐标系/绘图区)可以包含多个axis(坐标轴),包含两个即为2d坐标系,3个即为3d坐标系
辅助显示层
辅助显示层为Axes(绘图区)内的除了根据数据绘制出的图像以外的内容,主要包括Axes外观(facecolor)边框线(spines)、坐标轴(axis)、坐标轴名称(axis label)、坐标轴刻度(tick)、坐标轴刻度标签(tick label)、网格线(grid)、图例(legend)、标题(title)等内容。
该层的设置可使图像显示更加直观更加容易被用户理解,但又不会对图像产生实质的影响。
图像层
图像层指Axes内通过plot、scatter、bar、histogram、pie等函数根据数据绘制出的图像
总结
Canvas(画板)位于最底层,用户一般接触不到
Figure(画布)建立在Canvas之上
Axes(绘图区)建立在Figure之上
坐标轴(axis)、图例(legend)等辅助显示层以及图像层都是建立在Axes之上
2.2 折线图(plot)与基础绘图功能
2.2.1 折线图绘制与保存图片
基本步骤
- 创建画布
- 绘制图像
- 显示图像
#1创建画布
plt.figure(figsize=(20,8),dpi=80)
### figsize : 画布大小
### dpi : dot per inch 图像的清晰度,每英寸显示点数
#2绘制图像
plt.plot([1,2,3,4,5],[6,7,8,9,10])
#保存图像(注意保存图片代码应位于plt.show()之前)
plt.savefig("test.png")
#3显示图像
plt.show()
#plt.show()会释放figsure资源
2.2.2完善原始折线图(辅助显示层)
# 需求:再添加一个城市的温度变化
# 收集到北京当天温度变化情况,温度在1度到3度。
# 1、准备数据 x y
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
y_beijing = [random.uniform(1, 3) for i in x]
# 中文显示问题
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
# 2、创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 3、绘制图像
plt.plot(x, y_shanghai, color="r", linestyle="-.", label="上海")
plt.plot(x, y_beijing, color="b", label="北京")
# 显示图例,这里显示图例的前提是plt.plot时要添加标签lsbel=“”
plt.legend()#legend有自己的参数可以控制图例位置
# 修改x、y刻度
# 准备x的刻度说明 ticks表示刻度
x_label = ["11点{}分".format(i) for i in x]
plt.xticks(x[::5], x_label[::5])
#步长为5,即不让刻度显示过于密集第一处的x[::5]也要写,应该是用来给x_label定位的
plt.yticks(range(0, 40, 5))
# 添加网格显示,其中的alpha是网格的透明程度
plt.grid(linestyle="--", alpha=0.5)
# 添加描述信息
plt.xlabel("时间变化")
plt.ylabel("温度变化")
plt.title("上海、北京11点到12点每分钟的温度变化状况")
# 4、显示图
plt.show()
2.2.3多个坐标系显示-plt.subplots(面向对象的画图方法)
注意主要区别就是返回一个figsure和axes,后期全部利用axes[索引]来绘制图像,有一定的函数名字差别 axes[i].方法名()
#主要区别:
#figure, axes = plt.subplots(nrows=1, ncols=2, figsize=(20, 8), dpi=80)
# 需求:再添加一个城市的温度变化
# 收集到北京当天温度变化情况,温度在1度到3度。
# 1、准备数据 x y
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
y_beijing = [random.uniform(1, 3) for i in x]
# 2、创建画布
# plt.figure(figsize=(20, 8), dpi=80)
figure, axes = plt.subplots(nrows=1, ncols=2, figsize=(20, 8), dpi=80)
# 3、绘制图像
axes[0].plot(x, y_shanghai, color="r", linestyle="-.", label="上海")
axes[1].plot(x, y_beijing, color="b", label="北京")
# 显示图例
axes[0].legend()
axes[1].legend()
# 修改x、y刻度
# 准备x的刻度说明
x_label = ["11点{}分".format(i) for i in x]
axes[0].set_xticks(x[::5])
axes[0].set_xticklabels(x_label)
axes[0].set_yticks(range(0, 40, 5))
axes[1].set_xticks(x[::5])
axes[1].set_xticklabels(x_label)
axes[1].set_yticks(range(0, 40, 5))
# 添加网格显示
axes[0].grid(linestyle="--", alpha=0.5)
axes[1].grid(linestyle="--", alpha=0.5)
# 添加描述信息
axes[0].set_xlabel("时间变化")
axes[0].set_ylabel("温度变化")
axes[0].set_title("上海11点到12点每分钟的温度变化状况")
axes[1].set_xlabel("时间变化")
axes[1].set_ylabel("温度变化")
axes[1].set_title("北京11点到12点每分钟的温度变化状况")
# 4、显示图
plt.show()
效果图:
2.2.4 折线图绘制函数图像
import numpy as np
# 1、准备x,y数据
##表示区间[-1,1]左闭右闭并等间隔生成1000个数字
x = np.linspace(-1, 1, 1000)
y = 2 * x * x
# 2、创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 3、绘制图像
plt.plot(x, y)
# 添加网格显示
plt.grid(linestyle="--", alpha=0.5)
# 4、显示图像
plt.show()
2.3 散点图(scatter)
丰富图片的其他函数基本一致,主要区别在于plt.scatter()函数用于绘图
# 需求:探究房屋面积和房屋价格的关系
# 1、准备数据
x = [225.98, 247.07, 253.14, 457.85, 241.58, 301.01, 20.67, 288.64,
163.56, 120.06, 207.83, 342.75, 147.9 , 53.06, 224.72, 29.51,
21.61, 483.21, 245.25, 399.25, 343.35]
y = [196.63, 203.88, 210.75, 372.74, 202.41, 247.61, 24.9 , 239.34,
140.32, 104.15, 176.84, 288.23, 128.79, 49.64, 191.74, 33.1 ,
30.74, 400.02, 205.35, 330.64, 283.45]
# 2、创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 3、绘制图像
plt.scatter(x, y)
# 4、显示图像
plt.show()
2.4 柱状图(bar)
##绘制票房分布直方图
# 1、准备数据
movie_names = ['雷神3:诸神黄昏','正义联盟','东方快车谋杀案','寻梦环游记','全球风暴', '降魔传','追捕','七十七天','密战','狂兽','其它']
tickets = [73853,57767,22354,15969,14839,8725,8716,8318,7916,6764,52222]
# 2、创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 3、绘制柱状图
x_ticks = range(len(movie_names))
plt.bar(x_ticks, tickets,width=[0.2 for i in range(x_ticks)],color=['b','r','g','y','c','m','y','k','c','g','b'])
#主要参数x列表,y列表,width列表,color列表
# 修改x刻度
plt.xticks(x_ticks, movie_names)
# 添加标题
plt.title("电影票房收入对比")
# 添加网格显示
plt.grid(linestyle="--", alpha=0.5)
# 4、显示图像
plt.show()
如果绘制下图的柱状图怎么设置呢,主要在于给x_labels的刻度位置定位,将刻度改变即可
# 1、准备数据
movie_name = ['雷神3:诸神黄昏','正义联盟','寻梦环游记']
first_day = [10587.6,10062.5,1275.7]
first_weekend=[36224.9,34479.6,11830]
# 2、创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 3、绘制柱状图
x_ticks=[i for i in range(3)]
plt.bar(x_ticks, first_day, width=0.2, label="首日票房")
plt.bar([i+0.2 for i in x_ticks], first_weekend, width=0.2, label="首周票房")
##########为何是i+0.2呢,因为前面设置的柱状图宽度width=0.2,为了紧密相连,同时没有重合,因此设置0.2
# 显示图例
plt.legend()
# 修改刻度,即显示坐标轴上的数字或字符,本例即显示电影名字
plt.xticks([i+0.1 for i in x_ticks], movie_name)
###########柱状图宽度为0.2,为了字符名字在中间,因此相对于前面是加了0.1
# 4、显示图像
plt.show()
2.5 直方图(histogram)
2.5.1 直方图介绍
直方图,形状类似柱状图却有着与柱状图完全不同的含义。 直方图牵涉统计学的概念,首先要对数据进行分组,然后统计每个分组内数据元的数量。 在坐标系中,横轴标出每个组的端点,纵轴表示频数, 每个矩形的高代表对应的频数,称这样的统计图为频数分布直方图。
组数:在统计数据时,我们把数据按照不同的范围分成几个组,分成的组的个数称为组数
组距:每一组两个端点的差
2.5.2 直方图与柱状图的对比
柱状图是以矩形的长度表示每一组的频数或数量,其宽度(表示类别则是固定的,利于较小的数据集分析。
直方图描述的是一组数据的频次分布,是以矩形的长度表示每一组的频数或数量,宽度则表示各组的组距,因此其高度与宽度均有意义,利于展示大量数据集的统计结果。例如把年龄分成“0-5,5-10…80-85”17个组,统计一下中国人口年龄的分布情况。直方图有助于我们知道数据的分布情况,诸如众数、中位数的大致位置、数据是否存在缺口或者异常值。
- 直方图展示数据的分布,柱状图比较数据的大小。
- 直方图X轴为定量数据,柱状图X轴为分类数据。
- 直方图柱子无间隔,柱状图柱子有间隔
- 直方图柱子宽度可不一,柱状图柱子宽度须一致
2.5.3直方图绘制
可以尝试多种组距以获得一个较好的效果
# 需求:电影时长分布状况
# 1、准备数据
time = [131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130, 124, 101, 110, 116, 117, 110, 128, 128, 115, 99, 136, 126, 134, 95, 138, 117, 111,78, 132, 124, 113, 150, 110, 117, 86, 95, 144, 105, 126, 130,126, 130, 126, 116, 123, 106, 112, 138, 123, 86, 101, 99, 136,123, 117, 119, 105, 137, 123, 128, 125, 104, 109, 134, 125, 127,105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114,105, 115, 132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134,156, 106, 117, 127, 144, 139, 139, 119, 140, 83, 110, 102,123,107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133,112, 114, 122, 109, 106, 123, 116, 131, 127, 115, 118, 112, 135,115, 146, 137, 116, 103, 144, 83, 123, 111, 110, 111, 100, 154,136, 100, 118, 119, 133, 134, 106, 129, 126, 110, 111, 109, 141,120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126,114, 140, 103, 130, 141, 117, 106, 114, 121, 114, 133, 137, 92,121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,134, 106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110,105, 129, 137, 112, 120, 113, 133, 112, 83, 94, 146, 133, 101,131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111,111, 133, 150]
# 2、创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 3、绘制直方图
distance = 2#组距
group_num = int((max(time) - min(time)) / distance)#组数=极差/组距
plt.hist(time, bins=group_num, density=True)
##第一个参数是数据,第二个参数是组数,第三个参数是density默认为False
##False显示的是频数,True显示的是频率
# 修改x轴刻度
plt.xticks(range(min(time), max(time) + 2, distance))
# 添加网格
plt.grid(linestyle="--", alpha=0.5)
# 4、显示图像
plt.show()
2.6饼图
用于表示不同分类的占比情况,通过弧度大小来对比各种分类。
特点:分类数据的占比情况(占比)
# 1、准备数据
movie_name = ['雷神3:诸神黄昏','正义联盟','东方快车谋杀案','寻梦环游记','全球风暴','降魔传','追捕','七十七天','密战','狂兽','其它']
place_count = [60605,54546,45819,28243,13270,9945,7679,6799,6101,4621,20105]
# 2、创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 3、绘制饼图
plt.pie(place_count, labels=movie_name, colors=['b','r','g','y','c','m','y','k','c','g','y'], autopct="%1.2f%%")
# 显示图例
plt.legend()
plt.axis('equal')
##表示横纵轴比相同,即显示为圆形
# 4、显示图像
plt.show()
三:Numpy
介绍
ndarray
Numpy提供了一个N dimension array,即n维数组
numpy与list对比
-
存储风格:
ndarray 内部存储类型相同,存储空间连续,但通用性不强
list 内部存储类型可以不同,存储空间未必连续,通用性较强
-
并行化计算:ndarray支持向量化运算
-
底层语言:
Numpy底层采用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,效率远高于纯Python代码。
属性方法
属性名字 | 属性解释 |
---|---|
ndarray.shape | 数组维度的元组 |
ndarray.ndim | 数组维数 |
ndarray.size | 数组中的元素数量 |
ndarray.itemsize | 一个数组元素的长度(字节) |
ndarray.dtype | 数组元素的类型 |
使用方法 数组名.函数名 |
3.1基本操作
3.1.1ndarray形状和类型
形状
import numpy as np
a = np.array([[1,2,3],[4,5,6]]) #(2,3)
b = np.array([1,2,3,4]) #(4,)
c = np.array([[[1,2,3],[4,5,6]],[[1,2,3],[4,5,6]]])#(2,2,3)
类型
创建数组时指定即可
# 创建数组的时候指定类型
np.array([1.1, 2.2, 3.3], dtype="float32")
3.1.2生成数组
生成0 1 数组
# 1 生成0和1的数组
a=np.zeros(shape=(3, 4), dtype="float32")
##其中shape的参数为列表/元组均可,用于表示生成的数组维度
从现有数组生成
a1=np.array(a) #深拷贝
a2=np.copy(a) #深拷贝
a3=np.asarray(a)#浅拷贝
a4=a #浅拷贝
生成固定范围的数组
np.linspace(0, 10, 5) # 生成[0,10]之间等距离的5个数,左右均为闭区间
np.arange(0, 11, 5) # [0,11),5为步长生成数组 ,左闭右开
生成随机数组
# 生成均匀分布的一组数[low,high) 左闭右开,size是数量
data1 = np.random.uniform(low=-1, high=1, size=1000000)
########注意这两处的size都可以规定数组形状 size=(8,100)
# 生成正态分布的一组数,loc:均值;scale:标准差,size数量
data2 = np.random.normal(loc=1.75, scale=0.1, size=1000000)
3.1.3索引切片
stock_change = np.random.normal(loc=0, scale=1, size=(8, 10))
# 获取第一个股票的前3个交易日的涨跌幅数据
print(stock_change[0, :3])
a[1, 0, 2] = 1000
a[1][0][2] = 1000
3.1.4形状改变
stock_change.reshape((10, 8)) # 返回新的ndarray, 原始数据没有改变
stock_change.resize((10, 8)) # 没有返回值, 对原始的ndarray进行了修改
stock_change.T # 转置 行变成列,列变成行 返回一个ndarray,原数据未改变
##reshape()是一个函数,因此第一个括号是函数个括号,而第二个括号是因为传入了一个元##组,其实用列表也可
3.1.5类型修改
stock_change.astype("int32")
stock_change.tostring() # ndarray序列化到本地??????
https://blog.csdn.net/u010356210/article/details/106131209
3.1.6数组去重
temp = np.array([[1, 2, 3, 4],[3, 4, 5, 6]])
np.unique(temp)
set(temp.flatten())##set的操作对象需要时一维的,.flatten()可以压缩为一维的
3.2ndarray运算
3.2.1逻辑运算
stock_change = np.random.uniform(low=-1, high=1, size=(5,10))
# 逻辑判断, 如果涨跌幅大于0.5就标记为True 否则为False
stock_change > 0.5
#返回一个True和False的等大小矩阵
stock_change[stock_change > 0.5] = 1.1
#将>0.5的全部改为1
通用判断函数
#以下两者均只返回一个布尔值
# 判断stock_change[0:2, 0:5]是否全是上涨的
np.all(stock_change[0:2, 0:5] > 0)
# 判断前5只股票这段期间是否有上涨的
np.any(stock_change[:5, :] > 0)
三元运算符
# np.where(布尔表达式,True的位置的值,False的位置的值),类似于三元运算符,不# 过需要利用函数
np.where(temp > 0, 1, 0)
###涉及符合逻辑需要额外的函数logical_and/or
# 大于0.5且小于1
np.where(np.logical_and(temp > 0.5, temp < 1), 1, 0)
# 大于0.5或小于-0.5
np.where(np.logical_or(temp > 0.5, temp < -0.5), 11, 3)
3.2.2统计运算
###返回值
stock_change.max() #将返回最大值
np.max(stock_change,axis=1)#将返回一个向量,即所有行的最大值
###返回索引
np.argmax(tem,axis=0)
np.argmin(tem,axis=0)
3.2.3数组运算
数组与数字的运算
正常的运算即可 加减乘除等
数组与数组的运算
广播机制
执行broadcast的前提在于,两个nadarray执行的是element-wise的运算,Broadcast机制的功能是为了方便不同形状的ndarray(numpy库的核心数据结构)进行数学运算。
当操作两个数组时,numpy会逐个比较它们的shape(构成的元组tuple),只有在下述情况下,两个数组才能够进行数组与数组的运算。
具体解释解释就是看这个图。
比如(不一定是乘法)数组A*B,将两者的维度写出,如下,将维度从尾部开始对齐,则满足运算的要求是:
- 对应的维度相同
- 若维度不同,则其中一个维度应当为1
矩阵运算
可以通过np.mat(array)将数组转化为矩阵
矩阵的乘法必须满足运算规则,即(m,n)*(n,l)=(m,l)
如果是二维数组实现矩阵运算
np.dot(data,data1)
np.matmul(data,data1)
data @ data1
如果是矩阵进行运算
data1*data2
3.2.4数组合并分割
numpy.hstack 水平拼接
numpy.vstack 竖拼接
numpy.concatenate((a1,a2),axis=0|1) 水平|竖拼接
np.hstack((a, b))
np.vstack((a, b))
np.concatenate((a, b), axis=1)
四:Pandas
4.0基本介绍
核心数据结构
4.1DataFrame
4.1.0DataFrame结构
4.1.1构造dataframe 利用DataFrame函数
DataFrame是一个既有行索引又有列索引的二维数据结构
import numpy as np
import pandas as pd
a=np.ones((2,3))
b=pd.DataFrame(a)
如图,生成的打他frame是一个二维表,由于没有指定索引,因此默认行列索引为数字序号
4.1.2常用操作(设置索引)
-
获取局部展示
b.head()#默认展示前5行,可在head()加入数字,展示前几行 b.tail()#默认展示后5行,可在tail()加入数字,展示后几行
-
获取索引和值
b.index#获取行索引 #####返回一个类似列表的东西,也可以利用数字继续索引例:a.index[1] b.columns#获取列索引 b.values#获取数据值(数组,不含索引) b.shape#获取DataFrame的维度数据 b.T#获取转制后的dataframe
-
设置行列索引
# 创建一个符合正态分布的10个股票5天的涨跌幅数据 stock_change = np.random.normal(0, 1, (10, 5)) pd.DataFrame(stock_change) #设置行列索引 stock = ["股票{}".format(i) for i in range(10)] date = pd.date_range(start="20200101", periods=5, freq="B")#这个是pandas中设置日期的 # 添加行列索引 data = pd.DataFrame(stock_change, index=stock, columns=date)
-
修改索引
#不能单独修改行列总某一个索引的值,可以替换整行或整列 例:b.index[2]='股票1' 错误 data.index=新行索引 #重设索引 data.reset_index(drop=False) #drop参数默认为False,表示将原来的索引替换掉,换新索引为数字递增,原来的索引将变为数据的一部分。True表示,将原来的索引删除,更换为数字递增。如下图
# 设置新索引
df = pd.DataFrame({'month': [1, 4, 7, 10],
'year': [2012, 2014, 2013, 2014],
'sale':[55, 40, 84, 31]})
# 以月份设置新的索引
df.set_index("month", drop=True)
#见下图,即将原本数据中的一列拿出来作为index
new_df = df.set_index(["year", "month"])# 设置多个索引,以年和月份 多个索引其实就是MultiIndex
可以看到下面的new_df已经是multiIndex类型数据了。
有三级:index index.names index.levels
分别看各自的输出
4.1.3 MultiIndex与Panel
MultiIndex:多级或分层索引对象
Panel:
pandas.Panel(data=None,items=None,major_axis=None,minor_axis=None,copy=False,dtype=None)
存储3维数组的Panel结构
p = pd.Panel(np.arange(24).reshape(4,3,2),
items=list('ABCD'),
major_axis=pd.date_range('20130101', periods=3),
minor_axis=['first', 'second'])
p["A"]
p.major_xs("2013-01-01")
p.minor_xs("first")
###由于panel是三维数据,因此只能从某一个维度切入,可以理解为从立方体中抽出一个平面(dataframe)观察,则上面三行代码结果如下图;而series则是相当于从平面(dataframe)中抽出一行或一列来观察
Pandas从版本0.20.0开始弃用,推荐的用于表示3D数据的方法是DataFrame上的MultiIndex方法
4.1.4 Series
带索引的一维数组
# 创建
pd.Series(np.arange(3, 9, 2), index=["a", "b", "c"])
# 或
pd.Series({'red':100, 'blue':200, 'green': 500, 'yellow':1000})
sr = data.iloc[1, :]
sr.index # 索引
sr.values # 值
#####就是从dataframe中抽出一行或一列来观察
4.2基本数据操作(很重要的一点是布尔值索引)
4.2.1索引操作(bool索引见4.2.4)
data=pd.read_csv("./stock_day/stock_day.csv")#读入文件的前5行表示如下
######利用drop删除某些行列,需要利用axis告知函数是行索引还是列索引
data=data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1) # 去掉一些不要的列
data["open"]["2018-02-26"] # 直接索引,但需要遵循先列后行
#####按名字索引利用.loc函数可以不遵循列行先后关系
data.loc["2018-02-26"]["open"] # 按名字索引
data.loc["2018-02-26", "open"]
#####利用.iloc函数可以只利用数字进行索引
data.iloc[1][0] # 数字索引
data.iloc[1,0]
# 组合索引
# 获取行第1天到第4天,['open', 'close', 'high', 'low']这个四个指标的结果
data.ix[:4, ['open', 'close', 'high', 'low']] # 现在不推荐用了
###但仍可利用loc和iloc
data.loc[data.index[0:4], ['open', 'close', 'high', 'low']]
data.iloc[0:4, data.columns.get_indexer(['open', 'close', 'high', 'low'])]
4.2.2赋值操作
data仍然是上图类型
data.open=100
data['open']=100
###两种方式均可
data.iloc[1,0]=100
###找好索引即可
4.2.3排序
sort_values (比较values进行排序) sort_index (比较行索引进行排序,不行可以先转置简介对列排序)
data.sort_values(by="high", ascending=False) # DataFrame内容排序,ascending表示升序还是降序,默认True升序
data.sort_values(by=["high", "p_change"], ascending=False).head() # 多个列内容排序。给出的优先级进行排序
data.sort_index(ascending=True)###对行索引进行排序
#这里是取出了一列 “price_change”列,为serise,用法同上
sr = data["price_change"]
sr.sort_values(ascending=False)
sr.sort_index()
4.2.4数学运算 布尔值索引
-
算术运算:直接利用运算符或者函数
#正常的加减乘除等的运算即可 data["open"] + 3 data["open"].add(3) # open统一加3 data.sub(100)# 所有统一减100 data - 100 (data["close"]-(data["open"])).head() # close减open
-
逻辑运算 :< ; > ; | ; & 利用逻辑符号或者函数query
# 例如筛选p_change > 2的日期数据 data[data["p_change"] > 2].head() # 完成一个多个逻辑判断, 筛选p_change > 2并且low > 15 data[(data["p_change"] > 2) & (data["low"] > 15)].head() data.query("p_change > 2 & low > 15").head()###等效于上一行代码 ###判断# 判断'turnover'列索引中是否有4.19, 2.39,将返回一列布尔值 data["turnover"].isin([4.19, 2.39])##如下图
-
利用布尔值索引,即利用一个布尔数组索引出True的数据
###判断# 判断'turnover'列索引中是否有4.19, 2.39,将返回一列布尔值 data["turnover"].isin([4.19, 2.39])##如下图 data[data["turnover"].isin([4.19, 2.39])] #这块就将返回turnover列布尔值为true的如下图,也就是筛选出turnover中值为4.19和2.39 ###布尔值索引是一个很方便的数据筛选操作,比如: data[data["turnover"]>0.1] #也将筛选出turnover列中大于0.1的整体data数据,并不是说只返回turnover相关数据,判断只是返回布尔索引,利用索引的是data数据
4.2.5统计运算
data.describe()
#将返回关于列的最值,均值,方差等多种信息
##其实这里很多就和numpy相似了
data.max(axis=0)#返回最值
data.idxmax(axis=0) #返回最值索引
累计统计函数(累加,累乘等)
自定义运算
apply(func, axis=0)
func: 自定义函数
axis=0: 默认按列运算,axis=1按行运算
data.apply(lambda x: x.max() - x.min())
#这里的lambda x: x.max() - x.min()是lambda表达式,是函数的简单写法也可
def fx(data):
return data.max()-data.min()
4.3画图
pandas.DataFrame.plot
DataFrame.plot(x=None, y=None, kind=‘line’)
#更简易用matplotlib
data.plot(x="volume", y="turnover", kind="scatter")
data.plot(x="high", y="low", kind="scatter")
data['volume'].plot()
4.4文件读取写入
4.4.1 CSV文件
DataFrame.to_csv(path_or_buf=None,sep=','columns=None,header=True,index=True,index_label=None,mode='w',encoding=None)
Series.to_csv (path=None,index=True,sep=',',na_rep='',float_format=None,header=False,index_label=None,mode='w',encoding=None,compression=None,date_format=None,decimal='.)
pd.read_csv("./stock_day/stock_day.csv", usecols=["high", "low", "open", "close"]).head() # 读哪些列
data = pd.read_csv("stock_day2.csv", names=["open", "high", "close", "low", "volume", "price_change", "p_change", "ma5", "ma10", "ma20", "v_ma5", "v_ma10", "v_ma20", "turnover"]) # 如果列没有列名,用names传入
data[:10].to_csv("test.csv", columns=["open"]) # 保存open列数据
data[:10].to_csv("test.csv", columns=["open"], index=False, mode="a", header=False) # 保存opend列数据,index=False不要行索引,mode="a"追加模式|mode="w"重写,header=False不要列索引
csv可以用excel表格打开,但是可能有格式错误
4.4.2HDF5文件
read_hdf to_hdf
HDF5文件的读取和存储需要指定一个键,值为要存储的DataFrame,也就是说hdf5存储的是panel这种三维类型,一个key对应一个dataframe
pandas.read_hdf(path_or_buf, key=None, **kwargs)
从h5文件当中读取数据
DataFrame.to_hdf(path_or_buf, key, **kwargs)
day_close = pd.read_hdf("./stock_data/day/day_close.h5",key="close")
day_close.to_hdf("test.h5",key="close" )
4.4.3 JSON文件
read_json to_json
pandas.read_json(path_or_buf=None,orient=None,typ=“frame”,lines=False)
sa = pd.read_json("Sarcasm_Headlines_Dataset.json", orient="records", lines=True)
##主要是path,orient是一种确定索引与数值的对应,以本例来看,列索引就是‘key’,values就是key对应的值
sa.to_json("test.json", orient="records", lines=True)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1nR980In-1647746935684)(python数据挖掘.assets/image-20220319221645419.png)]
本示例中按行存储,每行是一个字典,键 有’article_link’,'headline’等
数据读取后的展示如下
4.5高级处理
4.5.1缺失值(标记值)处理
主要参数
如何进行缺失值处理?
判断NaN是否存在
删除nan数据
替换nan数据
df.fillna(value,inplace=True)
value替换的值
inplace:True修改原数据,False返回新数据,默认False
movie["Revenue (Millions)"].fillna(movie["Revenue (Millions)"].mean(), inplace=True)
###这就是先利用其他代码判断出"Revenue (Millions)"有nan数据,然后利用.fillna函数,令value=movie["Revenue (Millions)"].mean()列的均值,然后inplace=True修改原数据
import pandas as pd
import numpy as np
movie = pd.read_csv("./IMDB/IMDB-Movie-Data.csv")
# 1)判断是否存在NaN类型的缺失值
np.any(pd.isnull(movie)) # 返回True,说明数据中存在缺失值
np.all(pd.notnull(movie)) # 返回False,说明数据中存在缺失值
pd.isnull(movie).any()
pd.notnull(movie).all()
# 2)缺失值处理
# 方法1:删除含有缺失值的样本
data1 = movie.dropna()
pd.notnull(data1).all()
# 方法2:替换
# 含有缺失值的字段
# Revenue (Millions)
# Metascore
movie["Revenue (Millions)"].fillna(movie["Revenue (Millions)"].mean(), inplace=True)
movie["Metascore"].fillna(movie["Metascore"].mean(), inplace=True)
替换非nan的标记数据
有些数据不存在可能标记为“#”,“?”等
# 读取数据
path = "wisconsin.data"
name = ["Sample code number", "Normal Nucleoli","Mitoses", "Class"]
data = pd.read_csv(path, names=name)
#这里的非nan标记值缺失值就是利用“?”表示的,因此利用参数to_replace,value=np.nan,将默认标记值替换为nan值,然后再利用签署方法处理nan缺失值
# 1)替换
data_new = data.replace(to_replace="?", value=np.nan)
4.5.2 离散化
这一块建议去看视频,理解更快:视频地址
连续属性的离散化就是将连续属性的值域上,将值域划分为若干个离散的区间,最后用不同的符号或整数 值代表落在每个子区间的属性值。
连续属性离散化的目的是为了简化数据结构,数据离散化技术可以用来减少给定连续属性值的个数。离散化方法经常作为数据挖掘的工具。
实现方法:
- 分组
- 自动分组 sr = pd.qcut(data, bins)
- 自定义分组 sr = pd.cut(data, [])
one-hot编码:
one-hot
比如男女数据一般用1和0表示,但1和0本身有大小问题,而男女只是不同的概念,因此用1,0表示会存在区别
(男:1 女:0) | 性别 |
---|---|
小明 | 1 |
小红 | 0 |
如果用one-hot表示一种方法可以是,相当于利用一种编码的方式表示
男 | 女 | 编码 | |
---|---|---|---|
小明 | 1 | 0 | 1 0 |
小红 | 0 | 1 | 0 1 |
同时还可处理连续数据,比如将身高的连续数据分为不同的身高区间,每个区间对应一个类别,然后类比同上来考虑
# 1)准备数据
data = pd.Series([165,174,160,180,159,163,192,184], index=['No1:165', 'No2:174','No3:160', 'No4:180', 'No5:159', 'No6:163', 'No7:192', 'No8:184'])
# 2)分组
# 自动分组
sr = pd.qcut(data, 3)
sr.value_counts() # 看每一组有几个数据
# 3)转换成one-hot编码
pd.get_dummies(sr, prefix="height")
# 自定义分组
bins = [150, 165, 180, 195]#这就表示有三组[150,165][165,180][180,195]
sr = pd.cut(data, bins)
# get_dummies
pd.get_dummies(sr, prefix="身高")
4.5.3合并
指合并不同dataframe上的内容数据
按方向
pd.concat([data1, data2], axis=1)
#axis:0为列索引;1为行索引
按索引
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
'key2': ['K0', 'K1', 'K0', 'K1'],
'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
'key2': ['K0', 'K0', 'K0', 'K0'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']})
pd.merge(left, right, how="inner", on=["key1", "key2"])
pd.merge(left, right, how="left", on=["key1", "key2"])
pd.merge(left, right, how="outer", on=["key1", "key2"])
###这里merge参数解释:
#left: 需要合并的一个表,合并后在左侧
#right:需要合并的一个表,合并后在右侧
#how: 合并方式
#on: 在哪些索引上进行合并
4.5.4交叉表与透视表
-
交叉表
-
交叉表用于计算一列数据对于另外一列数据的分组个数(寻找两个列之间的关系)
-
pd.crosstab(value1, value2)
data = pd.crosstab(stock["week"], stock["pona"]) data.div(data.sum(axis=1), axis=0).plot(kind="bar", stacked=True)
-
透视表
-
相对于交叉表操作简单些
# 透视表操作 stock.pivot_table(["pona"], index=["week"])
4.5.6分组与聚合
分组与聚合通常是分析数据的一种方式,通常与一些统计函数一起使用,查看数据的分组情况。
DataFrame.groupby(key, as_index=False) key:分组的列数据,可以多个
col =pd.DataFrame({'color': ['white','red','green','red','green'], 'object': ['pen','pencil','pencil','ashtray','pen'],'price1':[5.56,4.20,1.30,0.56,2.75],'price2':[4.75,4.12,1.60,0.75,3.15]})
# 进行分组,对颜色分组,price1进行聚合
# 用dataframe的方法进行分组
col.groupby(by="color")
# 或者用Series的方法进行分组聚合
col["price1"].groupby(col["color"])
效果图
五:案例
要求
- 想知道这些电影数据中评分的平均分,导演的人数等信息,我们应该怎么获取?
- 对于这一组电影数据,如果我们想看Rating,Runtime(Minutes)的分布情况,应该如何呈现数据?
- 对于这一组电影数据,如果我们希望统计电影分类(genre)的情况,应该如何
处理数据?
数据结构展示
数据网址
代码
# 1、准备数据
movie = pd.read_csv("./IMDB/IMDB-Movie-Data.csv")
###movie读入后如上图所示
######################问题一
# 问题1:我们想知道这些电影数据中评分的平均分,导演的人数等信息,我们应该怎么获取?
# 评分的平均分
movie["Rating"].mean()
# 导演的人数
np.unique(movie["Director"]).size
######################问题二
##绘制直方图查看分布
movie["Rating"].plot(kind="hist", figsize=(20, 8))
#利用matplotlib可更细致绘图
import matplotlib.pyplot as plt
# 1、创建画布
plt.figure(figsize=(20, 8), dpi=80)
# 2、绘制直方图
plt.hist(movie["Rating"], 20)
# 修改刻度
plt.xticks(np.linspace(movie["Rating"].min(),movie["Rating"].max(), 21))
# 添加网格
plt.grid(linestyle="--", alpha=0.5)
# 3、显示图像
plt.show()
######################问题三
##如果我们希望统计电影分类(genre)的情况,应该如何处理数据?
###可以发现图中genre一列数据中每个电影都有多种标签,因此要先分割
# 先统计电影类别都有哪些
movie_genre = [i.split(",") for i in movie["Genre"]]
###得到的movie_genre结构图见《下图一》
###这一块主要是把movie_genre的二维列表变为以为列表,然后利用unique函数去重
movie_class = np.unique([j for i in movie_genre for j in i])
len(movie_class)####这就得到了电影的类型标签种类数
# 统计每个类别有几个电影
count = pd.DataFrame(np.zeros(shape=[1000, 20], dtype="int32"), columns=movie_class)
count.head()###得到的count结构如《下图二》
# 计数填表
for i in range(1000):
count.ix[i, movie_genre[i]] = 1###注意ix现在不太能用了
############movie_genre[i]将返回字符索引列
#这就得到了下面第三张图片的数据处理效果,列表示电影类型种类,行表示不同电影,如《下图三》
#因此只需逐列求和即可得到每类标签电影的数量
##最终实现数据可视化如《下图四》
count.sum(axis=0).sort_values(ascending=False).plot(kind="bar", figsize=(20, 9), fontsize=40, colormap="cool")
图一
图二
图三
图四
来源:天天写点代码