Python数据分析三剑客

256 阅读16分钟

前言

这是本人在学习b站BV1yi4y147A2课程过程中进行的笔记,老师讲的很好,很基础,适合小白入门,这里是部分跟着老师的讲解的代码以及自己的一些理解,本意是自用,也希望给大家一些参考。该课程主要讲解了python数据分析的常用的工具和方法,很全面。

基础知识

数据结构

list:[列表]
  • append()在末尾加
  • insert()在前面加
  • pop()删除最后一项,pop(索引)删除某项
  • a[:3]数据切片,a[0:-1]到最后一个数前一个,开区间
  • a[1:3:9]间隔取值
tuple(元组)

一旦初始化就不能被修改,经常用来作为常量

dict{字典}

字典里的数据可以是任何数据类型,也可以是字典{key:value}

  • .key()
  • .values()
  • .items()
  • 修改:a.['name']='' 增加a.[' ']=' ' 删除 .pop
set{集合}

集合中不含有相同元素

基础循环

if x>0:
print('x正')
elif x==0print('x0')
else:
print('x负')
while a<10:
    print(a)
    a+=2
for num in range(10,20):
   for i in range(2,num):
      if num%i == 0:
         j=num/i
         print ('%d 等于 %d * %d' % (num,i,j))
         break
   else:
      print ('%d 是一个质数' % num)

列表生成式

[i for i in range(1,10)]
[int(x) for x in list('123456789')]

Python函数

  • abs()

  • max(),min(),sum()

  • 定义 def 函数名称(参数1,参数2)

    def add(x,y):
        a=x+y
        return a
    

numpy

方便一些数组运算

导入
import numpy
import numpy as np  #推荐
from numpy import*
使用
a=np.array([1,2,3,4])
np.zeros(5) #生成全是0的数组
np.ones(5,dtype='bool') #生成全是1的数组,dtype设定数据的类型
a.fill(5) #用fill设定在数组设为指定值
a.astype('float') #设定数据类型
np.arange(1,10,2) #起点终点步长,左闭右开区间,生成整数数列
np.linspace(1,10,10) #起点终点,需要生成的数的数量,生成等差数列
np.random.rand(10) #0到1之间多少个随机数
np.random.randn(10) #满足标准正态分布的
np.random.randint(1,10,10) #前为范围后为数量

数据类型
type(a) #查看数据类型
a.dtype #查看数组中的数据类型
a.shape #查看形状,返回一个元组,每个元素代表这一维的元素数目
a.size  #查看数组元素数目
a.ndim  #查看数组维度
索引与切片
a=np.array #索引第一个元素
a[0]=10 #修改第一个元素
a=np.array([1,2,3,4,5])
a[1:3] #切片,改变切片会影响原数组
b=a[2:4].copy() #进行copy产生一个复制,这个复制会申请新的内存
index=[1,2,-3]
y=a[index]  #花式索引,index指定了索引位置,会返回数组中在索引位置的值
mask=np.array([0,1,1,0,0],dtype=bool)
a[mask] #用布尔数组来花式索引,为真的返回,该数组必须和原数组长度相等
a[(0,1,2,3,4),(1,2,3,4,5)] #二维数组的索引一一对应行列坐标
mask=np.array([1,0,1,0,0],dtype=bool)
a[mask,2] #布尔类型花式索引,mask为真的行,第三列
a[mask]  #mask为真的行的全部数据
#花式索引返回的是原对象的一个复制而不是引用
where(array) #where函数会返回所有非零元素的索引
np.where(a>10) #返回满足where条件的数的索引
a[a>10] #直接用数组操作上述语句
多维数组
a=np.array([[1,2,3,4],[2,3,4,5]]) #一个为一行
a[1,3] #行索引,列索引 行索引在逗号前,列索引在逗号后
a[1]  #返回一维,返回一行
a[:,1] #返回一列
a[0,3:5] #第一行的第4和第5个元素
a[4:,4:] #第四行到最后一行,第四列到最后一列
a[2::2,::2] #起始行:结束行:行步长,起始列:结束列:列步长
类型转换
a=np.array([1.5,-3],dtype=float) #dtype定义数组类型
np.asarray(a,dtype=float) #asarray定义数组类型
a.astype(float) #astype定义数组类型,并不改变数组原本的类型

数组排序

np.sort() #sort函数对数组进行排序,排完并不改变数组原数
order=np.argsort() #返回从小到大的排列在数组中的索引位置

取值

np.max()
.max() #最大值最小值min,均值mean,标准差std同理
np.cov(a,b) #相关系数矩阵

多维数组操作

a.shape=2,3 #对数组形状进行改变此处为2行3列,修改了数组的值
a.reshape(2,3) #不改变数组的值,而是创建一个新数组
a.T 
a.transpose #数组转置操作
a.np.concatenate((x,y))
np.vstack #默认沿着第一维进行连接
a.np.concatenate((x,y),axis=1)
np.hstack #沿着第二维进行连接
np.vstack #沿着第三维进行连接

其他内置函数

np.abs()
np.exp() #指数
np.median() #中值
np.cumsum() #累积和
...

Pandas

导入:import pandas as pd

基本结构

series
s=pd.Series([1,3,5,np.nan,6,8],index=['a','b','c','d','e','f']) #一维列表初始化,第四个的值为nan,index为索引,没有索引默认数字12345...
s.index #查看数据行标签
s.values #查看值 
s[3] #查看
s[2:5] #切片
s.index.name='索引' #索引赋值
s.index=list('abcdef')
s['a':'c'] #索引赋值 全闭区间
DataFrame

二维结构

date=pd.date_range('20180101',periods=6) #构造
df=pd.DataFrame(np.random.randn(6,4))  #传入二维数据
df=pd.DataFrame(np.random.randn(6,4),index=date,columns=list('ABCD'))
#column和index不指定时值用从0开始的数字替代

image-20231022162054936.png

df2=pd.DataFrame({'A':1.,'B':pd.Timestamp('20181001'),'C':pd.Series(1,index=list(range(4)),dtype=float),'D':np.array([3]*4,dtype=int),'E':pd.Categorical(['test','train','test','train']),'F':'abc'})
#用字典传入数据,只要求每一列数据格式相同

image-20231022164620747.png

查看数据

.head() # .tail(3) 查看头尾,内部写数字
.index #查看下标
.column #列标查看
.values #查看数据值
pandas读取数据及数据操作

df为例子

pd.read_excel(r'路径') #读取
.iloc[0] #行操作 [0:5]前五行,左闭右开区间
.loc[] #两闭区间[0:5]前六行
dit={'名字':'复仇者联盟','':'','':'',} 
s=pd.Series(dit)
s.name=38738  
df=df.append(s)#添加一行,需要覆盖原来的df
df=df.drop([38738])#删除一行
df.columns #看列
df[['名字','类型','','']][:5] #看列值,后面是展示几行
df['序号']=range(1.len(df)+1) #增加一列
df=df.drop['序号',axis=1] #删除一列 需要加入axis=1来表示删除的是列
df.loc[1,'名字'] #根据标签选择数据
df.loc[[1,3,5,7],[' ',' ']] #根据标签选择数据

df['产地']=='美国' #条件选择,得到真,假
df[df['产地']=='美国'][:5] #条件选择,出来的是具体数值
df[(df.产地=='美国')&(df.评分>9)] #多个条件选择
df[(()|())&()]#多个条件嵌套

缺失值及异常值处理

df.isnull() #判断缺失值
df[' '].isnull()#判断具体列的缺失
df[df[' '].isnull()]#列出需要的缺失值
df[df[' '].notnull()]#列出没有缺失值

df[' '].fillna(np.mean(df[' '],inplace=True) #填充中值
               #inplace=True 在原始数据上直接修改
df1.fillna('未知电影') #用未知电影填充所有空
df1[df1['名字'].isnull()][:10] #填充
删除缺失值
.dropna() #删除缺失值
.dropna(inplace=True) #inplace=True 覆盖之前的数据
#how='all' 删除全空的行或者列
#axis=0/1 选择行或者列
处理异常值

异常值,又称为离群点(如年龄为-1)不影响整体数据的分布的直接删除

df=df[df.投票人数>0]
df=df[df['投票人数']%1==0] #直接删除掉数据
数据保存

数据处理后,将数据重新保存到movie_data

df.to_excel('movie_data.xlsx')

数据格式转换

df['投票人数']=df['投票人数'].astype('int') #重新赋值数据格式
#遇到报错的情况:找出错误的值 df[df.年代=='2008\u200e'] 
#重新赋值 df.loc[14934,'年代']=2008
#直接删除 df.drop([  ],inplace=True) 

数据排序

.sort_values(by='投票人数')#括号里是按照哪个值进行排序,默认升序 ascending=Flase 为降序
.sort_values(by=['评分','投票人数'])#多条件排序,顺序按照写的顺序

基本统计分析

df.describe() #描述性统计,对数值型数据进行描述性统计,用来寻找异常值 
#用df[df[  ]>100]的方式来寻找错误数据
#用df.drop(df[df[ ]>1000.index,inplace=True)直接删除
#df.index=range(len(df)) 根据现在的数据长度,生成新的index
df['投票人数'].max() #找最值 min最小 mean均值 median中值
#var方差 std标准差 sum求和
df[['投票人数','评分']].corr #相关系数 cov协方差
len(df) #查看计数
df['产地'].unique() #列出唯一值,当有可以合并的东西时,通过替换来合并
df['产地'].replace('USA','美国',inplace='True')#用替换进行合并
df['产地'].replace(['西德','苏联'],['德国','俄罗斯'])#列表替换
df['年代'].values_counts() #对各个唯一值的数量进行计数

数据透视

对数据类型的值进行统计分析

pd.pivot_table(df,index=['年代']) #前为是什么数据,后为索引,统计汇总所有数值类型
pd.set_option('max_columns',100)
pd.set_option('max_rows',500) #设置展示多少行列(当前版本好像不行)
pd.pivot_table(df,index=['年代','产地'],values=['评分']) #指定需要统计汇总的数据
pd.pivot_table(df,index=['产地'],values=['投票人数','评分'],aggfunc[np.sum,np.mean]) #利用 aggfunc指定函数来统计多个不同的统计值
pd.pivot_table(df,index=['年代','产地'],values=['投票人数','评分'],aggfunc=[np.sum,np.mean],fill_value=0)#将非数值设置为0
#加入margins=True显示总和
pd.pivot_table(df,index=['年代','产地'],values=['投票人数','评分'],aggfunc={'投票人数':np.sum,'评分':np.mean},fill_value=0,margins=True)#通过传入字典对不同值执行不同的函数
#透视过后为DataFrame的格式

数据重塑和轴向旋转

层次化索引

层次化索引能使我们在一个轴上拥有多个索引

s=pd.Series(np.arange(1,10),index=[['a','a','a','b','b','c','c','d','d'],[1,2,3,1,2,3,1,2,3]]) #创建
s['a':'c'] #从a到c切片
s[:,1] # 前面'a':'c'为外层,后为内层,此处为内层为1的索引和值
s['a',1] #a1对应的值
s.unstack() #转化为df格式
s.unstack().stack() #转化回层次化索引

image-20231023205242893.png

image-20231023213921726.png

image-20231023214604955.png

层次化索引使用

data=pd.DataFrame(np.arange(12).reshape(4,3))

image-20231023215300483.png

data=pd.DataFrame(np.arange(12).reshape(4,3),index=[['a','a','b','b'],[1,2,1,2]])

image-20231023215431306.png data=pd.DataFrame(np.arange(12).reshape(4,3),index=[['a','a','b','b'],[1,2,1,2]],columns=[['A','A','B'],['Z','X','C']])

image-20231023215515570.png

通过data['A']的形式进行读取列

对各层设置名称:

data.index.names=['row1','row2'] data.columns.names=['col1','col2']

image-20231023220130834.png

data.swaplevel('row1','row2') 交换row1,row2名称位置

df=df.set_index(['产地','年代']) #重设索引,把列变成索引
#reset_index 把索引变成列
df.index #每一个索引都是一个元组
df.loc['美国'] #获取美国电影,产地信息变成索引,所以使用用loc方法
df=df.swaplevel['产地','年代'] #调整行的顺序
.T #行列转换
GroupBy技术

实现数据的分组,分组运算,作用类似于数据透视表

group=df.groupby(['产地']) #按照产地进行分组
type(group) #定义以一个分组变量
group.mean() 
group.sum()
#计算分组后的各个统计量
df['评分'].groupby(df['年代']).mean() #根据年代来分组统计评分的平均数
df['年代']=df['年代'].astype('str') #只会对数值变量进行分组运算,不需要的换成其他格式
df.groupby([df['产地'],df['年份']]).mean() #传入多个分组变量
df['评分'].groupby(df['产地'],df['年代']) #获得每个地区,每一年的电影评分的均值
means.unstack()#series 通过unstack方法转化为df会产生缺失值
离散化处理

区间化,分组化

pd.cut(df['评分'],[0,3,5,7,9,10]) #所属区间设定,默认左开右闭
df['评分等级']=pd.cut(df['评分'],[0,3,5,7,9,10],labels=['E','D','C','B','A']) 
#用labels替换区间
bins=np.percentile(df['投票人数'],[0,20,40,60,80,100])
df['热门程度']=pd.cut(df['投票人数'],bins,labels=['E','D','C','B','A']) 
#投票越多热门程度越高的设置
df[(df.热门程度=='A')&(df.评分等级=='E')] #寻找设定等级的数据
合并数据集合
df_usa=df[df.产地=='美国']
df_china=df[df. 产地=='中国大陆']
#拆分数据
df_china.append(df_usa) #当前版本会报错,不常用,被弃

merge

pd.merge(left,right,how='inner',on=None,right_on=None,left_index=Flase,right_index=Flase,sort=True,suffixes=('_x','_y'),cope=True,indicate=False)
#left:一个对象 right:另一个对象 
#on:要加入的列名称,必须在左右综合对象中找到
#left_on:从左边的综合使用作为键列 right_on:从右边...
#left_index:如果为True,则用行标签从左综合作为其连接键
#sort:综合通过联结键按字典顺序对结果进行排序,默认值为True,设置为Flase将大幅度提高性能
pd.merge(df1,df2,how='inner',on='名字') #有相同的量换为_x,_y代表

concat:将多个数据集进行批量合并

df1=df[:10]
df2=df[100:200]
df3=df[200:210]
#进行数据拆分
df4=pd.cincat([df1,df2,df3],axis=0) #进行数据合并,axis=0默认添加行,axis=1为添加列

Matplotlib

导入import matplotlib.pyplot as plt

plt.ylabel('y')
plt.xlabel('x')#设定xy轴名称
plt.plot([1,2,3,4],[1,4,9,16]) #传入x和y
plt.plot([1,2,3,4],[1,4,9,16],'ro') #从后面的组合进行对形式进行指定
plt.axis([0,6,0,20]) #axis([xmin,xmax,ymin,ymax])

image-20231027004925502.png

image-20231027005006559.png

t=np.arange(0.,5.,0.2) #0-5 步长0.2
plt.plot(t,t,'r--',t,t**2,'bs',t,t**3,'g^')#一个图里画多条线,传入多个函数
x=np.linspace(-np.pi,np.pi)
y=np.sin(x)
plt.plot(x,y,linewidth=4.0) #关键词改变线条性质 linewidth,color
line1,line2=plt.plot(x,y,'r-',x,y+1,'g-') #赋值给line1,2用返回值来设置线条属性
line1.set_antialiased(False)#关闭平滑
line=plt.plot(x,y)
plt.setp(line,'color','r','linewidth',4)#plt.setp()修改线条性质
子图
plt.figure(num) #figure()函数会产生一个指定编号为num的图,figure(1)可以省略因为会默认自动产生一张图像
plt.subplot(numrows,numcols,fignum)#subplot可以在一幅图中生成多个子图,此为参数,行数,列数(211)->两行,一列的图,共有2*1张,此为第一张
#当numrows*numcols<10时,中间的逗号可以省略(211)==(2,1,1)
def f(t):
    return np.exp(-t)*np.cos(2*np.pi*t)
t1=np.arange(0.0,5.0,0.1)
t2=np.arange(0.0,5.0,0.02)

plt.figure(figsize=(10,6))#图的长宽
plt.subplot(211)#第一张图
plt.plot(t1,f(t1),'bo',t2,f(t2),'k')

plt.subplot(212)#第二张图
plt.plot(t2,np.cos(2*np.pi*t2),'r--')


柱状图(bar)
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False #设置中文字体
x=data.index
y=data.values
#设定x,y轴
plt.figure(figsize=(10,6))#设定长宽
plt.bar(x,y,color='g')#bar设置柱状图
plt.title('国家地区电影数量',fontsize=20)#设置标题和标题字体
plt.xlabel('国家或地区',fontsize=18)
plt.ylabel('电影数量',fontsize=18)#设置xy轴标签
plt.tick_params(labelsize=14)#设置x轴上量的字大小
plt.xticks(rotation=90)#将图旋转90度
for a,b in zip(x,y):#打包循环操作
    plt.text(a,b+10,b,ha='center',va='bottom')#a:添加文本到x轴的位置 b:添加文本y轴的位置 b:显示在文本上的数据,ha水平,va垂直,center居中,bottom数字的底端是柱子,top在数字上面是柱子
plt.grid()#加上网格
曲线图(plot)
x=data.index
y=data.values
plt.plot(x,y,color='b')
plt.title('每年电影数量',fontsize=20)
plt.xlabel('年份',fontsize=18)
plt.ylabel('电影数量',fontsize=18)#设置xy轴标签
for a,b in zip(x[::10],y[::10]): #每隔十年进行显示
    plt.text(a,b+10,b,ha='center',va='bottom',fontsize=10)
plt.annotate('2012年达到最大值',xy=(2012,data[2012]),xytext=(2025,2100),arrowprops=dict(facecolor='black',edgecolor='red'))#特别标注的 设置横纵坐标位置 xy注释位置 xytext注释文字位置  arrowprops为箭头设置 facecolor填充颜色 edgecolor边缘颜色
plt.text(1980,1000,'电影开始快速增长')#设定横纵坐标和文字,在指定位置放入文字
饼图(pie)
pie(x,explode=None,labels=None,colors=None,autopct=None,pctdistance=0.6,shadow=False,labeldistance=1.1,startangle='None',radius='None')
#x:每一块的比例 labels:每一块饼图外面显示说明的文字 explode:每一块离开中心的距离 startangle:起始绘制角度,默认是从x轴正方向逆时针花旗,如=90则从y轴正方向画起 labeldistance label绘制位置相对于半径的比例 autopct饼图百分比格式设置 pctdistance指定autopct的位置刻度 radius饼图半径
data=pd.cut(df['时长'],[0,60,90,110,1000]).value_counts()#离散化
y=data.values
y=y/sum(y)#可要可不要,会自动
plt.figure(figsize=(10.10))
plt.title('电影时长占比',fontsize=15)
patches,l_text,p_text,plt.pie(y,labels=data.index,autopct='%.1f %%',colors='bygr')#l_text饼图外部文字 p_text饼图内部字体
for i in p_text:
    i.set_size(15)
    i.set_color('w')
for i in l_text:
    i.set_size(15)
    i.set_color('w')
plt.legend()#增加图例
频率分布直方图(hist)
plt.figure(figsize=(10,6))
plt.hist(df['评分'],bins=20,edgecolor='k',alpha=0.5)#bins柱子的多少 arr需要计算直方图的一维数组 edgecolor/facecolor alpha透明度 histtype直方图类型:bar narstackes step stepfilled 

双轴图(同一个x轴两个y轴)
fig=plt.figure(figsize=(10,8))
ax1=fig.add_subplot(111)
n,bins,patches=ax1.hist(df['评分'],bins=100,color='m')
ax1.set_ylabel('电影数量',fontsize=15)
ax1.set_xlabel('评分',fontsize=15)
ax1.set_title('频率分布图',fontsize=20)
y=mlab.normpdf(bins,df['评分'].mean(),df['评分'].std())
ax2=axl.twinx()
ax2.plot(bins,y,'b--')
ax2.set_ylabel('概率分布',fontsize=15)
散点图(scatter)
x=df['时长'][::100]#间隔100
y=df['评分'][::100]#间隔100
plt.figure(figsize(10,6))
plt.scatter(x,y,color='c',marker='p')#散点图,后面调整形状颜色等参数设置
plt.legend()
plt.title('电影时长与评分散点图',fontsize=20)
plt.xlabel('时长',fontsize=18)
plt.ylabel('评分',fontsize=18)

image-20231028014644593.png

image-20231028014655316.png

箱型图

image-20231028014827934.png

image-20231028014913578.png

data=df[df.产地=='美国']['评分']
plt.figure(figsize=(10,6))
plt.boxplot(plt.boxplot(data,whis=2,flierprops={'marker':'o','markerfacecolor':'r','color':'k'},patch_artist=True,boxprops={'color':'k','facecolor':'#9999ff'})) #whis为异常值范围,越大允许范围越大 flierprops设置异常值的属性 patch_artist箱体的颜色

plt.title('美国电影评分',fontsize=20)
data1=df[df.产地=='中国大陆']['评分']
data2=df[df.产地=='日本']['评分']
data3=df[df.产地=='中国香港']['评分']
data4=df[df.产地=='英国']['评分']
data5=df[df.产地=='法国']['评分']
plt.figure(figsize=(12,8))
plt.boxplot([data1,data2,data3,data4,data5],labels=['中国大陆','日本','中国香港','英国','法国'],whis=2,flierprops={'marker':'o','markerfacecolor':'r','color':'k'},patch_artist=True,boxprops={'color':'k','facecolor':'#9999ff'},vert=False)
#vert用来旋转表格
ax=plt.gca()#得到当前坐标系
ax.patch.set_facecolor('gray')#设置背景色
ax.patch.set_alpha('0.3')#背景色透明度
#多组数据箱线图
相关系数矩阵图--热力图
data=df['投票人数','评分','时长']
%pylab inline #使图片展示出来
result=pd.sactter_matrix(data[::100,]diagonal='kde',color='k',alpha=0.3,figsize=(10,10))#pandas本身封装了画图函数
seaborn
import seaborn as sns#一个用来画热力图的库
corr=data.corr()
corr=abs(corr)

fig=plt.figure(figsize(10,8))
ax=fig.add_subplot(figsize=(10,8))

ax=sns.heatmap(corr,vamx=1,vmin=0,annot=True,annot_kws={'size':13,'weight':'bold'},linewights=0.05)#data矩阵数据集 vminvmax热力图的颜色取值的最大和最小值 annot对热力图块注释 annot_kws注释
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)