2.pandas入门介绍

2.pandas入门介绍

前面知道NumPy是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,也针对数组运算提供大量的数学函数库。numpy是基于c语言开发,所以这使得numpy的运行速度很快,高效率运行就是numpy的一大优势。但numpy的特长并不是在于数据处理,而是在于能非常方便地实现科学计算,所以对数据进行处理时用的numpy情况并不是很多,因为需要处理的数据一般都是带有列标签和index索引的,而numpy并不支持这些,这时就需要pandas了,Pandas的主要工作就是做数据分析,pandas继承了numpy  我们要使用的是pandas而不是numpy。Pandas是基于Numpy构建的库,在数据处理方面可以把它理解为numpy加强版 。

数据分析中:样本是(行)  特征是(列)。

pandas的优缺点。优点:pandas相比于Excel,matlab,tableau等更加的灵活,处理大数据的问题上更加有优势,读取excel文件的时候,pandas更加快,处理速度快。缺点:操控方面相对比较僵硬,pandas当中的函数要清晰使用,statsmodels统计库(bug百出,官网提供的文档大部分不友好),scipy高数(stats,使用方法太繁琐)。

pandas的处理速度。为什么不用mysql?  慢:文件操作慢;pandas:快在于将数据加载到内存了。

数据分析使用的库:numpy作为依赖库;pandas数据分析库;matplotlib直观的数据可视化库;seaborn辅助库(库中含有调色板),图形更加丰富;pyecharts:简易的数据可视化库,电商中比较常用;,,,。

pandas中有两大数据类型。Series 级数(索引是有序的,一维的);DataFrame 结构化数据(二维的表)。

 

1. Series级数

Series是一种类似一维数组的数据结构,由一组数据和与之相关的index组成,即由values:一组数据(ndarray类型) 和 key:相关的数据索引标签两个部分组成。这个结构一看似乎与dict字典差不多,我们知道字典是一种无序的数据结构,而pandas中的Series的数据结构不一样,它相当于定长有序的字典,并且它的index和value之间是独立的,两者的索引还是有区别的,Series的index变的,而dict字典的key值是不可变的。Series是将 序列 和 hash 融合在一起了。序列:索引有序,索引是枚举类型;hash:键是无序的,键是关联类型的。pandas中的两大数据类型都可以使用对象和属性的方式来获取值和赋值,在pandas中,string也是object。

 

Series的创建 :

可由列表或numpy数组创建:默认索引为0到N-1的整数型索引。(list,tuple,dict,ndarry)强制转换为Series类型 。

 1 # 由列表创建,默认索引为0到4的整数型索引
 2 s0 = Series([1,2,3,4,5])
 3 s0[1]   # 2
4 # 由numpy数组创建 5 s1 = Series(np.array(list("ABCD"))) 6 7 # 由字典(hash)创建,字典的key会被Series当作是index 8 s2 = Series({"A":1,"B":2,"C":3}) 9 10 # 通过设置index参数指定索引 --> {a:甲,b:乙,c:} 11 s3 = Series(data=list("甲乙丙丁"),index=list("abcd"))

 

Series的索引和切片:

1). 常规索引:可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的仍然是一个Series类型)。

2). 显式索引:

- 使用index中的关联类型作为索引值;- 使用.loc[](推荐)。可以理解为pandas是ndarray的升级版,但是Series也是dict的升级版

3). 隐式索引:
- 使用整数作为索引值;- 使用.iloc[](推荐)

1 # 常规索引
2 s3[0]           # ‘甲’
3 s3["a"]        # ‘甲’​
4 
5 # 显式索引
6 s3.loc["a"]   # ‘甲’
7 8 # 隐式索引
9 s3.iloc[0]    # ‘甲’

4). 切片:

 1 # 常规切片,左闭右开
 2 s3[0:-1]
 3     # a    甲
 4     # b    乙
 5     # c    丙
 6     # Name: username, dtype: object
 7     
 8 # 显式切片,全闭区间
 9 s3.loc["a":"d"]
10     # a    甲
11     # b    乙
12     # c    丙
13     # d    丁
14     # Name: username, dtype: object
15     
16 # 隐式切片,左闭右开
17 s3.iloc[0:-1]
18     # a    甲
19     # b    乙
20     # c    丙
21     # Name: username, dtype: object

 

Series的属性:

可以把Series看成一个定长的有序字典。

 1 """
 2 ndim:维度
 3 shape:形状
 4 size:获取元素的长度
 5 dtype:数据类型
 6 index:获取所有的索引
 7 values:获取所有的值
 8 name:获取名称   
 9 head():快速查看Series对象的样式,获取前5条数据
10 tail():快速查看Series对象的样式,获取最后5条数据
11 """

代码演示示例:

 1 s3.shape      # (4,)
 2 s3.size       # 4
 3 s3.ndim       # 1
 4 s3.name       # "username"
 5 s3.dtype      # dtype("O") 表示字符串类型
 6 s3.index      # Index(["a", "b", "c", "d"], dtype="object")
 7 s3.keys()     # Index(["a", "b", "c", "d"], dtype="object")
 8 s3.valuse     # array(["甲", "乙", "丙", "丁"], dtype=object)
 9 s3.head(n=5)
10 s3.tail(n=5)

 

检测缺失数据:

当索引没有对应的值时,可能出现缺失数据显示NaN(not a number)的情况。注意:np.NaN  !==  np.NaN;可以使用pd.isnull(),pd.notnull(),或自带isnull(),notnull()函数检测缺失数据。

 1 # 造一含有NaN值的Series数据
 2 s5 = Series(data=range(4),index=list("abcd")) # NaN是float
 3 s5["c"] = np.nan        # 将索引c 的值变为nan  
 4 s5
 5   #  a    0.0
 6   #  b    1.0
 7   #  c    NaN
 8   #  d    3.0
 9   #  dtype: float64
10 
11 # 检测缺失数据
12 cond = pd.isnull(s5)        # 相当于s5.isnull()
13 cond 
14   # a     False
15   # b     False
16   # c     True
17   # d     False
18   # dtype: bool
19 # 检查到NaN值之后,将nan值的数据变成 0
20 s5[cond]= 0
21    # a    0.0
22    # b    1.0
23    # c    0.0
24    # d    3.0
25    # dtype: float64
26 
27 s5["c"] = np.nan    # 将索引c 的值变为nan  
28 
29 # 检测缺失数据 
30 cond_fa = s5.notnull()     # 相当于pd.notnull(s5)
31 cond_fa
32    # a     True
33    # b     True
34    # c     False
35    # d     True
36    # dtype: bool
37 # 检查到NaN值之后,将nan值筛选掉
38 s5[cond_fa]
39    # a    0.0
40    # b    1.0
41    # d    3.0
42    # dtype: float64 

 

Series之间的运算:

NaN+任何值都是NaN。在运算中自动对齐不同索引的数据,如果索引不对应,则补NaN。

 1 s5 * 3 
 2    # a    0.0
 3    # b    3.0
 4    # c    0.0
 5    # d    9.0
 6    # dtype: float64
 7 
 8 s6 = Series(range(5),list("bcdef"))
 9 
10 s5.add(s6)   # 相当于 s5+s6
11    # a    NaN
12    # b    1.0
13    # c    1.0
14    # d    5.0
15    # e    NaN
16    # f     NaN
17    # dtype: float64

 

2. DataFrame

DataFrame是一个【表格型】的数据结构,可以看做是【由Series组成的字典】(共用同一个索引)。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。行索引:index;列索引:columns;值:values(numpy的二维数组)。我们的 训练集(一些二维的数据)都是二维的,那么Series满足不了这个条件,xy轴,轴上的一点(0,0)。DataFrame每一列可以是不同类型的值集合,所以DataFrame你也可以把它视为不同数据类型同一index的Series集合。

DataFrame的创建:

最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列的值。此外,DataFrame会自动加上每一行的索引(和Series一样)。同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。

 1 df1 = DataFrame(data={"数学":[10,20,30,40,50],
 2                       "语文":[1,2,3,4,5],
 3                       "英语":[10,11,12,13,14]},
 4                 index=["Tom","Jhon","Jack","Marry","Jurray"],
 5                 columns=["英语","数学","语文"])
 6 
# 英语 数学 语文 7 # Tom 10 10 1 8 # Jhon 11 20 2 9 # Jack 12 30 3 10 # Marry 13 40 4 11 # Jurray 14 50 5

DataFrame属性:

values、columns、index、shape、ndim、dtypes。

 1 # 行索引
 2 df1.index     # Index(["雷军", "不知妻美", "不知爹富", "马云", "罗太军"], dtype="object")
 3 
 4 # 列索引
 5 df1.columns   # Index(["英语", "数学", "语文"], dtype="object")
 6 
 7 df1.dtypes    
 8    # 英语    int64
 9    # 数学    int64
10    # 语文    int64
11    # dtype: object
12 
13 df1.size    # 15
14
df1.ndim # 2

DataFrame的索引:

1). 对列进行索引(获取某一列): [ ] 默认只能取列索引- 通过类似字典的方式;- 通过属性的方式。可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且name属性也已经设置好了,就是相应的列名。

df1["语文"] ---> 获取‘语文’列

2). 对行进行索引(获取某一行):- 使用.loc[]加index来进行行索引;- 使用.iloc[]加整数来进行行索引。同样返回一个Series,index为原来的columns。

df1.loc["Tom"] ---> 获取‘Tom’行
df1.iloc[0] ---> 获取第0行,等于‘Tom’行

3). 对元素进行索引(获取某一个元数/值):- 使用列索引;- 使用行索引(iloc[3,1]相当于两个参数;iloc[[3,3]] 里面的[3,3]看做一个参数);- 使用values属性(二维numpy数组)

df1.loc["Tom","英语"] ---> 获取‘Tom’行,‘英语’列的这个元素的值
df1.iloc[0,0]  ---> 获取第0行,第0列的这个元素的值,和df1.loc["Tom","英语"]结果一样
 1 # 对列进行索引, [ ] 默认只能取列索引
 2 df1["语文"]             # 获取为一个Series  ,相当于【 df1.语文 】
 3 # Tom       1
 4 # Jhon      2
 5 # Jack      3
 6 # Marry     4
 7 # Jurray    5
 8 # Name: 语文, dtype: int64
 9 
10 df1.语文             # 不建议这样获取列
11 df1["Tom"]             # 会报错
12 
13 
14 # 对行进行索引
15 df1.loc["Tom"]         # 显式loc
16 # 英语    10
17 # 数学    10
18 # 语文     1
19 # Name: Tom, dtype: int64
20 
21 df1.iloc[0]            # 隐式iloc
22 # 英语    10 
23 # 数学    10
24 # 语文     1
25 # Name: Tom, dtype: int64
26 
27 # 对元素进行索引
28 df1.loc["Tom","英语"]   # 10
29 
30 df1.iloc[0,0]         # 10

4). 切片操作:

获取某些行和某些列的值,可以是多个值

 1 # 使用行索引显式loc切片,全闭区间
 2 df1.loc["Tom":"Jack"]                # 获取Tom到Jack行的数据,针对行
 3 #       英语  数学  语文
 4 # Tom   10  10   1
 5 # Jhon  11  20   2
 6 # Jack  12  30   3
 7 
 8 df1.loc["Tom":"Jack","英语":"数学"]   # 获取Tom到Jack行,英语到数学列的数据
 9 #       英语  数学
10 # Tom   10  10
11 # Jhon  11  20
12 # Jack  12  30
13 
14 
15 # 使用行索引隐式iloc切片,左开右闭
16 df1.iloc[1:2]       # 获取第1行到第2行的数据(不包含第2行),针对行
17 #       英语  数学  语文
18 # Jhon  11  20   2
19 
20 df1.iloc[0:2 , 0:2]  # 获取第0行到第2行,第0列到第2列的数据(不包含第2行和第2列)
21 #       英语  数学
22 # Tom   10  10
23 # Jhon  11  20

 

DataFrame的运算:

Dataframe的运算同Series一样。

下图是Python 操作符与pandas操作函数的对应表:

 

 

Series与DataFrame之间的运算:

使用pandas操作函数:axis=0:以列为单位操作(参数必须是列),对所有列都有效;axis=1:以行为单位操作(参数必须是行),对所有行都有效。

列方向:df1.add(s)    #默认列相加;行方向:  (df1.T + s).T。

处理丢失的数据:
df1.loc["Tom","英语"] = np.NaN
df1.loc["Jack","数学"] = np.NaN

pandas 中对于空的操作:

isnull():是空值,notnull():不是空值,dropna() :过滤空值,fillna() :填充空值。

数据分析:删除行比较合适,行代表的是一条数据,列会影响到所有的数据。机器学习:如果是行当中的空值比较多那就删行,列中空值比较多就删列。

 1 # 判断是否为空值
 2 df1.loc[:,"英语"].isnull()
 3 # Tom       True
 4 # Jhon      True
 5 # Jack      True
 6 # Marry     True
 7 # Jurray    True
 8 # Name: 英语, dtype: bool
 9 
10 # 当该行中所有的元素都为空则删除
11 df1.dropna(how="all")
12 13 # 当该行中所有的元素都为空则删除
14 df1.dropna(how="any",axis=1,inplace=True)
15 
16 # 填充空值
17 df1.fillna(value=None, method=None, axis=None, inplace=False, limit=None, #downcast=None, **kwargs)

 

聚合操作:
所谓的聚合操作:平均数,标准方差,最大值,最小值……

1 df1.sum()        # 默认是对列进行操作
2 df1.mean()       # 默认是对列进行操作  
3 df1.max()        # 求列的最大值                                                          
4 df1.var()        # 样本方差,表示的数据的波动性 
5 df1.std()        # 样本标准差  

 

pandas的拼接操作:

pandas的拼接分为两种:级联:pd.concat, pd.append;合并:pd.merge, pd.join。

回顾numpy的级联:

1 np.concatenate([np.random.randint(0,100,(5,4)),np.random.rand(5,4),np.random.randn(5,4)],axis=1)

1). 简单级联:

行合并:pd.concat([df1,df2],axis=0)。和np.concatenate一样,优先增加行数(默认axis=0)。注意index在级联时可以重复。

 

列合并:pd.concat([df1,df2],axis=1)。不建议用,concat它不是联表查询,只擅长当union(垂直的 axis=0),水平合并一定不要用。

 

 1 # 垂直的内连接,join="inner" ,会删除含有NaN的行或列
 2 pd.concat([df1,df2],axis=0,join="inner")   # index在级联时可以重复
 3 
 4 # 水平内连接
 5 pd.concat([df1,df2],axis=1,join="inner")
 6 
 7 # 外连接,不匹配的项补NaN
 8 pd.concat([df1,df2],axis=0,join="outer")
 9 
10 # ignore_index=True忽略重复索引
11 pd.concat([df1,df2],axis=0,join="outer",ignore_index=True)
12 
13 # 使用多层索引 keys ,解决重复问题
14 pd.concat([df1,df2],axis=0,join="outer",keys=["df1","df2"])
15          #   a   b   c
16    # df1 0  a0  b0  c0
17    #     1  a1  b1  c1
18    #     2  a2  b2  c2
19    # df2 2  a2  b2  c2
20    #     3  a3  b3  c3
21    #     4  a4  b4  c4

 

 2). 不匹配级联:
不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致;有3种连接方式:
外连接:补NaN(默认模式)
内连接:只连接匹配的项
-连接指定轴 join_axes 显示某一格dataframe 中的列

3).使用append()函数添加:

由于在后面级联的使用非常普遍,因此有一个函数append专门用于在后面添加,append 和 concat 相似,只能直接做垂直:df1.append(df2)

 

 

 4). 使用pd.merge()合并:

merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并,使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。注意每一列元素的顺序不要求一致

 

pd.merge(DataFrame1,DataFrame2, how=‘inner’, on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=(’_x’, ‘_y’))

pd.merge(DataFrame1,DataFrame2) == DataFrame1.merge(DataFrame2)

参数:

how:默认为inner,可设为inner/outer/left/right
on:根据某个字段进行连接,必须存在于两个DateFrame中(若未同时存在,则需要分别使用left_on和right_on来设置)
left_on:左连接,以DataFrame1中用作连接键的列
right_on:右连接,以DataFrame2中用作连接键的列
left_index:将DataFrame1行索引用作连接键
right_index:将DataFrame2行索引用作连接键
sort:根据连接键对合并后的数据进行排列,默认为True
suffixes:对两个数据集中出现的重复列,新数据集中加上后缀_x,_y进行区别

代码演示区别:

 1 pd.DataFrame({"lkey":["foo","bar","baz","foo"], "value":[1,2,3,4]})
 2 #   lkey  value
 3 # 0  foo      1
 4 # 1  bar      2
 5 # 2  baz      3
 6 # 3  foo      4
 7 
 8 pd.DataFrame({"rkey":["foo","bar","qux","bar"], "value":[5,6,7,8]})
 9 #   rkey  value
10 # 0  foo      5
11 # 1  bar      6
12 # 2  qux      7
13 # 3  bar      8
14 
15 # inner链接
16 dataDf1.merge(dataDf2, left_on="lkey",right_on="rkey")
17 #   lkey  value_x rkey  value_y
18 # 0  foo        1  foo        5
19 # 1  foo        4  foo        5
20 # 2  bar        2  bar        6
21 # 3  bar        2  bar        8
22 
23 # Outer链接
24 dataDf1.merge(dataDf2, left_on="lkey", right_on="rkey", how="outer")
25 #   lkey  value_x rkey  value_y
26 # 0  foo      1.0  foo      5.0
27 # 1  foo      4.0  foo      5.0
28 # 2  bar      2.0  bar      6.0
29 # 3  bar      2.0  bar      8.0
30 # 4  baz      3.0  NaN      NaN
31 # 5  NaN      NaN  qux      7.0
32 
33 # left链接
34 dataDf1.merge(dataDf2, left_on="lkey", right_on="rkey",how="left")
35 #   lkey  value_x rkey  value_y
36 # 0  foo        1  foo      5.0
37 # 1  bar        2  bar      6.0
38 # 2  bar        2  bar      8.0
39 # 3  baz        3  NaN      NaN
40 # 4  foo        4  foo      5.0
41 
41 # right链接 42 dataDf1.merge(dataDf2, left_on="lkey", right_on="rkey",how="right") 43 # lkey value_x rkey value_y 44 # 0 foo 1.0 foo 5 45 # 1 foo 4.0 foo 5 46 # 2 bar 2.0 bar 6 47 # 3 bar 2.0 bar 8 48 # 4 NaN NaN qux 7

【注意】1).当有多个key相同时使用,使用on=显式指定哪一列为key;当左右两边的key都不相等时,使用left_on和right_on指定左右两边的列作为key。

2).内合并:只保留两者都有的key(默认模式);外合并 how="outer":补NaN;左合并、右合并:how="left",how="right"。

 

 

 

列冲突的解决:

 

 

当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名,可以使用suffixes=自己指定后缀。

1 dataDf1.merge(dataDf2, left_on="lkey", right_on="rkey", how="right", suffixes=("_df1", "_df2"))
2 #   lkey     value_df1  rkey  value_df2
3 # 0  foo        1.0      foo      5
4 # 1  foo        4.0      foo      5
5 # 2  bar        2.0      bar      6
6 # 3  bar        2.0      bar      8
7 # 4  NaN        NaN      qux      7

 

 

pandas删除操作:

Dataframe.drop(labels=0,axis=0,inplace=True):labels=0表示 第0行 ,inplace=True表示对原数据 产生影响。

1 df1.drop(labels=0,axis=0,inplace=True)    # 删除第0行
2 df1.drop(0)                               # 删除第0行
3 df1.drop([0,1])                           # 删除第0,1行

行重新设定:

Dataframe.set_index("id",inplace=True)

 1 dataDf1
 2 #   lkey  value
 3 # 0  foo      1
 4 # 1  bar      2
 5 # 2  baz      3
 6 # 3  foo      4
 7 
 8 dataDf1.set_index(["value"],inplace=True)  # 将"value"设置为index
 9 dataDf1
10 #        lkey
11 # value
12 #   1     foo
13 #   2     bar
14 #   3     baz
15 #   4     foo
16 
17 dataDf1.reset_index(inplace=True)          # 将index返回回dataframe中
18 dataDf1
19 #     value   lkey
20 # 0      1     foo
21 # 1      2     bar
22 # 2      3     baz
23 # 3      4     foo

统计出现的次数:

1 data[ column_1 ].value_counts()

数据的简单保存与读取:

1 pd.read_csv("test.csv")  # 读取csv文件
2 
3 data.to_csv("test.csv")   # 保存csv文件

补充:基本的统计数据。data. describe() ;data.info()。