Pandas 学习笔记

DataFrame 对象操作

添加数据

>>> import numpy as np
>>> import pandas as pd
>>> frame1 = pd.DataFrame(np.arange(16).reshape((4,4)),
...                      index=['red','blue','yellow','white'],
...                      columns=['ball','pen','pencil','paper'])
>>> frame1
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
white     12   13      14     15
>>> frame1['pen']
red        1
blue       5
yellow     9
white     13
Name: pen, dtype: int32
>>> frame1.loc['blue']
ball      4
pen       5
pencil    6
paper     7
Name: blue, dtype: int32
>>> frame1.iloc[1]
ball      4
pen       5
pencil    6
paper     7
Name: blue, dtype: int32
>>> frame1.iloc[1]['pen']
5

使用 loc() 命令可以以 index 名的方式获得 DataFrame 中的某行数据,而 iloc() 则使用 index 的排序坐标来获得 DataFrame 中的某行数据。通过多次使用可以获得其中的数据。

>>> data1 = {'red':2,'blue':4,'yellow':6,'white':8}
>>> frame1['book'] = data1
>>> frame1
        ball  pen  pencil  paper    book
red        0    1       2      3     red
blue       4    5       6      7    blue
yellow     8    9      10     11  yellow
white     12   13      14     15   white

使用 frame1['book'] 命令可以添加一列数据,其 column 名为 book。该数据以数列形式添加。如果希望以字典形式添加,可以先将 DataFrame 转置之后以字典形式添加行数据后再转置回来。也可以使用 map() 映射操作,添加字典,不过要注意需要先将索引 index 通过 reset_index() 命令转化为一列再进行添加。

>>> import numpy as np
>>> import pandas as pd
>>>
>>> frame1 = pd.DataFrame(np.arange(16).reshape((4,4)),
...                      index=['red','blue','yellow','white'],
...                      columns=['ball','pen','pencil','paper'])
>>> frame1
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
white     12   13      14     15
>>> book = {'red':10, 'blue':20, 'yellow':30, 'white':40}
>>> frame2 = frame1.reset_index()
>>> frame2
    index  ball  pen  pencil  paper
0     red     0    1       2      3
1    blue     4    5       6      7
2  yellow     8    9      10     11
3   white    12   13      14     15
>>> frame2['price'] = frame2['index'].map(book)
>>> frame2
    index  ball  pen  pencil  paper  price
0     red     0    1       2      3     10
1    blue     4    5       6      7     20
2  yellow     8    9      10     11     30
3   white    12   13      14     15     40
>>> data2 = {'ball':0,'pen':2,'pencil':4,'paper':6,'book':8}
>>> frame1.append(data2,ignore_index=True)
   ball  pen  pencil  paper    book
0     0    1       2      3     red
1     4    5       6      7    blue
2     8    9      10     11  yellow
3    12   13      14     15   white
4     0    2       4      6       8
>>> series2 = pd.Series(data2)
>>> series2.name = 'green'
>>> frame1.append(series2)
        ball  pen  pencil  paper    book
red        0    1       2      3     red
blue       4    5       6      7    blue
yellow     8    9      10     11  yellow
white     12   13      14     15   white
green      0    2       4      6       8

以字典形式添加行数据时,使用 .append() 命令,设置 ignore_index = True 可以忽略索引名,这将导致索引将以0,1...数字表示。而要想保持索引名,则需要先将字典数据转化为 Series 类型,再添加 Series 名作为转化后数据行的索引名。以上操作不会改变 frame1 的数据。如果需要改变还需要将结果赋值给 frame1。

删除数据

>>> frame1.drop('white')
        ball  pen  pencil  paper    book
red        0    1       2      3     red
blue       4    5       6      7    blue
yellow     8    9      10     11  yellow
>>> frame1.drop('white',inplace=True)
>>> frame1
        ball  pen  pencil  paper    book
red        0    1       2      3     red
blue       4    5       6      7    blue
yellow     8    9      10     11  yellow
>>> frame1.drop('book',axis=1)
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
>>> frame1.drop('book',axis=1,inplace=True)
>>> frame1
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11

使用 .drop()命令可以删除 DataFrame 中某一行的数据。设置 inplace=True 可以在原数据上直接操作。设置 axis = 1 可以删除列数据。

索引操作

索引操作包括 reindex()set_index()reset_index() 等。

其中 reindex() 改变 DataFrame 中索引的顺序,同时增加或减少条目。set_index('item') 表示将 item 列设为索引,注意这种方法将弃置原来的索引列,因此如果需要保留原来的索引列内容,需要先使用 reset_index() 命令。在 reset_index() 中设置 drop=True 将弃置索引列。使用 reset_index('item') 命令将 item 列移出索引,如果原来有多列索引的话,保留其他列索引。

reindex() 中,还有 method 方法,可以设置 ffill、bfill 等来确定缺失值的插入方法。

单独某一行的索引不能修改,但是可以通过 obj.index = ['id1','id2'] 这样的方式直接覆盖原来的索引。

>>> frame1
        ball  pen  pencil  paper
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
>>> frame1.reindex(['red','blue','white'])
       ball  pen  pencil  paper
red     0.0  1.0     2.0    3.0
blue    4.0  5.0     6.0    7.0
white   NaN  NaN     NaN    NaN
>>> frame1.reset_index()
    index  ball  pen  pencil  paper
0     red     0    1       2      3
1    blue     4    5       6      7
2  yellow     8    9      10     11
>>> frame1.reset_index(drop=True)
   ball  pen  pencil  paper
0     0    1       2      3
1     4    5       6      7
2     8    9      10     11
>>> frame1.index.name = 'id'
>>> frame1.reset_index()
       id  ball  pen  pencil  paper
0     red     0    1       2      3
1    blue     4    5       6      7
2  yellow     8    9      10     11

按行或列执行操作的函数

除了通用函数,还可以自定义函数。注意这些函数对一维数组进行运算,返回结果为一个数值。

>>> f = lambda x: x.max() - x.min()
>>> def f(x):
...     return x.max()-x.min()
...
>>> frame1.apply(f)
ball      8
pen       8
pencil    8
paper     8
dtype: int64
>>> frame1.apply(f, axis=1)
id
red       3
blue      3
yellow    3
dtype: int64

apply() 函数并不是一定要返回一个标量,它还可以返回 Series 对象,因而可以借助它同时执行多个函数。没调用一次函数,就会有两个或两个以上的返回结果。

>>> def f(x):
...     return pd.Series([x.min(), x.max()], index=['min','max'])
...
>>> frame1.apply(f)
     ball  pen  pencil  paper
min     0    1       2      3
max     8    9      10     11

排序

使用 sort_index() 函数可以按索引排序,使用 sort_values() 可以按值排序,利用关键词 by 可以指定列名。关键词 ascending=False 为倒序排列。关键词 axis=1 为按列排列。

>>> frame1
        ball  pen  pencil  paper
id
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
>>> frame1.sort_index()
        ball  pen  pencil  paper
id
blue       4    5       6      7
red        0    1       2      3
yellow     8    9      10     11
>>> frame1.sort_values(by=['pen','paper'])
        ball  pen  pencil  paper
id
red        0    1       2      3
blue       4    5       6      7
yellow     8    9      10     11
>>> frame1.sort_index(ascending=False)
        ball  pen  pencil  paper
id
yellow     8    9      10     11
red        0    1       2      3
blue       4    5       6      7
>>> frame1.sort_index(axis=1)
        ball  paper  pen  pencil
id
red        0      3    1       2
blue       4      7    5       6
yellow     8     11    9      10

相关性和协方差

>>> frame2 = pd.DataFrame([[1,4,3,6],[4,5,6,1],[3,3,1,5],[4,1,6,4]],
...                      index=['red','blue','yellow','white'],
...                      columns=['ball','pen','pencil','paper'])
>>> frame2
        ball  pen  pencil  paper
red        1    4       3      6
blue       4    5       6      1
yellow     3    3       1      5
white      4    1       6      4
>>> frame2.corr()
            ball       pen    pencil     paper
ball    1.000000 -0.276026  0.577350 -0.763763
pen    -0.276026  1.000000 -0.079682 -0.361403
pencil  0.577350 -0.079682  1.000000 -0.692935
paper  -0.763763 -0.361403 -0.692935  1.000000
>>> frame2.cov()
            ball       pen    pencil     paper
ball    2.000000 -0.666667  2.000000 -2.333333
pen    -0.666667  2.916667 -0.333333 -1.333333
pencil  2.000000 -0.333333  6.000000 -3.666667
paper  -2.333333 -1.333333 -3.666667  4.666667

NaN 数据

使用 dropna() 命令可以删除所有包含 NaN 的行和列。使用关键词 how='all' 可以确保只有全部为 NaN 的行和列才被删除。使用 fillna(0) 可以将所有 NaN 值替换为 0。

等级索引和分级

>>> mframe = pd.DataFrame(np.random.randn(16).reshape(4,4),
...                      index=[['white','white','red','red'],['up','down','up','dow']],
...                      columns=['ball','pen','pencil','paper'])
>>> mframe.columns.names = ['object']
>>> mframe.index.names = ['colors','status']
>>> mframe
object             ball       pen    pencil     paper
colors status
white  up     -1.259801 -1.383362 -0.874770 -1.059613
       down    0.695087 -0.577320  2.173605  0.982928
red    up      0.065333 -1.305821 -0.153447 -0.291298
       dow    -0.393989 -0.863765 -1.076841  1.118641

先设定好一个 DataFrame 格式的数据集。使用 swaplevel() 命令可以互换两个层级的名称位置。

>>> mframe.swaplevel('colors','status')
object             ball       pen    pencil     paper
status colors
up     white  -1.259801 -1.383362 -0.874770 -1.059613
down   white   0.695087 -0.577320  2.173605  0.982928
up     red     0.065333 -1.305821 -0.153447 -0.291298
dow    red    -0.393989 -0.863765 -1.076841  1.118641

通过 sort_index() 命令可以针对索引排序,通过关键词 level 指定需要排序的索引名称。

>>> mframe.sort_index(level='colors')
object             ball       pen    pencil     paper
colors status
red    dow    -0.393989 -0.863765 -1.076841  1.118641
       up      0.065333 -1.305821 -0.153447 -0.291298
white  down    0.695087 -0.577320  2.173605  0.982928
       up     -1.259801 -1.383362 -0.874770 -1.059613

通过 reset_index()set_index() 可以更改索引。

>>> mframe.reset_index().set_index(['ball','pen'])
object              colors status    pencil     paper
ball      pen
-1.259801 -1.383362  white     up -0.874770 -1.059613
 0.695087 -0.577320  white   down  2.173605  0.982928
 0.065333 -1.305821    red     up -0.153447 -0.291298
-0.393989 -0.863765    red    dow -1.076841  1.118641

如果想对行一层级进行统计,把层级的名称赋给 level 选项即可。

>>> mframe.sum(level='colors')
object      ball       pen    pencil     paper
colors
red    -0.328656 -2.169587 -1.230288  0.827343
white  -0.564714 -1.960682  1.298836 -0.076685

函数应用和映射

Dataframe 中的 apply 方法可以将函数应用到由各列或行所形成的一维数组上。

>>> frame = pd.DataFrame(np.random.randn(4,3), columns=list('bde'),
...                     index=['Utah','Ohio','Texas','Oregon'])
>>> frame
               b         d         e
Utah   -0.218889 -1.237154 -2.911465
Ohio   -1.760496 -0.362065 -1.057770
Texas  -0.569765 -0.472543 -0.754792
Oregon -1.440514  0.039739 -0.696772
>>> np.abs(frame)
               b         d         e
Utah    0.218889  1.237154  2.911465
Ohio    1.760496  0.362065  1.057770
Texas   0.569765  0.472543  0.754792
Oregon  1.440514  0.039739  0.696772
>>> f = lambda x: x.max()-x.min()
>>> frame.apply(f)
b    1.541607
d    1.276893
e    2.214693
dtype: float64
>>> frame.apply(f, axis=1)
Utah      2.692576
Ohio      1.398431
Texas     0.282249
Oregon    1.480253
dtype: float64
>>> def f(x):
...     return pd.Series([x.min(), x.max()], index=['min','max'])
...
>>> frame.apply(f)
            b         d         e
min -1.760496 -1.237154 -2.911465
max -0.218889  0.039739 -0.696772
>>> frame.apply(f)
            b         d         e
min -1.760496 -1.237154 -2.911465
max -0.218889  0.039739 -0.696772
>>> def f(x):
...     return pd.Series([x.min(), x.max()], index=['min','max'])
...
>>> frame.apply(f)
            b         d         e
min -1.760496 -1.237154 -2.911465
max -0.218889  0.039739 -0.696772

元素级的 Python 函数也是可以用的。如果想得到 frame 中各个浮点值的格式化字符串,使用 applymap 即可。

>>> format = lambda x: '%.2f' % x
>>> frame.applymap(format)
            b      d      e
Utah    -0.22  -1.24  -2.91
Ohio    -1.76  -0.36  -1.06
Texas   -0.57  -0.47  -0.75
Oregon  -1.44   0.04  -0.70