数据分析
1.matplotlib折线图
matplotlib:最流行的Python底层绘图库,主要做数据可视化图表,名字取材于MATLAB,模仿MATLAB构建
from matplotlib import pyplot as plt
'''
设置图片大小
figure表示图形图标的意思,这里指画的图
通过实例化一个figure并且传递参数,能够在后台自动使用该figure实例
在图像模糊的时候可以传入dpi参数,让图片更加清晰
'''
fig = plt.figure(figsize=(20,8),dpi = 80)
x = range(120)
y = [15,13,14.5,17,20,25,26,26,24,22,18,15]
#传入x和y,通过plot绘制折线图
plt.plot(x,y)
#设置x的刻度
plt.xticks(x)
plt.savefig("fig1.png") #保存图片
#在执行程序的时候展示图形
plt.show()
实例
假设大家在30岁的时候,根据自己的实际情况,统计出来了你和你同桌各自从11岁到30岁每年交的女(男)朋友的数量如列表a和b,请在一个图中绘制出该数据的折线图,以便比较自己和同桌20年间的差异,同时分析每年交女(男)朋友的数量走势
a = [1,0,1,1,2,4,3,2,3,4,4,5,6,5,4,3,3,1,1,1]
b = [1,0,3,1,2,2,3,3,2,1 ,2,1,1,1,1,1,1,1,1,1]
要求:
y轴表示个数
x轴表示岁数,比如11岁,12岁等
from matplotlib import pyplot as plt
import random
plt.figure(figsize = (15,8))
x = [i for i in range(11,31)]
a = [1,0,1,1,2,4,3,2,3,4,4,5,6,5,4,3,3,1,1,1]
b = [1,0,3,1,2,2,3,3,2,1 ,2,1,1,1,1,1,1,1,1,1]
plt.plot(x,a,label = "myself",linestyle = "--",color = "red",alpha = 0.5)
plt.plot(x,b,label = "you",linestyle = "-",color = "orange",alpha = 0.5)
plt.legend(loc="best") #图例的地方
plt.xticks(x[:31:1])
plt.xlabel("age")
plt.ylabel("number")
plt.title("the number of friend in this year")
plt.show()
1.1.2 绘制散点图
实例
假设通过爬虫你获取到了北京2016年3,10月份每天白天的最高气温(分别位于列表a,b),那么此时如何寻找出气温和随时间(天)变化的某种规律?
a = [11,17,16,11,12,11,12,6,6,7,8,9,12,15,14,17,18,21,16,17,20,14,15,15,15,19,21,22,22,22,23]
b = [26,26,28,19,21,17,16,19,18,20,20,19,22,23,17,20,21,20,22,15,11,15,5,13,17,10,11,13,12,13,6]
from matplotlib import pyplot as plt
y_3 = [11,17,16,11,12,11,12,6,6,7,8,9,12,15,14,17,18,21,16,17,20,14,15,15,15,19,21,22,22,22,23]
y_10 = [26,26,28,19,21,17,16,19,18,20,20,19,22,23,17,20,21,20,22,15,11,15,5,13,17,10,11,13,12,13,6]
x_3 = range(1,32)
x_10 = range(51,82)
plt.figure (figsize = (20,8),dpi=80)
plt.scatter(x_3,y_3,label = "March")
plt.scatter(x_10,y_10,label = "October")
#调整x轴的刻度
_x= list(x_3)+list(x_10)
_xtick_labels = ["3.{}".format(i) for i in x_3]
_xtick_labels +=["10.{}".format(i-50) for i in x_10]
plt.xticks(_x[::3],_xtick_labels[::3])
#添加图例
plt.legend(loc="upper left")
#增加描述信息
plt.xlabel("Day")
plt.ylabel("Temperature")
plt.title("Title")
plt.show()
1.1.3 绘制条形图
#绘制竖向条形图
plt.bar(x,y,width=0.3)
#绘制横向条形图
plt.barh(x,y,width=0.3)
1.1.4 绘制多次条形图
假设你知道了列表a中电影分别在2017-09-14(b_14), 2017-09-15(b_15), 2017-09-16(b_16)三天的票房,为了展示列表中电影本身的票房以及同其他电影的数据对比情况,应该如何更加直观的呈现该数据?
a = ["Film1","Film2","Film3","Film4"]
b_16 = [15746,312,4497,319]
b_15 = [12357,156,2045,168]
b_14 = [2358,399,2358,362]
from matplotlib import pyplot as plt
a = ["Film1","Film2","Film3","Film4"]
b_16 = [15746,312,4497,319]
b_15 = [12357,156,2045,168]
b_14 = [2358,399,2358,362]
bar_width = 0.2
x_14 = list(range(len(a)))
x_15 = [i+bar_width for i in x_14]
x_16 = [i+bar_width*2 for i in x_14]
plt.figure(figsize=(20,8),dpi=80)
plt.bar(range(len(a)),b_14,width=bar_width,label="Sep.14")
plt.bar(x_15,b_15,width=bar_width,label="Sep.15")
plt.bar(x_16,b_16,width=bar_width,label="Sep.16")
plt.legend()
plt.xticks(x_15,a)
plt.xlabel("film")
plt.ylabel("number")
plt.show()
1.1.5 绘制直方图
假设你获取了250部电影的时长(列表a中),希望统计出这些电影时长的分布状态(比如时长为100分钟到120分钟电影的数量,出现的频率)等信息,你应该如何呈现这些数据?
a=[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]
from matplotlib import pyplot as plt
a = [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]
d = 3
num_bins = (max(a)-min(a))
plt.figure(figsize = (20,8),dpi = 80)
plt.hist(a,num_bins)
plt.xticks(range(min(a),max(a)+d,d))
plt.grid()
plt.show()
2. Numpy
Numpy:一个在Python中做科学计算的基础库,重在数值计算,也是大部分PYTHON科学计算库的基础库,多用于在大型、多维数组上执行数值运算。
2.1 数组
2.1.1 数组与数字的运算
#创建数组
a = np.array([[3,4,5,6,7,8],[4,5,6,7,8,9]])
b = np.array(range(1,6))
c = np.arrange(1,6)
#查看数组的类名
type(a) #输出:numpy.ndarray
#查看数据的类型
a.dtype #输出:dtype('int64')
#查看数组的形状
a.shape() #输出:(2,6)
#将二维数据展开为一维的
a.flattern()
#数组的加法,减法,乘法,除法,类似。numpy的广播机制,作用在所有元素上
a + 2
'''
输出
[[ 5 6 7 8 9 10]
[ 6 7 8 9 10 11]]
'''
2.1.2 数组与数组的运算
- 维度一样时,对应位进行运算;
- 维度不同时,若其中一个维度相同,另一个维度为1的话,可以进行运算。否则不能进行运算
import numpy as np
a = np.array([[3,4,5,6,7,8],[4,5,6,7,8,9]])
b = np.array([[1],[2]])
c = a + b
print(c)
#输出:
[[ 4 5 6 7 8 9]
[ 6 7 8 9 10 11]]
广播原则:
如果两个数组的后缘维度,即从末尾开始算起的维度的轴长度相符或其中一方的长度为2,则认为它们是广播兼容的。广播会在缺失和长度为1的维度上进行。
2.1.3 轴的概念
2.2 numpy读取数据
2.2.1 从CSV中读数据
CSV:Comma-Separated Value,逗号分隔值文件
显示:表格状态
源文件:换行和逗号分隔行列的格式化文本,每一行的数据表示一条记录
由于csv便于展示,读取和写入,所以很多地方也是用csv的格式存储和传输中小型的数据
np.loadtxt(fname, dtype=np.float, delimiter=None, skiprows=0, usecols=None, unpack=False)
import numpy as np
us_file = "data_numbers.csv"
'''
其中,us_file表示路径;
delimiter表示数据是以什么作为分割的;
dtype表示数据类型,默认情况下对于较大数据会变为科学计数的方式
unpack=true表示将数据矩阵进行转置
'''
np.loadtext(us_file,delimiter=",",dtype="int",unpack = True)
numpy中的转置
t = np.array([[],[],[]])
#第一种
t.transpose()
#第二种,交换0和1轴
t.swapaxes(1,0)
t.T
2.2.2 索引和切片
a[1] #取1行
a[:,2] #取1列
a[1:3] #取多行
a[:,2:4] #取多列
a[:,2:4] = 0
a[t<10] = 0 #将t中<10的都替换为0
#numpy的三元运算符,将<10的替换为0,将>=10的替换为10
np.where(t<10,0,10)
#将<10的替换为10,大于18的替换为18
t.clip(10,18)
2.2.3 numpy中的nan和inf
nan(NAN,Nan):not a number表示不是一个数字。当我们读取本地的文件为float的时候,如果有缺失,就会出现nan
当做了一个不合适的计算的时候(比如无穷大(inf)减去无穷大)inf(-inf,inf):infinity,inf表示正无穷,-inf表示负无穷。比如一个数字除以0,(python中直接会报错,numpy中是一个inf或者-inf)。
#指定一个nan或inf
a = np.inf
b = mp.nan
type(a) #输出:float
type(b) #输出:float
2.2.4 numpy中常用统计函数
#其中,默认返回多维数组的全部统计结果,如果指定axis则返回一个当前轴上的结果
t.sum(axis=None) #求和
t.mean(a,axis=None) #均值
t.median(t,axis=None) #中值
t.max(axis=None) #最大值
t.min(axis=None) #最小值
np.ptp(t,axis=None) #极差
t.std(axis=None) #标准差
2.3 其他一些方法
2.3.1 数组的拼接
#竖直拼接
np.vstack((t1,t2))
#水平拼接
np.hstack((t1,t2))
2.3.2 数组的行列交换
#行交换
t[[1,2],:] = t[[2,1]:]
#列交换
t[:,[0,2]] = t[:,[2,0]]
2.3.3 一些方法
#获取最大值,每一行的最大值位置
np.argmax(t,axis=0)
#获取最小值,每一列最大值的位置
np.argmin(t,axis=1)
#创建全为0的数组
np.zeros((3,4))
#创建全为1的数组
np.ones((3,4))
#创建对角线为1的正方形数组(方阵)
np.eve(3)
2.3.4 生成随机数
#创建一个4*5的在10-20之间的整数
np.random.randint(10,20,(4,5))
#随机数种子,s是给定的种子值,通过设定相同的随机数种子,可以每次生成相同的随机数
np.random.seed(10)
t=np.random.randint(0,20,(3,4))
print(t)
2.3.5 copy与view
- a=b 完全不复制,a和b相互影响;
- a = b[:],视图的操作,一种切片,会创建新的对象a,但是a的数据完全由b保管,他们两个的数据变化是一致的;
- a = b.copy(),复制,a和b互不影响。
3. Pandas
numpy能够帮助我们处理数值,但是pandas除了处理数值之外(基于numpy),还能够帮助我们处理其他类型的数据。
pandas的常用数据类型:
- Series 一维,带标签数组;
- DataFrame 二维,Series容器。
3.1 Series
3.1.1 创建
- 通过一个列表创建;
- 通过一个字典创建,前面为值,后面为键。
import pandas as pd
import string
import numpy as np
#前面为数值,后面为键
t = pd.Series(np.arange(10),index = list(string.ascii_uppercase[:10]))
print(t)
print(t.dtype) #输出:int
print(type(t))
#通过字典方式创建
a ={"age":22,"name":"Mary","emotion":"happy"}
print(a)
print(type(a))
a = pd.Series(a) #创建Series
print(a)
print(a.dtype) #输出:object。只要有字符串就是object
print("*"*100)
b = {string.ascii_uppercase[i]: i for i in range(10)}
b = pd.Series(b,index=list(string.ascii_uppercase[5:15]))
print(b)
print(b.dtype)
3.1.2 切片和索引
- 切片:直接传入start,end或者步长即可;
- 索引:一个的时候直接传入序号或者index,多个的时候传入序号或者index的列表。
import pandas as pd
import string
import numpy as np
b = {string.ascii_uppercase[i]: i for i in range(10)}
b = pd.Series(b,index=list(string.ascii_uppercase[5:15]))
print(b)
print(b.dtype)
print(b[2:10:2])
print(b[[5,6,7]]) #注意两层括号索引
print(b[b>6])
print(b[["F","H","I"]])
print(b.index)
print(b.values)
print(type(b.index))
print(type(b.values))
#输出:
Index(['F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'], dtype='object')
[ 5. 6. 7. 8. 9. nan nan nan nan nan]
因此,Series对象本质上由两个数组构成,一个数组构成对象的键(index,索引),一个数组构成对象的值(values),键->值。
2.1.3 读取外部数据
#pandas读取CSV中的文件
df = pd.read_csv("myfile.csv")
2.2 DataFrame
import pandas as pd
import numpy as np
a = pd.DataFrame(np.arange(12).reshape(3,4))
print(a)
#指定行索引和列索引
b = pd.DataFrame(np.arange(12).reshape(3,4),index=list("abc"),columns=list("wxyz"))
print(b)
#通过字典传入数据,一种方式
c = {"name":["xiaoming","xiaogang"],"age":[20,32],"tel":[10085,34895]}
c = pd.DataFrame(c)
print(c)
#第二种方式
d=[{"name":"xiaohong","age":32,"tel":10058},{"name":"xiaogang","age":32,"tel":11058}]
d = pd.DataFrame(d)
print(d)
d=[{"name":"xiaohong","age":32,"tel":10058},{"name":"xiaogang","age":32,"tel":11058},{"name":"xiake","age":52,"tel":10038}]
d = pd.DataFrame(d)
print(d.shape) #行数,列数
print(d.dtypes) #列数据类型
print(d.ndim) #数据维度
print(d.index) #行索引
print(d.columns) #列索引
print(d.values) #对象值,二维ndarray数组
print("+"*100)
print(d.head(2)) #显示头部前2行
print(d.tail(2)) #显示尾部后2行
print(d.info()) #相关信息概览:行数,列数,列索引,列非空值个数
print("/"*100)
print(d.describe()) #快速综合统计结果:计数,均值,标准差,最大值,四分位数,最小值
DataFrame对象既有行索引,又有列索引。
行索引,表明不同行,横向索引,叫index,0轴,axis=0;
列索引,表明不同列,纵向索引,叫columns,1轴,axis=1。
2.2.1 取行或取列及数据的处理
import pandas as pd
import numpy as np
b = pd.DataFrame(np.arange(12).reshape(3,4),index=list("ABC"),columns = list("WXYZ"))
print(b)
#loc通过标签索引行数据
b.loc["A","W"]
b.loc["A",["W","Z"]]
b.loc[["A","C"],["W","Z"]]
b.loc["A":"C",["W","Z"]]
#iloc通过位置获取行数据
b.iloc[1:3,[2,3]]
b.iloc[1:3,1:3]
#赋值更改数据
b.iloc[1:2,0:2] = 200
b.loc["A","Y"] = 100
#实现布尔索引,不同的额条件之间需要用括号括起来
b[(b["Row_Labels"].str.len()>4) & (b["Count_AnimalName"]>700)]
'''
缺失数据常见的处理方式
判断数据是否为NaN:
处理方式1:删除NaN所在的行列
处理方式2:填充数据
'''
pd.isnull(b)
pd.notnull(b)
b.dropna(axis = 0,how='any',inplace=False) #方式1
b.fillna(b.mean()) #方式2,填充平均值
b.fiallna(b.median()) #方式2,填充中位数
b.fillna(0) #方式3,填充0
#处理为0的数据
b[b==0]=np.nan
2.2.2 数据合并
import pandas as pd
import numpy as np
t1 = pd.DataFrame(np.ones((2,4)),index=["A","B"],columns=list("abcd"))
t2 = pd.DataFrame(np.zeros((3,3)),index=["A","B","C"],columns=list("xyz"))
#按照行索引进行合并
print(t1.join(t2))
print(t2.join(t1))
#输出:
a b c d x y z
A 1.0 1.0 1.0 1.0 0.0 0.0 0.0
B 1.0 1.0 1.0 1.0 0.0 0.0 0.0
x y z a b c d
A 0.0 0.0 0.0 1.0 1.0 1.0 1.0
B 0.0 0.0 0.0 1.0 1.0 1.0 1.0
C 0.0 0.0 0.0 NaN NaN NaN NaN
#merge,这是有相同值的情况
t1.merge(t2,on="a") #默认内连接,求交集
t1.merge(t2,on='a',how="outer") #外连接,并集
t1.merge(t2,on="a",how="left") #以t1为准,并集
t1.merge(t2,on="a",how="right") #以t2为准,并集
#若没有相同值ze进行指定列索引
t1,mnerge(t2,left_on="o",right="x",how="outer")
2.3 分组和聚合
这里的内容类似SQLserver中的内容,在此没有深究。如果不常用的话容易忘记。
2.4 时间序列
pd.date_range(start=None, end=None, periods=None, freq='D')
start和end以及freq配合能够生成start和end范围内以频率freq的一组时间索引
start和periods以及freq配合能够生成从start开始的频率为freq的periods个时间索引
t4 = pd.date_range(start="20170101",end="20171225",freq="BM")
print(t4)
#输出:
DatetimeIndex(['2017-01-31', '2017-02-28', '2017-03-31', '2017-04-28',
'2017-05-31', '2017-06-30', '2017-07-31', '2017-08-31',
'2017-09-29', '2017-10-31', '2017-11-30'],
dtype='datetime64[ns]', freq='BM')
关于频率的更多缩写,如图。
2.4 重采样
重采样:指的是将时间序列从一个频率转化为另一个频率进行处理的过程,将高频率数据转化为低频率数据为降采样,低频率转化为高频率为升采样。
pandas提供了一个resample的方法来帮助我们实现频率转化。
具体的应用实例不学习了,数据分析入门结束,接下来进入正题。