乐趣区

关于python:利用-Python-进行数据分析-3-pandas-入门

上一篇咱们理解了 NumPy 的基本功能,本篇引入一个新的 python 数据处理库——pandas。

NumPy 更适宜解决对立的数值数组数据。Pandas 是基于 NumPy 数组构建的,专门解决表格和混淆数据。接下来,让咱们来理解一下 pandas 的根本应用吧。

首先让咱们导入 pandas 库:

import pandas as pd
import numpy as np  # 后续也会应用到 numpy,在此先导入进来 

3.1 pandas 的数据结构

pandas 有两个根本的数据结构:Series 和 DataFrame。

3.1.1 Series

咱们能够把 Series 了解为带有索引的一维 np 数组。让咱们创立进去比照一下:

 in: obj = pd.Series([4, 7, -5, 3])  # 能够将一个 list 转换为 Series
     obj
out: 0    4
     1    7
     2   -5
     3    3
     dtype: int64

 in: np_obj = np.array([4, 7, -5, 3])
     np_obj
out: array([4,  7, -5,  3])

能够看到,用 pd.Series() 创立的 Series 比 np.array() 创立的 ndarray 多了索引值——0, 1, 2, 3。

Series 的两个属性也能够在此印证这个事实:

 in: obj.values  # Series 的值:的确是个 np 数组
out: array([4,  7, -5,  3], dtype=int64)  

 in: obj.index  # Series 的索引(index)out: RangeIndex(start=0, stop=4, step=1)  

如果不想要 pandas 主动生成的索引,也能够指定:

 in: obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
     obj2
out: d    4
     b    7
     a   -5
     c    3
     dtype: int64

如何从 Series 当选取出一个值或一组值呢?

 in: obj2['a']
out: -5

 in: obj2[['a', 'b']]  # 取出一组值时,留神方括号的应用
out: a   -5
     b    7
     dtype: int64  # 取出一组值时,取出的也是一个 Series 

Series 如何运算呢?它能够像 NumPy 那样运算。

obj2[obj2 > 2]  # 用布尔值索引选取
obj2 * 2  # 元素级乘法运算
np.exp(obj2)

Series 有索引也有值,就像字典的“键 - 值”一样。Series 的一些用法也像字典一样:

  in: "a" in obj2  # 像是在查看某个值是否属于字典的键
 out: True

方才在创立 Series 时,咱们是将一个 list 转换为 Series。其实,也能够将一个 dict 转换为 Series(此时,字典的键就是 Series 的索引):

 in: sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
     obj3 = pd.Series(sdata)
     obj3
out: Ohio      35000
     Texas     71000
     Oregon    16000
     Utah       5000
     dtype: int64

在曾经有索引的状况下,如果再指定索引,会产生什么呢?

 in: states = ['California', 'Ohio', 'Oregon', 'Texas']
     obj4 = pd.Series(sdata, index=states)
     obj4 
out: California        NaN  # 原索引被新索引代替了,新索引中的 California 找不到对应的原索引,因而赋空值 NaN
     Ohio          35000.0
     Oregon        16000.0
     Texas         71000.0
     dtype: float64  # 新索引中没有 Utah 了,此处能够看到也没有呈现 Utah 的数据 

咱们在上一个代码块中看到了缺失值的存在。咱们在解决数据时经常碰到有缺失数据的状况。那么如何检测数据中是否存在缺失数据呢?

 in: pd.isnull(obj4)  # 和上面成果一样
     obj4.isnull()  # 和下面成果一样
out: California     True
     Ohio          False
     Oregon        False
     Texas         False
     dtype: bool
        
 in: pd.notnull(obj4)  # 也能够检测非空值
out: California    False
     Ohio           True
     Oregon         True
     Texas          True
     dtype: bool

最初,再介绍一个 Series 的重要性能:依据运算的索引标签主动对齐数据。

 in: obj3 + obj4  # 两个 Series 的索引存在不同,而加法运算主动将能对应上的索引值相加
out: California         NaN  # 而对应不上的值间接赋空值
     Ohio           70000.0  
     Oregon         32000.0
     Texas         142000.0
     Utah               NaN  # 对应不上,赋空值,不管其是否在某一个 Series 中有值
     dtype: float64

3.1.2 DataFrame

DataFrame 是一个表格型数据结构,既有行索引也有列索引。一列的值类型是雷同的,但不同列能够有不同的值类型。

首先让咱们创立一个 DataFrame。

 in: data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
             'year': [2000, 2001, 2002, 2001, 2002, 2003],
             'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}  # 建设一个值为等长 list 的字典
     frame = pd.DataFrame(data)  # 将上述字典转为 DataFrame
     frame
out:     state  year  pop
     0    Ohio  2000  1.5
     1    Ohio  2001  1.7
     2    Ohio  2002  3.6
     3  Nevada  2001  2.4
     4  Nevada  2002  2.9
     5  Nevada  2003  3.2  # 能够看到这个 DataFrame 应用了字典的键作为列索引,行索引是主动创立的 

咱们时常会解决很大数据量的 DataFrame,当想查看这个表格构造时,并不想将整个表格都输入。咱们能够用 head() 查看一个 DataFrame 的前几行:

 in: frame.head()
out:     state  year  pop
     0    Ohio  2000  1.5
     1    Ohio  2001  1.7
     2    Ohio  2002  3.6
     3  Nevada  2001  2.4
     4  Nevada  2002  2.9  # 默认输入前 5 行

 in: frame.head(3)  # 能够设置输入的行数
out:     state  year  pop
     0    Ohio  2000  1.5
     1    Ohio  2001  1.7
     2    Ohio  2002  3.6

那如何取出一列呢?

 in: frame['state']  # 像取字典的值那样就能够,咱们取出了一个 Series
     frame.state  # 这样也能够,成果和上一行是一样的,因为 DataFrame 有一个 name 属性
out: 0      Ohio
     1      Ohio
     2      Ohio
     3    Nevada
     4    Nevada
     5    Nevada
     Name: state, dtype: object

在创立 DataFrame 时,咱们还能够指定列(字段)的排列程序,让表格按咱们想要的顺序排列:

 in: pd.DataFrame(data, columns=['year', 'state', 'pop'])
out:    year   state  pop
     0  2000    Ohio  1.5
     1  2001    Ohio  1.7
     2  2002    Ohio  3.6
     3  2001  Nevada  2.4
     4  2002  Nevada  2.9
     5  2003  Nevada  3.2

但如果咱们指定了匹配不上原数据的字段名,那么会产生缺失值:

 in: frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'],
                      index=['one', 'two', 'three', 'four', 'five', 'six'])
     frame2
out:        year   state  pop debt  # 能够看到 debt 列都是缺失值
     one    2000    Ohio  1.5  NaN
     two    2001    Ohio  1.7  NaN
     three  2002    Ohio  3.6  NaN
     four   2001  Nevada  2.4  NaN
     five   2002  Nevada  2.9  NaN
     six    2003  Nevada  3.2  NaN

缺失值的这列数据该如何解决呢?

 in: frame2['debt'] = 12  # 能够间接赋一个整数,这会被播送到整列
out:        year   state  pop  debt
     one    2000    Ohio  1.5    12
     two    2001    Ohio  1.7    12
     three  2002    Ohio  3.6    12
     four   2001  Nevada  2.4    12
     five   2002  Nevada  2.9    12
     six    2003  Nevada  3.2    12
        
 in: frame2['debt'] = np.arange(6.)  # 也能够退出一个与表格长度等长的序列
out:        year   state  pop  debt
     one    2000    Ohio  1.5   0.0
     two    2001    Ohio  1.7   1.0
     three  2002    Ohio  3.6   2.0
     four   2001  Nevada  2.4   3.0
     five   2002  Nevada  2.9   4.0
     six    2003  Nevada  3.2   5.0
 
 in: val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
     frame2['debt'] = val  # 如果将一个带有能匹配上的索引的 Series 赋值给缺失值列的话
     frame2
out:        year   state  pop  debt
     one    2000    Ohio  1.5   NaN
     two    2001    Ohio  1.7  -1.2
     three  2002    Ohio  3.6   NaN
     four   2001  Nevada  2.4  -1.5
     five   2002  Nevada  2.9  -1.7
     six    2003  Nevada  3.2   NaN  # 能够看到匹配上索引的赋值了,没匹配上的仍是缺失值 

如果咱们不想要 debt 这列了,如何删除呢?

 in: del frame2['debt']
     frame2.columns  # 来查看一下还有哪几列
out: Index(['year', 'state', 'pop'], dtype='object')

3.2 pandas 基本功能

3.2.1 插入新数据:应用“从新索引”

有时咱们心愿往 Series 或 DataFrame 中插入新数据,这能够用从新索引的形式实现。对于 Series 而言:

 in: obj = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
     obj
out: 0      blue
     2    purple
     4    yellow
     dtype: object
    
 in: obj.reindex(range(6))  # 咱们通过扭转并笼罩原来的索引,达到插入新行的目标
out: 0      blue
     1       NaN
     2    purple
     3       NaN
     4    yellow
     5       NaN
     dtype: object
        
 in: obj.reindex(range(6),method='ffill')  # 指定 method 参数,还能够实现诸如插值解决的操作
out: 0      blue
     1      blue  # 不再是空值了,而是依照前一个值来填充
     2    purple
     3    purple
     4    yellow
     5    yellow
     dtype: object

DataFrame 有两个索引,因而咱们能够通过从新索引向表格中插入行和列。

 in: frame = pd.DataFrame(np.arange(9).reshape((3, 3)),
                     index=['a', 'c', 'd'],
                     columns=['Ohio', 'Texas', 'California'])
     frame
out:    Ohio  Texas  California
     a     0      1           2
     c     3      4           5
     d     6      7           8

 in: frame2 = frame.reindex(['a', 'b', 'c', 'd'])  # 默认从新索引行,用一个 list 表述新的索引序列。frame2
out:    Ohio  Texas  California  # 能够看到匹配上索引的行还是原来的数据,没匹配上的赋空值
     a   0.0    1.0         2.0
     b   NaN    NaN         NaN
     c   3.0    4.0         5.0
     d   6.0    7.0         8.0

 in: states = ['Texas', 'Utah', 'California']
     frame2.reindex(columns=states)   # 指明 columns 参数,即可从新索引列
out:    Texas  Utah  California  # 原数据中,没匹配索引的列被删除了
     a    1.0   NaN         2.0
     b    NaN   NaN         NaN
     c    4.0   NaN         5.0
     d    7.0   NaN         8.0

3.2.2 抛弃指定轴上的项

咱们能够指定索引,来抛弃指定轴上的项。

对 Series 来说,只有一个索引,能够这么做:

 in: obj = pd.Series(np.arange(5.))
     obj.drop([1, 3])
out: 0    0.0
     2    2.0
     4    4.0
     dtype: float64

对于 DataFrame 来说,索引有两个,drop() 默认对行删除。留神,drop() 的删除是一个视图,并不是间接在原数据上操作的。如果想间接删除的话,须要应用 del。

 in: data = pd.DataFrame(np.arange(16).reshape((4, 4)),
                         index=['Ohio', 'Colorado', 'Utah', 'New York'],
                         columns=['one', 'two', 'three', 'four'])
     data.drop('Ohio')
out:           one  two  three  four
     Colorado    4    5      6     7
     Utah        8    9     10    11
     New York   12   13     14    15
    
 in: data.drop(['one', 'two'], axis=1)  # 指定 axis=1 能够对列进行删除
out:           three  four
     Ohio          2     3
     Colorado      6     7
     Utah         10    11
     New York     14    15  

在实际操作中,我通常设置横轴的索引,而是用默认主动创立的序号索引(0, 1, 2, …)。

这样的话,drop() 后,index 就会有完好。

 in: data = pd.DataFrame(np.arange(16).reshape((4, 4)),
                         columns=['one', 'two', 'three', 'four'])
     data = data.drop(index=(data.loc[(data['one']>5) & (data['one']<10)]).index)
     data
out:    one  two  three  four
     0    0    1      2     3
     1    4    5      6     7
     3   12   13     14    15  # 缺失了 index = 2 的行 

这时,咱们须要从新设置 index:

 in: data = data.reset_index(drop=True)  # 指定 drop=True 能够不保留原来的 index
out:    one  two  three  four
     0    0    1      2     3
     1    4    5      6     7
     2   12   13     14    15

3.2.3 选取 Series 中的一些数据

能够像字典那样,写出键,就能够选取:

 in: obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
     obj
out: a    0.0
     b    1.0
     c    2.0
     d    3.0
     dtype: float64

 in: obj['b']
     obj[1]  # 即便咱们设置了 index 的名称,依然能够用默认的数字 index 进行索引,和上一行产生同样的成果
out: 1.0

 in: obj[0:2]  # 能够利用切片选取间断的几个值
out: a    0.0
     b    1.0
     dtype: float64
        
 in: obj[[0, 2]]  # 也能够选取不间断的几个值
out: a    0.0
     c    2.0
     dtype: float64
        
 in: obj[obj<2]  # 布尔值也能够索引,像 ndarray 一样
out: a    0.0
     b    1.0
     dtype: float64

这里用切片选取时,有个有意思的特点:用一般的 python 切片失去的数据是不蕴含末端的,但用咱们设置的 index 标签来切片,就会蕴含末端数据。

 in: obj['a':'c']
out: a    0.0
     b    1.0
     c    2.0
     dtype: float64  # 能够比照下面的 obj[0:2]

3.2.4 选取 DataFrame 中的一些数据

能够间接用相似下面的办法选取:

 in: data
out:    one  two  three  four
     0    0    1      2     3
     1    4    5      6     7
     2   12   13     14    15
    
 in: data[['one', 'three']]  # 选取指定的两列数据
out:    one  three
     0    0      2
     1    4      6
     2   12     14
 
 in: data[:2]  # 利用切片按行选取
out:    one  two  three  four
     0    0    1      2     3
     1    4    5      6     7

罕用的选取办法是用布尔值选取,以达到按条件选取的目标:

 in: data['three'] > 5  # 这样能够返回一个布尔值序列
out: 0    False
     1     True
     2     True
     Name: three, dtype: bool

 in: data[data['three'] > 5]  # 用这样的布尔值选取,咱们就能够实现按条件选取(选出 three 列中值 > 5 的行)out:    one  two  three  four
     1    4    5      6     7
     2   12   13     14    15

此外,另外一种常见的选取形式是通过轴标签(loc)或整数索引(iloc)来选取:

 in: data = pd.DataFrame(np.arange(16).reshape((4, 4)),
                         index=['Ohio', 'Colorado', 'Utah', 'New York'],
                         columns=['one', 'two', 'three', 'four'])
     data
out:           one  two  three  four
     Ohio        0    1      2     3
     Colorado    4    5      6     7
     Utah        8    9     10    11
     New York   12   13     14    15
 
 in: data.loc['Utah', ['one', 'four']]  # 指定行和列
     data.iloc[2,[0,3]]  # 和上式达到雷同成果
out: one      8
     four    11
     Name: Utah, dtype: int32
 
 in: data.loc[:'Utah', 'two']  # loc 和 iloc 也能够用切片索引
out: Ohio        1
     Colorado    5
     Utah        9
     Name: two, dtype: int32

 in: data.iloc[:, :3][data.three > 5]  # 还能够加条件,通过在最初加一个方括号蕴含的布尔值序列的形式
out:           one  two  three
     Colorado    4    5      6
     Utah        8    9     10
     New York   12   13     14

3.2.5 算数运算和数据对齐

pandas 的一个重要个性是,它反对对两个索引不同的对象做运算,并进行数据对齐——运算时,索引匹配上的值会进行运算,索引不匹配的值会间接赋值为空。

 in: s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])
     s2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'])
     s1 + s2
out: a    5.2
     c    1.1
     d    NaN
     e    0.0
     f    NaN
     g    NaN  # 即便 s2 中有值,但 s1 中不存在这个索引,运算后该索引的值仍为空
     dtype: float64

DataFrame 有两个索引,数据对齐会同时产生在行和列上。

 in: df1 = pd.DataFrame(np.arange(9.).reshape((3, 3)),
                        columns=list('bcd'),
                        index=['Ohio', 'Texas', 'Colorado'])
     df2 = pd.DataFrame(np.arange(12.).reshape((4, 3)),
                        columns=list('bde'),
                        index=['Utah', 'Ohio', 'Texas', 'Oregon'])
     df1 + df2
out:             b   c     d   e
     Colorado  NaN NaN   NaN NaN
     Ohio      3.0 NaN   6.0 NaN
     Oregon    NaN NaN   NaN NaN
     Texas     9.0 NaN  12.0 NaN
     Utah      NaN NaN   NaN NaN

 in: df1.add(df2, fill_value=0)  # 如果不想要空值,能够应用 add(),并指明 fill_value=0
out:             b    c     d     e
     Colorado  6.0  7.0   8.0   NaN  # 能够看到还是存在空值,这是因为当两个表中都不存在值时不能填充
     Ohio      3.0  1.0   6.0   5.0
     Oregon    9.0  NaN  10.0  11.0
     Texas     9.0  4.0  12.0   8.0
     Utah      0.0  NaN   1.0   2.0  

如果是 DataFrame 和 Series 进行运算,运算会被逐行播送:

 in: frame = pd.DataFrame(np.arange(12.).reshape((4, 3)),
                          columns=list('bde'),
                          index=['Utah', 'Ohio', 'Texas', 'Oregon'])
     series = frame.iloc[0]
     frame
     series
out:           b     d     e
     Utah    0.0   1.0   2.0
     Ohio    3.0   4.0   5.0
     Texas   6.0   7.0   8.0
     Oregon  9.0  10.0  11.0
     
     b    0.0
     d    1.0
     e    2.0
 in: frame - series  # 表格从第一行开始减 series,始终向下播送,减到最初一行
out:           b    d    e
     Utah    0.0  0.0  0.0
     Ohio    3.0  3.0  3.0
     Texas   6.0  6.0  6.0
     Oregon  9.0  9.0  9.0

3.2.6 函数利用

numpy 的 ufuncs(元素级数组办法)也可用于操作 pandas 对象。而 pandas 对象也内置了许多罕用的统计办法,能够间接调用。

 in: frame = pd.DataFrame(np.random.randn(4, 3),
                          columns=list('bde'),
                          index=['Utah', 'Ohio', 'Texas', 'Oregon'])
     frame
out:                b         d         e
     Utah   -0.661018  0.130761  0.508856
     Ohio    0.174303 -1.288930 -0.384396
     Texas  -0.523870 -0.657847 -0.822806
     Oregon  0.969613  0.894881 -0.623135

 in: np.abs(frame)
     frame.abs()  # DataFrame 曾经内置了 abs() 办法,该行和上一行会产生雷同的成果
out: Utah    0.661018  0.130761  0.508856
     Ohio    0.174303  1.288930  0.384396
     Texas   0.523870  0.657847  0.822806
     Oregon  0.969613  0.894881  0.623135

简单的计算能够应用 lambda 函数,并用 apply() 将函数利用到由各列或行所造成的一维数组上。

 in: frame.apply(lambda x: x.max() - x.min())  # 对每列进行函数运算
out: b    1.630631
     d    2.183811
     e    1.331663
     dtype: float64

 in: frame.apply(lambda x: x.max() - x.min(), axis=1)  # 匹配列,对每行进行函数运算
out: Utah      1.169874
     Ohio      1.463233
     Texas     0.298937
     Oregon    1.592748
     dtype: float64

3.2.7 排序

对于 DataFrame 来说,排序能够按行索引排,也能够按列索引排。

 in: frame = pd.DataFrame(np.arange(8).reshape((2, 4)),
                     index=['three', 'one'],
                     columns=['d', 'a', 'b', 'c'])
     frame
out:        d  a  b  c
     three  0  1  2  3
     one    4  5  6  7

 in: frame.sort_index()  # 按行排
out:        d  a  b  c
     one    4  5  6  7
     three  0  1  2  3
        
 in: frame.sort_index(axis=1, ascending=False)  # 按列排,降序排
out:        d  c  b  a
     three  0  3  2  1
     one    4  7  6  5

此外,还能够按值排序:

 in: frame.sort_values(by='a',ascending=False)  # 也能够按值排列
out:        d  a  b  c
     one    4  5  6  7
     three  0  1  2  3

 in: me.sort_values(by=['a','b'])  # 按多个列的值来排
out:        d  a  b  c
     three  0  1  2  3
     one    4  5  6  7

5.3 描述性统计

先创立一个 DataFrame 用于举例:

 in: df = pd.DataFrame([[1.4, np.nan], [7.1, -4.5],[np.nan, np.nan], [0.75, -1.3]],
                       index=['a', 'b', 'c', 'd'],
                       columns=['one', 'two'])
     df
out:     one  two
     a  1.40  NaN
     b  7.10 -4.5
     c   NaN  NaN
     d  0.75 -1.3                

描述性统计的方向默认是以列为单位,统计行数据的:

 in: df.sum()
out: one    9.25
     two   -5.80
     dtype: float64    

 in: df.mean(axis=1)  # 也能够按行统计
out: a    1.400  # 包含一个空值时,空值被跳过了
     b    1.300
     c      NaN  # 都是空值时,返回的也是空值
     d   -0.275
     dtype: float64

能够间接应用 describe() 返回描述性统计后果:

 in: df.describe()
out:             one       two
     count  3.000000  2.000000
     mean   3.083333 -2.900000
     std    3.493685  2.262742
     min    0.750000 -4.500000
     25%    1.075000 -3.700000
     50%    1.400000 -2.900000
     75%    4.250000 -2.100000
     max    7.100000 -1.300000

还能够计算相关系数:

 in: df.corr()  # 默认为 pearson 相关系数
out:      one  two
     one  1.0 -1.0
     two -1.0  1.0

还有波及到惟一值、值计数以及成员资格的统计:

 in: obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
     obj
out: 0    c
     1    a
     2    d
     3    a
     4    a
     5    b
     6    b
     7    c
     8    c
     dtype: object

 in: obj.unique()  # 返回一个惟一值数组
out: array(['c', 'a', 'd', 'b'], dtype=object)

 in: obj.value_counts()  # 计算一个值呈现的频率
out: a    3
     c    3
     b    2
     d    1
     dtype: int64
 
 in: obj.isin(['b', 'c'])  # 是否在 [] 中
out: 0     True
     1    False
     2    False
     3    False
     4    False
     5     True
     6     True
     7     True
     8     True
     dtype: bool

注:转载请注明出处。

本文属于《利用 Python 进行数据分析》读书笔记系列:

  • 利用 Python 进行数据分析 —— 1 数据结构、函数和文件
  • 利用 Python 进行数据分析 —— 2 NumPy 根底
退出移动版