数据分析三剑客numpy,pandas,matplotlib学习总结

数据分析三剑客numpy,pandas,matplotlib学习总结

numpy,pandas,matplotlib可谓是数据分析的好伙伴,对于处理庞大数据有奇效,奇思妙想让我们的开发起飞
我个人理解numpy的作用是读取简单的数据型数据,再对数据进行各种各样的操作;pandas相比于numpy 可以读取的数据就不局限与数据型,文本型,字符串型都可以,同时可以插入行和列的表头;matplotlib可以将处理好的数据可视化的展现出来

首先三者的使用都需要导入外部包,确认是否已经安装

pip3 install numpy
pip3 install pandas
pip3 install matplotlib

一.numpy

距离起飞只差一个导包

# 导包并取别名
import numpy as np

首先先看一些简单的操作

打印一个数组

array = np.array([[1, 2, 3],
                 [2, 3, 4]])

->[[1 2 3] [2 3 4]]

聪明的你很容易发现这和我们python中的list很像,但是在处理大量数据情况下,由于numpy底层由c语言实现,效率比list高多了

其实我们不妨打印一下t1的类型,差别就一目了然

print(type(t1))

-><class ‘numpy.ndarray’>

诶这就有意思了,这个数据类型从来没见到过,ndarray是个什么类型?
其实这就是numpy中专门的一个数据类型–多维数组

接下来再来讲一些简单的操作

array = np.array([[1, 2, 3],   
                 [2, 3, 4]])
# 输出维度
print('number of dim:',array.ndim)
# 输出数组的形状
print('shape',array.shape)
# 输出元素个数
print('size',array.size)
print(array.dtype)

->2
->(2,3)
->6
->int32
需要说明数组内的元素的类型默认是根据当前平台自动选择,当然也可也自己设定(以下两种都可以)

array1 = np.array([2,3,4],dtype = np.float)
array2 = np.array([2,3,4],dtype = "float")

很简单对吧,我们上点难度

  • 首先看看arange,和python中的range差不多,相对于的就有两种写法,效果是一样的
array1 = np.arange(12).reshape(3,4)
array2 = np.array(range(12)).reshape(3,4)
  • 起飞过快刹下车:上述代码提到的reshape是干嘛的呢,arange的数组是一个一维数组,reshape就能把数组重新塑形,变成形如(3,4)的二维数组,需要注意前面元素数量要和后方括号内乘积相等

特别注意
若我们想把一个二维矩阵展开成一维矩阵,实用reshape方法需注意以下区别

在讲reshape转换维度的时候,我的理解为传入几个参数就转换成几维数组,所以对于3行4 列矩阵展开成一维数组要写(12,)--------(12,1)或(1,12)的情况如下
序列不能通过转置变成一列print(A[np.newaxis,:]) 增加了行的维度 (,1)->(1,3)
print(A[:,np.newaxis]) 增加了列的维度(,1)->(3,1)

array = np.array([[0, 1, 2, 3],
 [4, 5, 6, 7],
 [8,  9, 10, 11]])
 print(array.reshape(12,1)
 print(arrat.reshape(1,12)

->[[ 0]
[ 1]
[ 2]
[ 3]
[ 4]
[ 5]
[ 6]
[ 7]
[ 8]
[ 9]
[10]
[11]]
->[[ 0 1 2 3 4 5 6 7 8 9 10 11]]

第二种乍一看挺对的,但仔细看就能发现由两层 [] 是一个一行十二列的矩阵

如此提前引申出一个专门展开矩阵的函数flatten,还是上述例子

array = np.array([[0, 1, 2, 3],
 [4, 5, 6, 7],
 [8,  9, 10, 11]])
 print(array.flatten())

->[ 0 1 2 3 4 5 6 7 8 9 10 11]

  • 再来介绍下linespace,跟arange挺像的
# 自动把[1,10]的元素分成20段
array=np.linspace(1,10,20)
  • 一些实用的矩阵
#  输出3行4列全为0的矩阵
print(np.zeros((3,4)))
# 输出全为1的矩阵
print(np.ones((3,4),dtype=np.int16))
# 输出主对角线为1的方形矩阵  由于考虑到主对角线的方形阵,只需传入一个参数即可
print(np.eye(3))
# 输出几乎为0的矩阵
print(np.empty((3,4)))

如何理解几乎为0,矩阵中的元素数值很小,类似6.23042070e-307,接近0但是不等于0

  • 基础的如何创建一个矩阵相信已经学会,接下来讲一些矩阵的简单运算
  1. 首先想一下一个矩阵加减乘除一个数字,是每一项都执行该操作还是某一项对该数字操作。显而易见,是前者
array = np.array([[0, 1, 2, 3],
 [4, 5, 6, 7],
 [8,  9, 10, 11]])

print(print(array + 1))

->[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]

  1. 矩阵相乘
  • 第一种,只是简单的把相同位置的两项相乘
array = np.array([[0, 1, 2, 3],
 [4, 5, 6, 7],
 [8,  9, 10, 11]])
array1 = np.array([[0, 1, 2, 3],
 [4, 5, 6, 7],
 [8,  9, 10, 11]])
print(print(array * array1))

->[[ 0 1 4 9]
[ 16 25 36 49]
[ 64 81 100 121]]

  • 第二种 线代内的矩阵相乘
array = np.array([[0, 1, 2, 3],
 [4, 5, 6, 7],
 [8,  9, 10, 11]])
array1 = np.array([[0, 1, 2],
 [4, 5, 6],
 [8,  9, 10],
 [3, 7, 11]])
print(np.dot(array,array1))

->[[ 29 44 59]
[ 89 132 175]
[149 220 291]]

  1. 一些常用的数学统计函数
array = np.array([[0, 1, 2, 3],
 [4, 5, 6, 7],
 [10, 11, 12, 13]])
 # 取最大值,不指定坐标默认全部最大值
print(np.max(array))
print(np.max(array, axis=0))
# 取最小值
print(np.min(array, axis=0))
# 取平均值
print(np.mean(array, axis=0))
# 取中位数
print(np.median(array,axis=0))
# 取最大值的下标
print(np.argmax(array,axis=0))
# 取最小值的下标
print(np.argmin(array, axis=0))
# 逐项相加,每一项等于前面所有项的和
print(np.cumsum(array))
# 每行元素与前一行元素的差
print(np.diff(array))
# 裁剪 小于5的替换成5,大于10的替换成10
print(array.clip(5,10))
# 转置(三种方法)
print(array.T)
# print(array.transpose())
# print(array.swapaxes(1,0))

# 计算标准差 反应数据的离散程度
print(np.std(array))
# 取极值
print(np.ptp(array))

->13
->[10 11 12 13]
->[0 1 2 3]
->[4.66666667 5.66666667 6.66666667 7.66666667]
->[4. 5. 6. 7.]
->[2 2 2 2]
->[0 0 0 0]
->[ 0 1 3 6 10 15 21 28 38 49 61 74]
->[[1 1 1]
[1 1 1]
[1 1 1]]
->[[ 5 5 5 5]
[ 5 5 6 7]
[10 10 10 10]]
->[[ 0 4 10]
[ 1 5 11]
[ 2 6 12]
[ 3 7 13]]
->4.258977446393546
->13

特别注意

上述方法中我有提及参数 axis=0,这是什么意思呢?
我们的数组是一个二维数组,相对于的就有坐标轴,axis=0 即为第一维度相当于x轴,axis=1就是y轴。那么,上述代码是对每行操作吗?
仔细观一下输出的结果,三行的数组输出了四个元素,这么看好像并不是像我们的惯性思维一样
其实
<axis = 0 按行计算,得到列的性质。
axis = 1 按列计算,得到行的性质。>

确实有点绕,请务必和现实中的坐标轴的惯性思维区分开

加快飞行速度(进阶)

切片和索引

numpy的切片和python是很像的,很好上手

  1. 行列切片
    取一行的时候可以不传入列
array = np.array([[0, 1, 2, 3],
 [4, 5, 6, 7],
 [8,  9, 10, 11]])
print(array[1])
print(array[:,1])

->[4 5 6 7]
->[ 1 5 11]

  1. 切片选择多行
  • 连续
print(array[1:,:])

->[[ 4 5 6 7]
[10 11 12 13]]

  • 不连续
print(array[[0,2],:])

->[[ 0 1 2 3]
[10 11 12 13]]

  • 行列具体选择
# (0,1)(2,3)一一对应 取出这两个元素
print(array[[0,2],[1,3]])

->[ 1 13]

  • 切片指向具体单个元素就是索引
    print(array[2,3])

布尔索引
根据条件能筛选元素

array = np.array([[0, 1, 2, 3],
 [4, 5, 6, 7],
 [8,  9, 10, 11]])
 print(array<5)

->[[ True True True True]
[ True False False False]
[False False False False]]

#在根据筛选矩阵传入矩阵就能取出为True的元素
 print(array[array<5])

->[0 1 2 3 4]

  • 三元操作符
# 根据price标签大于50的变成50,小于等于50的变成100
np.where(df['price'>50,50,100]

读取本地数据

# path 为文件路径,dilimiter为分隔符,dtype 设定读取出来数据的类型
np.loadtxt(path,dilimiter,dtype)

虽然方法是txt,也可也读入csv格式的文件

处理丢失数据

在读入数据的时候可能遇到读出来的数据为nan(not a number),这时对其所在行列做各种操作,最后结果都是nan,对我们处理数据造成很大困扰,以下两种方式处理:
1.直接删除为nan的数据
2.将nan替换为指定的数据(中位数/平均值/0):直接换成0是不可取的,例如数据都是负数,增加0会让整体增大

首先介绍下nan的性质:

  1. 两个nan是不相等的,这点很好理解,nan不是一个数字,都不是数字自然没法比较,由此我们可以找到一个找出nan的办法
#astype 转换数据类型,nan并不是int类型无法直接赋值需要先进行转换
array = array.astype("float")
array[1,2] = np.nan
print(array != array)

->[[False False False False]
[False False True False]
[False False False False]]
如此布尔索引的方法便能找出nan的位置方便后续的操作
2. np.isnan(array)实现与上述相同的操作
3. 删除nan

  • 删除包含nan的行列
print(array[~np.isnan(array).any(axis=1)])
print(array[~np.isnan(array).any(axis=0)])

->[[ 0. 1. 2. 3.]
[10. 11. 12. 13.]]

  • 删除该行列全为nan的数据
print(array[:, ~np.isnan(array).all(axis=0)])

->[[ 0. 1. 2. 3.]
[ 4. 5. nan 7.]
[10. 11. 12. 13.]]
4.替换nan

  • 使用 np.nan_to_num()结合isnan()配合布尔索引,可以选择的替换nan为指定的数字
    一般换为中位数或平均数这样对数据影响不大

数据的合并与分隔

  • 合并
A = np.array([1,1,1])
# A = np.array([1,1,1])[:,np.newaxis]变成纵向的
B = np.array([2,2,2])
# 上下合并
C = np.vstack((A,B))# vertical stack
#左右 都可以多个合并
D = np.hstack((A,B))# horizontal stack 
print(C)
print(D)

->[[1 1 1]
[2 2 2]]
->[1 1 1 2 2 2]

  1. C=np.concatenate((A,B,B,A),axis=0)合并多个序列 并能要求是哪个维度的合并
  • 分隔
  1. print(np.split(A,2,axis=1))/ np.hsplit(A,2)纵向分成2块,不能进行不等分隔
  2. print(np.split(A,2,axis=0))/np.vsplit(A,2)横向分隔
  3. print(np.array_split(A,3,axis=1)) 不等分割

numpy 赋值

numpy赋值的时候默认是浅拷贝
浅拷贝:两个变量指向同一块地址,一个变量改变,令一个变量也会改变
因此需要用到深拷贝 b=a.copy()
深拷贝:两个变量真正隔离开,不相互关联

pandas

pandas对于处理各种类型的数据都很好,因此常常用pandas读取数据,再结合numpy处理数据,pandas包含两种结构:Series和DataFrame

前期准备

首先第一步当然需要导包,这是一切的基础

import pandas as pd
import numpy as np

Series

一些简单的尝试

  1. 传入标签数据
t = pd.Series([1,23,445,342,324,6], index =list("abcdef") )
print(t)

->a 1
b 23
c 445
d 342
e 324
f 6
dtype: int64

如此一个简单的尝试就展现了pandas的用处,将数据导入可以插入标签,需要注意标签的数量要和数据数量一致

  1. 传入字典
    处理字典数据显得理所应当
temp_dict = {"name":"cy","age":18,"tel":131}
t1 = pd.Series(temp_dict)
print(t1)

->name cy
age 18
tel 131
dtype: object

DataFrame

Series用的比较少因此也只是粗略介绍,接下来才是重头戏

  • 来个小菜开开胃
# 输出从20130101开始的6个日期
dates = pd.date_range('20130101',periods=6)
# index设置每行的标签,columns设置每列的标签
df = pd.DataFrame(np.arange(24).reshape((6,4)),index=dates,columns=['A','B','C','D'])

->A B C D
2013-01-01 0 1 2 3
2013-01-02 4 5 6 7
2013-01-03 8 9 10 11
2013-01-04 12 13 14 15
2013-01-05 16 17 18 19
2013-01-06 20 21 22 23

  • 导入 各种文件

pandas 提供了丰富的读取文件的方式,可以处理各种类型的文件,以下只展示常用的

df = pd.DataFrame(pd.read_csv('name.csv',header=1))
df = pd.DataFrame(pd.read_excel('name.xlsx'))

  • 自己导入简易数据
df = pd.DataFrame({"id":[1001,1002,1003,1004,1005,1006],
 "date":pd.date_range('20130102', periods=6),
  "city":['Beijing ', 'SH', ' guangzhou ', 'Shenzhen', 'shanghai', 'BEIJING '],
 "age":[23,44,54,32,34,32],
 "category":['100-A','100-B','110-A','110-C','210-A','130-F'],
  "price":[1200,np.nan,2133,5433,np.nan,4432]},
  columns =['id','date','city','category','age','price'])
print(df)

-> id date city category age price
0 1001 2013-01-02 Beijing 100-A 23 1200.0
1 1002 2013-01-03 SH 100-B 44 NaN
2 1003 2013-01-04 guangzhou 110-A 54 2133.0
3 1004 2013-01-05 Shenzhen 110-C 32 5433.0
4 1005 2013-01-06 shanghai 210-A 34 NaN
5 1006 2013-01-07 BEIJING 130-F 32 4432.0

数据表信息查看

# 查看df的形状
print(df.shape)
# 数据表的基本信息
print(df.info())
# 查看数据的类型
print(df.dtypes)
#查看id数据的类型
print(df['id'].dtype)
# 类似numpy的isnan
print(df.isnull())
# 对特定数据项进行操作
print(df['id'].isnull())
# 查看默认前5行
print(df.head())
# 默认查看后5行
print(df.tail())
# 对数据进行简单的计数及 平均值,最小,最大等
print(df2.describe())

pandas处理丢失数据

在pandas也存在空值为NaN
与numpy不一样在于,pandas处理数据的时候,当某行(列)存在NaN时并不会使结果都为NaN,而是忽略NaN处理余下的数据

  1. print(df.dropna(axis=0,how='any')) [how ='all']全部为nan删除,any是任一元素为nan就删除一整行,all则是当某一行全部等于nan才删除 [inplace=“True”] True: 在原数据上修改,返回None,False:返回为修改过的数据,原数据不变
  2. print(df.fillna(value=0))把nan值赋值为0 df["name"].fillna(df.mean()) 筛选name行操作赋值为平均值
  3. print(df.isna()) 输出一个每个元素是否为nan 的矩阵
  4. print(np.any(df.fillna) ==True) 筛选是否存在一个nan

数据表清洗

1、用数字0填充空值:

df.fillna(value=0)

2、使用列prince的均值对NA进行填充:

df["price"].fillna(df["price".mean())

3、清除name字段的字符空格:

df["name"].str.strip()

4、大小写转换:

df["name"].str.lower
df["name"].str.upper

5、更改数据格式:

df["name"].astype("int")

6、更改列名称:

df.rename(columns={'category': 'category-size'}) 

合并

1. concat函数
  • 上下合并
df1= pd.DataFrame(np.ones((3,4))*0,columns=['a','b','c','d'])
df2= pd.DataFrame(np.ones((3,4))*1,columns=['a','b','c','d'])
df3= pd.DataFrame(np.ones((3,4))*2,columns=['a','b','c','d'])
# ignore_index 参数置为True可以让编号重新编号不会混乱
res= pd.concat([df1,df2,df3],axis=0,ignore_index=True)
  • join 标签
    [inner]只输出标签相同的数据,取交集
    [outer]所有标签都会合并,但是一方在该column标签下没有元素的会被赋值为NaN
df1= pd.DataFrame(np.ones((3,4))*0,columns=['a','b','c','d'],index=[1,2,3])
df2= pd.DataFrame(np.ones((3,4))*1,columns=['b','c','d','e'],index=[2,3,4])
res = pd.concat([df1, df2], join="outer", ignore_index=True)
print(res)

-> a b c d e
0 0.0 0.0 0.0 0.0 NaN
1 0.0 0.0 0.0 0.0 NaN
2 0.0 0.0 0.0 0.0 NaN
3 NaN 1.0 1.0 1.0 1.0
4 NaN 1.0 1.0 1.0 1.0
5 NaN 1.0 1.0 1.0 1.0

df1= pd.DataFrame(np.ones((3,4))*0,columns=['a','b','c','d'],index=[1,2,3])
df2= pd.DataFrame(np.ones((3,4))*1,columns=['b','c','d','e'],index=[2,3,4])
res = pd.concat([df1, df2], join="inner", ignore_index=True)
print(res)

-> b c d
0 0.0 0.0 0.0
1 0.0 0.0 0.0
2 0.0 0.0 0.0
3 1.0 1.0 1.0
4 1.0 1.0 1.0
5 1.0 1.0 1.0

我们很容易看出差别,对于相同的两组数据采取的合并方式不同,结果是天壤之别

  • 两组数据index不一致,重新选择index
# 左右合并,使用df1的index
res = pd.concat([df1,df2.reindex(df1.index)],axis=1)

思考下和 res = pd.concat([df1,df2,axis=1) 的区别

2. append方法
res = df1.append([df2],ignore_index=True)

可以传入多个矩阵,也可以创建一个Series 进行append操作

3. merge方法

也有[left,inner,outer,right] 控制合并的方式

  • 基于单个key进行合并
left = pd.DataFrame({'Key':['K0','K1','K2','K3'],
                     'A':['A0','A1','A2','A3'],
                     'B':['B0','B1','B2','B3']})
right = pd.DataFrame({'Key':['K0','K1','K2','K3'],
                     'C':['C0','C1','C2','C3'],
                     'D':['D0','D1','D2','D3']})
# 根据两个数据的Key来进行合并                   
res=pd.merge(left,right,on='Key')
  • 基于两个key合并
    两对key都相等的时候才进行输出,列的标签会区分标记
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'],
                     'A':['A0','A1','A2','A3'],
                     'B':['B0','B1','B2','B3']})
res = pd.merge(left,right,on=['Key1','Key2'])
print(res)

->Key1 Key2 A_x B_x A_y B_y
0 K0 K0 A0 B0 A0 B0
1 K1 K0 A2 B2 A1 B1
2 K1 K0 A2 B2 A2 B2

  • 手动设置区分数据的suffix
boys=pd.DataFrame({'k':['K0','K1','K2'],'age':[1,2,3]})
girls=pd.DataFrame({'k':['K0','K1','K2'],'age':[4,5,6]})
res = pd.merge(boys,girls,on='k',suffixes=['_boys','_girls'],how='inner)

->k age_boys age_girls
0 K0 1 4
1 K1 2 5
2 K2 3 6

  • 输出一列来表明每行数据的来源
    res = pd.merge(left,right,on=['Key1','Key2'],indicator=True)
    indicator参数设置为字符串就给该标签设置名字
    ->Key1 Key2 A_x B_x A_y B_y _merge
    0 K0 K0 A0 B0 A0 B0 both
    1 K1 K0 A2 B2 A1 B1 both
    2 K1 K0 A2 B2 A2 B2 both
  • 设置索引列
pd.setindex('id')
  • 按照特定列的值排序:
pd.sort_values(by='')
  • 按照索引列排序:
df.sort_index()

数据提取

  • loc:通过行、列的名称或标签来索引
  • iloc方法是通过索引行、列的索引位置[index, columns]来寻找值
  • 重设索引 df.reset_index()
  • 使用ix按索引标签和位置混合提取数据
pd.ix['name',:4]
  • 与或非结合布尔索引快速检索数据

matplotlib

matplotlib 主要就是将处理好的数据用图的形式展现出来实现可视化
有相当多的图形 ‘bar’ ‘hist’ ‘box’ ‘bde’ ‘area’ ‘scatter’ ‘hexbin’ ‘pie’
以下只对plot bar hist scatter做简要描述

首先仍就是必不可少的一步

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd

直线图plt

  • 调整画布大小
plt.figure(figsize=(20,8),dpi=80)
  • 设置疏密和x(y)坐标轴
# _x和_xtick_label 分别是坐标轴上对应的位置以及该位置上想要显示的内容
_x = range(11,31)
_xtick_labels = ["age{}".format(i) for i in ramge(11,31)
# 想要调整坐标轴疏密程度就是对_x,_xtick_label 进行缩放,调疏切片操作就行记得先把_x转为list,调密就反向操作
# rotation控制旋转度数
plt.xticks(_x,_xtick_label,rotation=90)
  • 设置标签标题信息
plt.xlabel("")
plt.ylabel("")
plt.title("")
  • 设置网格
# alpha设置透明度
plt.grid(alpha=0.5) 
  • 设置字体
# 定义my_font 存放想用的字体
from matplotlib import font_manager
my_font = font_manager.fontproperities(fname="path")
# 后续若是需要该字体,传入参数fontproperities=my_font 即可
plt.title("表格",fontproperities=my_font )
  • 设置图例(可以在plot传入数据的时候传入参数label=" "设置图例的名字)
#loc 控制图例的位置 upper left best(自动选择数据少的地方)
plt.lengend() [loc=""]
  • 传入数据设置图样式
plt.plot(x,y,...)[color,alpha,linestyle,linewidth,label]

上述操作在其他的图内部也是通用的只有少数地方有区别

条形图

  • bar(竖直方向):plt.bar(x,y,width) width 设置柱子宽度
  • barh(水平方向)plt.barh(x,y,height) height也是设置宽度,

直方图

  • plt.hist(list,num_bins(组数),density=true(转换频率图))
  • num_bins=(max()-min())//d # d为设置的组距
  • 条形图各柱子之间没有缝隙就是直方图
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值