Pandas is a software library written for the Python programming language for data manipulation and analysis. In particular, it offers data structures and operations for manipulating numerical tables and time series.

Topic 1 Data Structure

1.1 Overview

Pandas包含以下三个数据结构:

  • 系列(Series)
  • 数据帧(DataFrame)
  • 面板(Panel)

这些数据结构构建在Numpy数组之上,这意味着它们处理速度很快.

数据结构 维数 描述
Series 1 一维数组, 大小可变,由同种数据类型元素组成.
DataFrame 2 二维数组, 大小可变的表格结构, 它含有一组有序的列, 每列可以是不同的数据类型(整型、字符串、 布尔值等)
Panel 3 大小可变的三维数组

可以简单理解为, 高维数据结构是低维数据结构的容器. 例如,DataFrameSeries的容器, PanelDataFrame的容器.

1.2 Series

Series是由相同数据类型组成的一维数组. 有三个关键点:

  • 同种类型数据构成 (同 numpy 的 ndarray)
  • 大小可变
  • 数据可变

1.3 DataFrame

数据帧 (DataFrame) 是大小可变的数据结构, 每列可以是不同的数据类型 (整型、字符串、布尔值等). 有三个关键点:

  • 可以由不同的数据类型构成
  • 大小可变
  • 数据可变
姓名 年龄 性别 等级
Maxsu 25 4.45
Katie 34 2.78
Vina 46 3.9
Lia 4.6

上表表示某销售团队的绩效评级数据, 数据以行和列表示, 每列表示一个属性, 每行代表一个人. DataFrame 四列的数据类型分别为: 字符串, 整数, 字符串, 浮点型.

1.4 Panel

面板(Panel)可以由不同的数据类型构成的三维数据结构, PanelDataFrame的容器.

Topic 2 Series

序列 (Series) 是 pandas 中的一维数据结构,类似于 python 中的 list 和 Numpy 中的 ndarray 对象,在 Series 中包含的数据类型可以是整数,浮点数,字符串,python对象等.

2.1 Series Creation

Series 的构造函数如下:

1
2
3
4
5
6
7
pandas.Series(data, index, dtype, copy)

# 参数说明
# data: 支持多种数据类型,如:ndarray, list ...
# index: 索引值必须是唯一的(set), 与data的长度相同, 默认为np.arange(n)
# dtype: 数据类型, 同 numpy 中介绍的数据类型
# copy: 是否复制数据, 默认为 False

[例 2.1] 创建一个空的 Series

1
2
3
4
import pandas as pd

s = pd.Series()
print('空 Series:\n',s)

输出结果是:

1
2
空 Series:
Series([], dtype: float64)

[例 2.2] 从 ndarray 创建一个 Series

1
2
3
4
5
6
import pandas as pd
import numpy as np

a = np.array(['a','b','c','d'])
s = pd.Series(a)
print(s)

输出结果是:

1
2
3
4
5
0    a
1 b
2 c
3 d
dtype: object

注:

我们其实可以根据实际情况传入索引, 也就是左边那一列

[例 2.3]

1
2
3
4
5
6
import pandas as pd
import numpy as np

a = np.array(['a','b','c','d'])
s = pd.Series(a,index=[100,101,102,103])
print(s)

输出结果是:

1
2
3
4
5
100    a
101 b
102 c
103 d
dtype: object

[例 2.4] 从字典创建一个 Series

keyindex, valueSeries 的值

1
2
3
4
5
import pandas as pd

a = {'a':1,'b':2,'c':3}
s = pd.Series(a)
print(s)

输出结果是:

1
2
3
4
a    1
b 2
c 3
dtype: int64

注:

我们也可以传入索引

[例 2.5]

索引顺序保持不变, 缺少的元素使用NaN(不是数字)填充.

1
2
3
4
5
import pandas as pd

a = {'a':1,'b':2,'c':3}
s = pd.Series(a,index=['b','c','d','e','a'])
print(s)

输出结果是:

1
2
3
4
5
6
b    2.0
c 3.0
d NaN
e NaN
a 1.0
dtype: float64

[例 2.6] 从标量创建一个 Series

如果数据是标量类型, 则必须提供索引. 重复该值以匹配索引的长度.

1
2
3
4
import pandas as pd

s = pd.Series(5, index=[0,1,2,3])
print(s)

输出结果是:

1
2
3
4
5
0    5
1 5
2 5
3 5
dtype: int64

2.2 Reading Series

Series 中的数据可以使用类似于访问 ndarray 中的数据来访问.

[例 2.7] 检索第一个元素

1
2
3
4
import pandas as pd

s = pd.Series([1,2,3,4,5],index=['a','b','c','d','e'])
print('获取第一个元素:\n',s[0])

输出结果是:

1
2
获取第一个元素:
1

[例 2.8] 获取前三个元素

1
2
3
4
5
import pandas as pd

s = pd.Series([1,2,3,4,5],index=['a','b','c','d','e'])
print('获取前三个元素:')
print(s[:3])

输出结果是:

1
2
3
4
5
获取前三个元素:
a 1
b 2
c 3
dtype: int64

我们也能通过 Seriesindex 来访问其数据.

[例 2.9] 使用 index 访问单个数据

1
2
3
4
import pandas as pd

s = pd.Series([1,2,3,4,5],index=['a','b','c','d','e'])
print('访问索引为 d 的元素:\n',s['d'])

输出结果是:

1
2
访问索引为 d 的元素:
4

[例 2.10] 使用索引访问多个元素

1
2
3
4
5
import pandas as pd

s = pd.Series([1,2,3,4,5],index=['a','b','c','d','e'])
print('使用索引访问多个元素:')
print(s[['a','c','d']])

输出结果是:

1
2
3
4
5
使用索引访问多个元素:
a 1
c 3
d 4
dtype: int64

2.3 Properties of Series

属性 说明
axes 返回 Series 的索引列表
dtype 返回 Series 的数据类型
empty 判断 Series 是否为空, 若为空, 返回 True
ndim 返回基础数据的维数
size 返回基础数据中的元素个数
values 将 Series 作为 ndarray 返回
head() 返回前 n 个元素
tail() 返回最后 n 个元素

2.3.1 Series.axes

[例 2.11] 返回 Series 的索引列表

1
2
3
4
5
import pandas as pd
import numpy as np

s = pd.Series(np.random.randn(4))
print('数据的索引是:\n',s.axes)

输出结果是:

1
2
数据的索引是:
[RangeIndex(start=0, stop=4, step=1)]

2.3.2 Series.empty

[例 2.12] 查看 Series 是否为空

1
2
3
4
5
import pandas as pd
import numpy as np

s = pd.Series(np.random.randn(4))
print('数据为空?\n',s.empty)

输出结果是:

1
2
数据为空?
False

2.3.3 Series.ndim

[例 2.13] 返回数据的维数

1
2
3
4
5
import pandas as pd
import numpy as np

s = pd.Series(np.random.randn(4))
print('数据的维数:\n',s.ndim)

输出结果是:

1
2
数据的维数:
1

2.3.4 Series.size

[例 2.14] 查看 Series 中的元素个数

1
2
3
4
5
import pandas as pd
import numpy as np

s = pd.Series(np.random.randn(4))
print('Series 包含的元素个数:\n',s.size)

输出结果是:

1
2
Series 包含的元素个数:
4

2.3.5 Series.values

[例 2.15] 将 Series 作为 ndarray 返回

1
2
3
4
5
6
7
8
9
import pandas as pd
import numpy as np

s = pd.Series(np.random.randn(4))
print('我们的数据是:\n',s)
print('\n')
print('将数据转换成 ndarray.')
a = s.values
print('数据类型是:\n',type(a))

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
我们的数据是:
0 0.139829
1 -0.858539
2 -0.060587
3 0.087893
dtype: float64


将数据转换成 ndarray.
数据类型是:
<class 'numpy.ndarray'>

Topic 3 DataFrame

DataFrame 是二维数据结构, 它包含一组有序的列, 每列可以是不同的数据类型, DataFrame既有行索引, 也有列索引, 它可以看作是Series组成的字典, 不过这些Series共用一个索引. 其包含以下几个功能特点:

  • 不同的列可以是不同的数据类型
  • 大小可变
  • 包含行索引和列索引
  • 可以对行和列执行算术运算

3.1 DataFrame Creation

DataFrame 的构造函数如下:

1
2
3
4
5
6
7
8
pandas.DataFrame(data, index, columns, dtype, copy)

# 参数说明
# data: 支持多种数据类型,如:ndarray,series, lists, dict, constant 或另外一个 DataFrame
# index: 行标签, 如果没有传递索引值, 默认值为np.arange(n)
# columns: 列标签, 如果没有传递索引值, 默认值为np.arange(n)
# dtype: 每列的数据类型
# copy: 是否复制数据, 默认为 False

[例 3.1] 创建一个空的 DataFrame

1
2
3
4
import pandas as pd

df = pd.DataFrame()
print(df)

输出结果是:

1
2
3
Empty DataFrame
Columns: []
Index: []

[例 3.2] 从一个二维列表创建 DataFrame

1
2
3
4
5
import pandas as pd

l = [['Alex',10],['Bob',12],['Clarke',13]]
df = pd.DataFrame(l, columns=['Name','Age'])
print(df)

输出结果是:

1
2
3
4
     Name  Age
0 Alex 10
1 Bob 12
2 Clarke 13

[例 3.3] 从一个 dict 创建 DataFrame

1
2
3
4
5
import pandas as pd

data = {'Name':['Tom','Jack','Steve','Ricky'],'Age':[28,34,29,42]}
df = pd.DataFrame(data, index=['1st','2nd','3rd','4th'])
print(df)

输出结果是:

1
2
3
4
5
      Name  Age
1st Tom 28
2nd Jack 34
3rd Steve 29
4th Ricky 42

[例 3.4] 从 ndarray 创建 DataFrame

1
2
3
4
5
import pandas as pd

a = np.array([['Tom',28],['Jack',34],['Steve',29],['Ricky',42]])
df = pd.DataFrame(a, index=['1st','2nd','3rd','4th'],columns=['Name','Age'])
print(df)

输出结果是:

1
2
3
4
5
      Name Age
1st Tom 28
2nd Jack 34
3rd Steve 29
4th Ricky 42

[例 3.5] 从 Series 字典来创建 DataFrame

1
2
3
4
5
6
7
import pandas as pd

d = {'one' : pd.Series([1, 2, 3], index=['a', 'b', 'c']),
'two' : pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])}

df = pd.DataFrame(d)
print(df)

输出结果是:

1
2
3
4
5
   one  two
a 1.0 1
b 2.0 2
c 3.0 3
d NaN 4

3.2 DataFrame Operations

3.2.1 Reading Data from Columns

1
2
3
4
5
import pandas as pd

a = np.array([['Tom',28],['Jack',34],['Steve',29],['Ricky',42]])
df = pd.DataFrame(a, index=['1st','2nd','3rd','4th'],columns=['Name','Age'])
print(df['Name']) # 也可以是 print(df.Name)

输出结果是:

1
2
3
4
5
1st      Tom
2nd Jack
3rd Steve
4th Ricky
Name: Name, dtype: object

3.2.2 Reading Data from Rows

有两种方式读取行数据:

  • 使用 DataFrame.loc[] 依据行索引进行读取

    1
    2
    3
    4
    5
    6
    7
    import pandas as pd

    a = np.array([['Tom',28],['Jack',34],['Steve',29],['Ricky',42]])
    df = pd.DataFrame(a, index=['1st','2nd','3rd','4th'],columns=['Name','Age'])

    print('第三行的数据是:')
    print(df.loc['3rd'])

    输出结果是:

    1
    2
    3
    4
    第三行的数据是:
    Name Steve
    Age 29
    Name: 3rd, dtype: object
  • 使用 DataFrame.iloc[] 依据 row number 进行读取

    1
    2
    3
    4
    5
    6
    7
    import pandas as pd

    a = np.array([['Tom',28],['Jack',34],['Steve',29],['Ricky',42]])
    df = pd.DataFrame(a, index=['1st','2nd','3rd','4th'],columns=['Name','Age'])

    print('倒数两行的数据是:')
    print(df.iloc[-2:])

    输出结果是:

    1
    2
    3
    4
    倒数两行的数据是:
    Name Age
    3rd Steve 29
    4th Ricky 42

    3.2.3 Adding and Deleting Columns

添加列有两种方式:

  • 传入新的 Series
  • 利用现有列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd

a = np.array([['Tom',28],['Jack',34],['Steve',29],['Ricky',42]])
df = pd.DataFrame(a, index=['1st','2nd','3rd','4th'],columns=['Name','Age'])
print('原 DataFrame:')
print(df)
print('\n')

print('通过传入一个新的 Series 来增加新列:')
df['Sex'] = pd.Series(['Male','Male','Male','Female'],index=['1st','2nd','3rd','4th'])
print(df)
print('\n')

print('通过操作已有列来增加新列:')
df['Name and Sex'] = df['Name'] + df['Sex']
print(df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
原 DataFrame:
Name Age
1st Tom 28
2nd Jack 34
3rd Steve 29
4th Ricky 42


通过传入一个新的 Series 来增加新列:
Name Age Sex
1st Tom 28 Male
2nd Jack 34 Male
3rd Steve 29 Male
4th Ricky 42 Female


通过操作已有列来增加新列:
Name Age Sex Name and Sex
1st Tom 28 Male TomMale
2nd Jack 34 Male JackMale
3rd Steve 29 Male SteveMale
4th Ricky 42 Female RickyFemale

删除列有两种方式:

  • 使用 del 关键字
  • 使用 DataFrame.pop() 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd

a = np.array([['Tom',28],['Jack',34],['Steve',29],['Ricky',42]])
df = pd.DataFrame(a, index=['1st','2nd','3rd','4th'],columns=['Name','Age'])
df['Sex'] = pd.Series(['Male','Male','Male','Female'],index=['1st','2nd','3rd','4th'])
print('原 DataFrame:')
print(df)
print('\n')

print('使用 del 关键字:')
del df['Sex']
print(df)
print('\n')

print('使用 DataFrame.pop() 函数') # 如你在 python 中学的 pop 函数一样, 这个函数会返回该列
print('返回列:')
df.pop('Age')
print()
print('修改之后的 DataFrame:')
print(df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
原 DataFrame:
Name Age Sex
1st Tom 28 Male
2nd Jack 34 Male
3rd Steve 29 Male
4th Ricky 42 Female


使用 del 关键字:
Name Age
1st Tom 28
2nd Jack 34
3rd Steve 29
4th Ricky 42


使用 DataFrame.pop() 函数
返回列:
1st 28
2nd 34
3rd 29
4th 42
Name: Age, dtype: object

修改之后的 DataFrame:
Name
1st Tom
2nd Jack
3rd Steve
4th Ricky

3.2.4 Adding and Deleting Rows

添加行只有一种方式: DataFrame.append(pandas.DataFrame)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as np

df1 = pd.DataFrame([[1,2],[3,4]],columns=['a','b'])
df2 = pd.DataFrame([[5,6],[7,8]],columns=['a','b'])

print('df1:')
print(df1)
print('\n')

print('df2:')
print(df2)
print('\n')

print('将 df2 添加到 df1 之后:')
print(df1.append(df2))

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
df1:
a b
0 1 2
1 3 4


df2:
a b
0 5 6
1 7 8


将 df2 添加到 df1 之后:
a b
0 1 2
1 3 4
0 5 6
1 7 8

使用索引标签从 DataFrame 中删除行. 如果标签重复, 则会删除多行.

1
2
3
4
5
6
7
8
9
import pandas as np

df1 = pd.DataFrame([[1,2],[3,4]],columns=['a','b'])
df2 = pd.DataFrame([[5,6],[7,8]],columns=['a','b'])

df1 = df1.append(df2)
print('删除行标为 0 的行:')
df1 = df1.drop(0)
print(df1)

输出结果是:

1
2
3
4
删除行标为 0 的行:
a b
1 3 4
1 7 8

3.2.5 Reindexing and Renaming

  1. DataFrame.reindex()

    我们首先看对 Series 重新索引

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import pandas as pd 

    s = pd.Series([1,7,3,9],index=['d','c','a','f'])
    print('我们的数据是:')
    print(s)
    print('\n')

    print('reindex 函数会对数据重新排序, 缺失值会有 NaN 填补:')
    s = s.reindex(index=['a','b','c','d','e','f'])
    print(s)

    输出结果是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    我们的数据是:
    d 1
    c 7
    a 3
    f 9
    dtype: int64


    reindex 函数会对数据重新排序, 缺失值会有 NaN 填补:
    a 3.0
    b NaN
    c 7.0
    d 1.0
    e NaN
    f 9.0
    dtype: float64

    fillna() 函数一样, reindex 可以选择重新索引时的数据插入方式来填补缺失值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import pandas as pd

    s = pd.Series(['blue','red','black'],index=[0,2,4])
    print('我们的数据是:')
    print(s)
    print('\n')

    print('reindex 之后数据是:')
    s = s.reindex(index=range(6),method='ffill') # 前向填充
    print(s)

    输出结果是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    我们的数据是:
    0 blue
    2 red
    4 black
    dtype: object


    reindex 之后数据是:
    0 blue
    1 blue
    2 red
    3 red
    4 black
    5 black
    dtype: object

    我们再来看一下对 DataFrame 的索引

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import pandas as pd
    import pandas as np

    s = pd.DataFrame(np.arange(9).reshape(3,3), index=['a','c','d'], columns=['one','two','four'])
    print('我们的数据是:')
    print(s)
    print('\n')

    print('使用 reindex 填充数据, 传入参数 fill_value 可以填充缺失值:')
    s = s.reindex(index=['a','b','c','d'],columns=['one','two','three','four'],fill_value=100)
    print(s)

    输出结果是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    我们的数据是:
    one two four
    a 0 1 2
    c 3 4 5
    d 6 7 8


    使用 reindex 填充数据, 传入参数 fill_value 可以填充缺失值:
    one two three four
    a 0 1 100 2
    b 100 100 100 100
    c 3 4 100 5
    d 6 7 100 8
  2. DataFrame.rename()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import pandas as pd
    import numpy as np

    df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
    df.rename(columns={"A": "a", "B": "c"})
    a c
    0 1 4
    1 2 5
    2 3 6

    df.rename(index={0: "x", 1: "y", 2: "z"})
    A B
    x 1 4
    y 2 5
    z 3 6

    df.rename(str.lower, axis='columns')
    a b
    0 1 4
    1 2 5
    2 3 6

    df.rename({1: 2, 2: 4}, axis='index')
    A B
    0 1 4
    2 2 5
    4 3 6

    3.3 Properties of DataFrame

属性 描述
T 转置行和列
axes 返回 DataFrame 的行和列标签
dtype 返回 DataFrame 中每一列的数据类型
empty 若 DataFrame 为空, 则返回 True
ndim 返回 DataFrame 维度的数量, 默认为 2
shape 返回 DataFrame 的维度
size 返回 DataFrame 中元素的个数
values 将 DataFrame 中的数据以 ndarray 返回
head() 返回开头前 n
tail() 返回最后 n

3.3.1 DataFrame.T

返回DataFrame的转置, 行和列将交换:

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd

d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack']),
'Age':pd.Series([25,26,25,23,30,29,23]),
'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8])}

df = pd.DataFrame(d)
print('原数据是:')
print(df)
print('\n')

print('转置之后的数据是:')
print(df.T)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
原数据是:
Name Age Rating
0 Tom 25 4.23
1 James 26 3.24
2 Ricky 25 3.98
3 Vin 23 2.56
4 Steve 30 3.20
5 Minsu 29 4.60
6 Jack 23 3.80


转置之后的数据是:
0 1 2 3 4 5 6
Name Tom James Ricky Vin Steve Minsu Jack
Age 25 26 25 23 30 29 23
Rating 4.23 3.24 3.98 2.56 3.2 4.6 3.8

3.3.2 DataFrame.axes

返回 DataFrame 的行轴标签和列轴标签列表

1
2
3
4
5
6
7
8
9
import pandas as pd

d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack']),
'Age':pd.Series([25,26,25,23,30,29,23]),
'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8])}

df = pd.DataFrame(d)
print('行标签和列标签是:')
print(df.axes)

输出结果是:

1
2
行标签和列标签是:
[RangeIndex(start=0, stop=7, step=1), Index(['Name', 'Age', 'Rating'], dtype='object')]

3.3.3 DataFrame.dtypes

返回每列的数据类型

1
2
3
4
5
6
7
8
9
import pandas as pd

d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack']),
'Age':pd.Series([25,26,25,23,30,29,23]),
'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8])}

df = pd.DataFrame(d)
print('每列的数据类型:')
print(df.dtypes)

数据类型是:

1
2
3
4
5
每列的数据类型:
Name object
Age int64
Rating float64
dtype: object

3.4 DataFrame MultiIndex

MultiIndex 表示多级索引, 它是从Index继承过来的, 其中多级标签用元组对象来表示.

3.4.1 MultiIndex Creation

我们主要使用 pandas.MultiIndex.from_arrays() 来创建多级索引.

1
2
3
4
5
6
7
8
9
import pandas as pd
import numpy as np

class1=["A","A","B","B",'B']
class2=["x1","x2","y1","y2",'y3']
multi_index=pd.MultiIndex.from_arrays([class1,class2],names=["class1","class2"])

df = pd.DataFrame(np.random.randint(1,10,(5,3)),index=multi_index)
df

输出结果是:

image-20200821172656280

Series和DataFrame的列名称属性就是columns, 他也可以是一个 MultiIndex 对象:

1
2
3
4
5
6
7
8
9
10
import numpy as np
import pandas as pd

arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]

multi_index = pd.MultiIndex.from_arrays(arrays,names=['FirstLevel','SecondLevel'])

df = pd.DataFrame(np.random.randn(3, 8), index=['A', 'B', 'C'], columns=multi_index)
df

输出结果是:

image-20200821173753159

3.4.2 Use of MultiIndex

我们再来看一下如何使用 MultiIndex 选择数据

首先, 获取FirstLevel是bar的所有数据:

1
df['bar']

输出结果是:

image-20200821173853310

获取FirstLevel是bar, SecondLevel是one的所有数据:

1
df['bar','one'] # 也可以是 df['bar']['one']

输出结果是:

image-20200821173956442

如果要选择第二层的列名为one的所有数据, 我们需要借助xs方法:

1
df.xs('one',level=1,axis=1)

输出结果是:

image-20200821174211172

或者使用名称代替数字:

1
df.xs('one', level='SecondLevel', axis='columns')

输出结果是:

image-20200821174211172

xs 不仅可以用来选择列, 也可以用来选择行:

1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np
import pandas as pd

class1=["A","A","B","B",'B']
class2=["x1","x2","y1","y2",'y3']
multi_index=pd.MultiIndex.from_arrays([class1,class2],names=["class1","class2"])

df = pd.DataFrame(np.random.randint(1,10,(5,3)),index=multi_index)
print('我们的数据是:')
print(df)
print("\n")
print('选取结果是:')
df.xs('x1',level=1,axis='index')

输出结果是:

image-20200821174735322

注: 当然, 也可以使用我们学过的 loc 或者 iloc 函数.

3.5 DataFrame Iteration

我们可以直接迭代 DataFrameSeries:

  • Series - 值
  • DataFrame - 列标签

看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd
import numpy as np

N=20

df = pd.DataFrame({
'A': pd.date_range(start='2016-01-01',periods=N,freq='D'),
'x': np.linspace(0,stop=N-1,num=N),
'y': np.random.rand(N),
'C': np.random.choice(['Low','Medium','High'],N).tolist(),
'D': np.random.normal(100, 10, size=(N)).tolist()
})

for col in df:
print(col)

输出结果是:

1
2
3
4
5
A
x
y
C
D

若我们要遍历 DataFrame 中的行, 我们使用以下函数:

  • iteritems() - 遍历每一列
  • iterrows() - 遍历每一行
  • itertuples()

3.5.1 DataFrame.iteritems()

列为 key, 列中的值为 value.

1
2
3
4
5
6
7
8
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randn(4,3), columns=['A','B','C'])
for k,v in df.iteritems():
print('列名:',k)
print(v)
print('\n')

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
列名: A
0 0.296866
1 -0.148633
2 1.621515
3 -0.660666
Name: A, dtype: float64


列名: B
0 -0.253393
1 0.574725
2 0.503636
3 0.204850
Name: B, dtype: float64


列名: C
0 1.317005
1 0.346061
2 0.358695
3 0.341376
Name: C, dtype: float64

3.5.2 DataFrame.iterrows()

返回迭代器,产生每个索引值以及包含每行数据的序列.

1
2
3
4
5
6
7
8
import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randn(4,3), columns=['A','B','C'])
for row_index, row in df.iterrows():
print('行 index 是:', row_index)
print(row)
print('\n')

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[102]



df = pd.DataFrame(np.random.randn(4,3), columns=['A','B','C'])
for row_index, row in df.iterrows():
print('行 index 是:', row_index)
print(row)
print('\n')
行 index 是: 0
A -0.831008
B -0.864205
C 0.146520
Name: 0, dtype: float64


行 index 是: 1
A -0.991669
B -2.374277
C -0.356669
Name: 1, dtype: float64


行 index 是: 2
A 2.209128
B -0.420584
C 0.506585
Name: 2, dtype: float64


行 index 是: 3
A -1.058109
B -0.000286
C 1.033392
Name: 3, dtype: float64

3.5.3 DataFrame.itertuples()

itertuples()方法将为DataFrame中的每一行返回一个产生一个命名元组的迭代器. 元组的第一个元素将是行的相应索引值, 而剩余的值是行值.

1
2
3
4
5
6
7
8
9
10
import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randn(4,3), columns=['A','B','C'])
for row in df.itertuples():
print(row)
print('行 index 是:', row[0])
print('行的值是:')
print(row[1:])
print('\n')

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Pandas(Index=0, A=-0.3540071641471044, B=1.6031505884204515, C=-0.4870924983750079)
行 index 是: 0
行的值是:
(-0.3540071641471044, 1.6031505884204515, -0.4870924983750079)


Pandas(Index=1, A=0.5879313227987284, B=-0.5026893763858423, C=0.6591968909105315)
行 index 是: 1
行的值是:
(0.5879313227987284, -0.5026893763858423, 0.6591968909105315)


Pandas(Index=2, A=-1.8100048151441157, B=0.7800415414210258, C=-0.47082706870345153)
行 index 是: 2
行的值是:
(-1.8100048151441157, 0.7800415414210258, -0.47082706870345153)


Pandas(Index=3, A=0.22830697450955625, B=-0.6997787075277464, C=1.6736471725117756)
行 index 是: 3
行的值是:
(0.22830697450955625, -0.6997787075277464, 1.6736471725117756)

3.6 Sorting DataFrame

Pandas有两种排序方式, 它们分别是:

  • 按 index (可以是行, 也可以是列)
  • 按 values

我们先创建一个 DataFrame 用于之后的示例.

1
2
3
4
5
6
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randn(10,2),index=[1,4,6,2,3,5,9,8,0,7],columns=['col2','col1'])
print('我们的数据是:')
print(df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
我们的数据是:
col2 col1
1 -0.270190 0.970122
4 -0.387794 0.023349
6 -0.340047 0.412159
2 0.473514 0.697203
3 -1.062665 0.666765
5 -0.157076 0.810648
9 0.601996 0.700997
8 1.305286 0.591112
0 0.272618 -0.105529
7 -2.122524 -0.613860

3.6.1 DataFrame.sort_index()

使用sort_index()方法, 通过传递axis参数和排序顺序, 可以对DataFrame进行排序. 默认情况下, 按照升序对行 index 进行排序.

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randn(10,2),index=[1,4,6,2,3,5,9,8,0,7],columns=['col2','col1'])

asc_sorted_df = df.sort_index(axis=0)
desc_sorted_df = df.sort_index(axis=0, ascending=False)
print('升序排序:')
print(asc_sorted_df)
print('\n')
print('降序排序:')
print(desc_sorted_df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
升序排序:
col2 col1
0 0.509889 -0.863155
1 0.717766 -0.865105
2 -1.465073 0.501439
3 -0.891743 -0.772799
4 -1.086885 0.241132
5 0.104040 1.564791
6 -1.271712 0.074772
7 0.772256 -0.880302
8 -0.361009 -0.391085
9 0.255575 0.506795


降序排序:
col2 col1
9 0.255575 0.506795
8 -0.361009 -0.391085
7 0.772256 -0.880302
6 -1.271712 0.074772
5 0.104040 1.564791
4 -1.086885 0.241132
3 -0.891743 -0.772799
2 -1.465073 0.501439
1 0.717766 -0.865105
0 0.509889 -0.863155

我们再看一下按列排序的情况

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randn(10,2),index=[1,4,6,2,3,5,9,8,0,7],columns=['col2','col1'])

asc_sorted_df = df.sort_index(axis=1)
desc_sorted_df = df.sort_index(axis=1, ascending=False)
print('升序排序:')
print(asc_sorted_df)
print('\n')
print('降序排序:')
print(desc_sorted_df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
升序排序:
col1 col2
1 -0.482662 1.857978
4 1.008759 0.157484
6 0.404661 0.084503
2 -0.350703 0.340782
3 -0.577663 -0.453446
5 0.136501 -1.253516
9 0.893234 -0.239606
8 1.246226 -0.945827
0 0.322587 -2.122998
7 -2.055323 0.208008


降序排序:
col2 col1
1 1.857978 -0.482662
4 0.157484 1.008759
6 0.084503 0.404661
2 0.340782 -0.350703
3 -0.453446 -0.577663
5 -1.253516 0.136501
9 -0.239606 0.893234
8 -0.945827 1.246226
0 -2.122998 0.322587
7 0.208008 -2.055323

3.6.2 DataFrame.sort_values()

sort_values()是按值排序的方法. 它接受一个by参数, 它将使用要与其排序值的DataFrame的列名称.

1
2
3
4
5
6
7
8
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randn(10,2),index=[1,4,6,2,3,5,9,8,0,7],columns=['col2','col1'])

sorted_df = df.sort_index(axis=1).sort_values(by=['col1','col2'],kind='mergesort',ascending=False)
print('排序结果是:')
print(sorted_df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
排序结果是:
col1 col2
2 1.643330 0.634745
7 1.424638 -0.712359
8 1.091883 0.342883
4 1.047769 -0.215468
5 0.432504 -3.370203
9 0.134519 0.829283
6 -0.001631 -1.385783
3 -0.775563 0.302277
0 -1.370623 -0.091588
1 -1.941154 -0.107553

3.7 Date Function

日期功能扩展了时间序列, 在财务数据分析中起主要作用. 在处理日期数据的同时, 我们经常会遇到以下情况:

  • 生成日期序列
  • 将日期序列转换为不同的频率

3.7.1 pandas.date_range()

通过指定周期和频率, 使用date.range()函数就可以创建日期序列. 默认情况下, 范围的频率是天.

1
2
3
4
import pandas as pd

datelist = pd.date_range('2020/11/21',periods=5)
print(datelist)

输出结果是:

1
2
3
DatetimeIndex(['2020-11-21', '2020-11-22', '2020-11-23', '2020-11-24',
'2020-11-25'],
dtype='datetime64[ns]', freq='D')

我们可以更改日期频率为月

1
2
3
4
import pandas as pd

datelist = pd.date_range('2020/11/21',periods=5, freq='M')
print(datelist)

输出结果是:

1
2
3
DatetimeIndex(['2020-11-30', '2020-12-31', '2021-01-31', '2021-02-28',
'2021-03-31'],
dtype='datetime64[ns]', freq='M')

3.7.2 pandas.bdate_range()

bdate_range()用来表示商业日期范围, 不同于date_range(), 它不包括星期六和星期天.

1
2
3
4
5
6
import pandas as pd

start = pd.datetime(2020,8,21)
end = pd.datetime(2020,8,29)
datelist = pd.bdate_range(start,end)
print(datelist)

输出结果是:

1
2
3
DatetimeIndex(['2020-08-21', '2020-08-24', '2020-08-25', '2020-08-26',
'2020-08-27', '2020-08-28'],
dtype='datetime64[ns]', freq='B')

参数 freq 可以有以下选择:

image-20200821192822274

3.7.3 pandas.Timedelta()

时间差(Timedelta)是时间上的差异, 以不同的单位来表示. 例如:日, 小时, 分钟, 秒. 它们可以是正值, 也可以是负值.
可以使用各种参数创建Timedelta对象, 如下所示:

1
2
3
4
import pandas as pd

timediff = pd.Timedelta('2 days 2 hours 15 minues 30 seconds')
print(timediff)

输出结果是:

1
2 days 02:15:30

以在Series/DataFrames上执行运算操作, 并通过在 datetime64 [ns] 系列或在时间戳上减法操作来构造 timedelta64 [ns] 系列.

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd

s = pd.Series(pd.date_range('2012-1-1', periods=3, freq='D'))
tdiff = pd.Series([pd.Timedelta(days=i) for i in range(3)])
df = pd.DataFrame(dict(A=s,B=tdiff))
print('我们的数据是:')
print(df)
print('\n')

df['A+B'] = df['A'] + df['B']
df['A-B'] = df['A'] - df['B']
print('修改后的数据是:')
print(df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
我们的数据是:
A B
0 2012-01-01 0 days
1 2012-01-02 1 days
2 2012-01-03 2 days


修改后的数据是:
A B A+B A-B
0 2012-01-01 0 days 2012-01-01 2012-01-01
1 2012-01-02 1 days 2012-01-03 2012-01-01
2 2012-01-03 2 days 2012-01-05 2012-01-01

3.8 Categorical Data

分类数据 (Categorical Data) 用于表示统计学里有限且唯一性数据集, 例如描述个人信息的性别一般就男和女两个数据常用’m’和’f’来描述, 有时也能对应编码映射为0和1. 血型A、B、O和AB型等选择可以映射为0、1、2、3这四个数字分别代表各个血型. Pandas 里直接就有 categorical 类型, 可以有效地对数据进行分组进行相应的汇总统计工作.

3.8.1 Object Creation

分类对象可以通过多种方式创建:

  1. 通过在pandas对象创建中将dtype指定为“category”.

    1
    2
    3
    4
    import pandas as pd

    s = pd.Series(['a','b','c','d'], dtype='category')
    print(s)

    输出结果是:

    1
    2
    3
    4
    5
    6
    0    a
    1 b
    2 c
    3 d
    dtype: category
    Categories (4, object): [a, b, c, d]
  2. 使用标准 Pandas 分类构造函数: pandas.Categorical(). 我们可以创建一个类别对象, 语法如下:

    1
    2
    3
    4
    5
    6
    pandas.Categorical(values, categories, ordered)

    # 参数说明
    # values: 传入的数据
    # categories: 数据的分类, 在类别中不存在的任何值将被视为NaN
    # ordered: bool, 是否进行逻辑排序, 按 categories 里面的顺序从小到达

    看个例子

    1
    2
    3
    4
    import pandas as pd

    cat = pd.Categorical(values=['a','b','c','d','e'],categories=['d','b','c','a'],ordered=True)
    print(cat)

    输出结果是:

    1
    2
    [a, b, c, d, NaN]
    Categories (4, object): [d < b < c < a]

    3.8.2 Reading Categorical Data

我们可以对分类数据使用 .describe() , 得到各类数据出现的次数和频率

1
2
3
4
5
import pandas as pd
import numpy as np

cat = pd.Categorical(['a','c','a','b','c','b','a'],categories=['a','b','c'],ordered=False)
cat.describe()

输出结果是:

image-20200823164719200

我们可以使用 .categories 访问对象的类别, 以及使用 .ordered 看数据是否有排序.

我们还能使用 Categorical.categories 来修改对象的类别

1
2
3
4
5
6
7
8
9
10
import pandas as pd

cat = pd.Categorical(['a','c','a','b','c','b','a'],categories=['a','b','c'],ordered=False)
print('我们的原数据是:')
print(cat)
print('\n')

print('修改数据类别')
cat.categories = ['a','c','e'] # 原来的 b 变成 c, c 变成 e
print(cat)

输出结果是

1
2
3
4
5
6
7
8
我们的原数据是:
[a, c, a, b, c, b, a]
Categories (3, object): [a, b, c]


修改数据类别
[a, e, a, c, e, c, a]
Categories (3, object): [a, c, e]

3.8.3 Categorical Data Operations

  1. Adding Categories

    使用Categorical.add.categories()方法, 可以追加新的类别.

    1
    2
    3
    4
    5
    import pandas as pd

    s = pd.Series(['a','b','c','a'],dtype='category')
    s = s.cat.add_categories(['d'])
    print(s.cat.categories)

    输出结果是:

    1
    Index(['a', 'b', 'c', 'd'], dtype='object')
  2. Removing Categories

    使用Categorical.remove_categories()方法, 可以删除不需要的类别.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import pandas as pd

    s = pd.Series(['a','b','c','a'],dtype='category')
    print('我们原数据是:')
    print(s)
    print('\n')

    print('移除类别后:')
    print(s.cat.remove_categories(['a']))

    输出结果是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    我们原数据是:
    0 a
    1 b
    2 c
    3 a
    dtype: category
    Categories (3, object): [a, b, c]


    移除类别后:
    0 NaN
    1 b
    2 c
    3 NaN
    dtype: category
    Categories (2, object): [b, c]

    Topic 4 Statistics Functions

函数 说明
count() 每一列或行的非空数据的数量
sum() 每一列或行的所有值之和
mean() 每一列或行的所有值的平均值
median() 每一列或行的所有值的中位数
mode() 每一列或行中出现次数最多的数据
std() 每一列或行的标准差
min() 每一列或行的所有值中的最小值
max() 每一列或行的所有值中的最大值
abs() 取绝对值, 只适用于所有数值元素.
prod() 每一列或行的数组元素的乘积
cumsum() 累计总和
cumprod() 累计乘积, 只适用于所有数值元素.
var() 方差
skew() 偏差
kurt() 峰度
quantile() 分位数
cov() 协方差
corr() 相关系数

4.1 DataFrame.count()

每一列非空数据的数量, 用法如下:

1
2
3
4
5
DataFrame.count(self, axis=0, numeric_only=False)

# 参数说明
# axis: 0 竖直, 1 水平
# numeric_only: 是否只计算数据类型为数值的数据

看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd

d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack',
'Lee','David','Gasper','Betina','Andres']),
'Age':pd.Series([25,26,25,23,30,29,23,34,40,30,51,46]),
'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8,3.78,2.98,4.80,4.10,3.65])}

df = pd.DataFrame(d)

print('我们的数据是:')
print(df)
print('\n')

print('非空行的数量:')
print(df.count())

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
我们的数据是:
Name Age Rating
0 Tom 25 4.23
1 James 26 3.24
2 Ricky 25 3.98
3 Vin 23 2.56
4 Steve 30 3.20
5 Minsu 29 4.60
6 Jack 23 3.80
7 Lee 34 3.78
8 David 40 2.98
9 Gasper 30 4.80
10 Betina 51 4.10
11 Andres 46 3.65


非空行的数量:
Name 12
Age 12
Rating 12
dtype: int64

4.2 DataFrame.sum()

返回行或列的数据之和, 用法如下:

1
2
3
4
5
6
7
DataFrame.sum(self,axis=None,skipna=None,numeric_only=None,min_count=0)

# 参数说明
# axis: 指明沿什么轴计算, 可看我的 numpy 笔记的 Topic 3. 0 是竖直, 1 是水平
# skipna: 是否跳过空数据, 默认为 True
# numeric_only: 是否只计算 int 或 float 的和, 默认为 False
# min_count: 默认为 0, 若该列的有效数据量低于这个值, 则不计算该列的和

看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd

d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack',
'Lee','David','Gasper','Betina','Andres']),
'Age':pd.Series([25,26,25,23,30,29,23,34,40,30,51,46]),
'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8,3.78,2.98,4.80,4.10,3.65])}

df = pd.DataFrame(d)

print('我们的数据是:')
print(df)
print('\n')

print('数据类型是数值的列之和:')
print(df.sum(numeric_only=True,axis=0))

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
我们的数据是:
Name Age Rating
0 Tom 25 4.23
1 James 26 3.24
2 Ricky 25 3.98
3 Vin 23 2.56
4 Steve 30 3.20
5 Minsu 29 4.60
6 Jack 23 3.80
7 Lee 34 3.78
8 David 40 2.98
9 Gasper 30 4.80
10 Betina 51 4.10
11 Andres 46 3.65


数据类型是数值的列之和:
Age 382.00
Rating 44.92
dtype: float64

4.3 DataFrame.mean()

返回数据的平均值, 用法如下:

1
DataFrame.mean(axis=None,skipna=None,numeric_only=None)

DataFrame.median(), DataFrame.std(), DataFrame.min() , DataFrame.max() 以及 DataFrame.prod() …. 的用法与之相同, 我就不再赘述了.

看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd

d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack',
'Lee','David','Gasper','Betina','Andres']),
'Age':pd.Series([25,26,25,23,30,29,23,34,40,30,51,46]),
'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8,3.78,2.98,4.80,4.10,3.65])}

df = pd.DataFrame(d)

print('我们的数据是:')
print(df)
print('\n')

print('每列的平均值是:')
print(df.mean())

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
我们的数据是:
Name Age Rating
0 Tom 25 4.23
1 James 26 3.24
2 Ricky 25 3.98
3 Vin 23 2.56
4 Steve 30 3.20
5 Minsu 29 4.60
6 Jack 23 3.80
7 Lee 34 3.78
8 David 40 2.98
9 Gasper 30 4.80
10 Betina 51 4.10
11 Andres 46 3.65


每列的平均值是:
Age 31.833333
Rating 3.743333
dtype: float64

4.4 DataFrame.mode()

每一列或行中出现次数最多的数据, 用法如下:

1
2
3
4
5
6
DataFrame.mode(self, axis=0, numeric_only=False, dropna=True)

# 参数说明
# axis: 0 获取各列的 mode, 1 获取各行的 mode
# numeric_only: 若为 True, 那么只适用于数字列
# dropna: 是否考虑 na 值

看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
import numpy as np

df = pd.DataFrame([('bird', 2, 2),
('mammal', 4, np.nan),
('arthropod', 8, 0),
('bird', 2, np.nan)],
index=('falcon', 'horse', 'spider', 'ostrich'),
columns=('species', 'legs', 'wings'))

print('我们的数据是:')
print(df)
print('\n')

print('dropna 情况下, 每列的 mode:')
print(df.mode())
print('\n')

print('不 dropna 的情况下, 每列的 mode:')
print(df.mode(dropna=False))

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
我们的数据是:
species legs wings
falcon bird 2 2.0
horse mammal 4 NaN
spider arthropod 8 0.0
ostrich bird 2 NaN


dropna 情况下, 每列的 mode:
species legs wings
0 bird 2.0 0.0
1 NaN NaN 2.0


不 dropna 的情况下, 每列的 mode:
species legs wings
0 bird 2 NaN

4.5 DataFrame.abs()

返回一个包含每个元素绝对值的Series/DataFrame. 此函数只适用于所有数值元素.

看个列子:

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
import pandas as pd

df = pd.DataFrame({'a': [4, 5, 6, 7],'b': [10, 20, 30, 40],'c': [100, 50, -30, -50]})

print('我们的数据是:')
print(df)
print('\n')

print('取绝对值之后的数据:')
print(df.abs())

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
我们的数据是:
a b c
0 4 10 100
1 5 20 50
2 6 30 -30
3 7 40 -50


取绝对值之后的数据:
a b c
0 4 10 100
1 5 20 50
2 6 30 30
3 7 40 50

4.6 DataFrame.cumsum() & DataFrame.cumprod()

返回DataFrame或Series轴上的累计和/积

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import pandas as pd

df = pd.DataFrame({'a': [4, 5, 6, 7],'b': [10, 20, 30, 40],'c': [100, 50, -30, -50]})

print('我们的数据是:')
print(df)
print('\n')

print('沿轴 0 累计的和:')
print(df.cumsum())
print('\n')

print('沿轴 0 累计的积:')
print(df.cumprod())
print('\n')

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
我们的数据是:
a b c
0 4 10 100
1 5 20 50
2 6 30 -30
3 7 40 -50


沿轴 0 累计的和:
a b c
0 4 10 100
1 9 30 150
2 15 60 120
3 22 100 70


沿轴 0 累计的积:
a b c
0 4 10 100
1 20 200 5000
2 120 6000 -150000
3 840 240000 7500000

4.7 DataFrame.describe()

描述性统计归纳总计

1
2
3
4
5
6
7
8
9
10
import pandas as pd

d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack',
'Lee','David','Gasper','Betina','Andres']),
'Age':pd.Series([25,26,25,23,30,29,23,34,40,30,51,46]),
'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8,3.78,2.98,4.80,4.10,3.65])}

df = pd.DataFrame(d)

print(df.describe())

输出结果是:

1
2
3
4
5
6
7
8
9
             Age     Rating
count 12.000000 12.000000
mean 31.833333 3.743333
std 9.232682 0.661628
min 23.000000 2.560000
25% 25.000000 3.230000
50% 29.500000 3.790000
75% 35.500000 4.132500
max 51.000000 4.800000

4.8 DataFrame.pct_change()

Series, DatFrames和Panel都有pct_change()函数, 此函数将每个元素与其前一个元素进行比较, 并计算变化百分比.

1
2
3
4
5
6
7
import pandas as pd
import numpy as np
s = pd.Series([1,2,3,4,5,4])
print (s.pct_change())

df = pd.DataFrame(np.random.randn(5, 2))
print (df.pct_change())

输出结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
0         NaN
1 1.000000
2 0.500000
3 0.333333
4 0.250000
5 -0.200000
dtype: float64
0 1
0 NaN NaN
1 0.384032 -0.996141
2 -1.736876 679.793981
3 1.063848 -0.441469
4 -1.060066 -1.576158

4.9 DataFrame.sample()

从对象轴返回随机的项目样本, 用法如下:

1
2
3
4
5
6
7
8
9
DataFrame.sample(n=None,axis=None,frac=None,replace=False,weights=None,random_state=None)

# 参数说明
# n: 想要取得的样本数, 不能和 frac 一起使用, 若 frac=None, 则 n 默认值为 1
# axis: 沿什么轴抽样
# frac: 取百分之几的数据, 不能与 n 一起使用
# replace: bool, 默认为 False. 允许或不允许对同一行进行多次抽样
# weights: 默认的 None 将导致相等的概率权重.
# random_state: 实现重现性

看个例子:

选取数据的 200% 作为样本, 且允许随机抽样

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
import pandas as pd

df = pd.DataFrame({'num_legs': [2, 4, 8, 0],
'num_wings': [2, 0, 0, 0],
'num_specimen_seen': [10, 2, 1, 8]},
index=['falcon', 'dog', 'spider', 'fish'])

sample = df.sample(frac=2, replace=True, random_state=1)
print('我们的样本是:')
print(sample)

输出结果是:

1
2
3
4
5
6
7
8
9
10
我们的样本是:
num_legs num_wings num_specimen_seen
dog 4 0 2
fish 0 0 8
falcon 2 2 10
falcon 2 2 10
fish 0 0 8
dog 4 0 2
fish 0 0 8
dog 4 0 2

使用DataFrame列作为权重. num_specimen_seen列中值较大的行更可能被采样.

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
import pandas as pd

df = pd.DataFrame({'num_legs': [2, 4, 8, 0],
'num_wings': [2, 0, 0, 0],
'num_specimen_seen': [10, 2, 1, 8]},
index=['falcon', 'dog', 'spider', 'fish'])

sample = df.sample(frac=2, replace=True, weights='num_specimen_seen', random_state=1)
print('我们的样本是:')
print(sample)

输出结果是:

1
2
3
4
5
6
7
8
9
10
我们的样本是:
num_legs num_wings num_specimen_seen
falcon 2 2 10
fish 0 0 8
falcon 2 2 10
falcon 2 2 10
falcon 2 2 10
falcon 2 2 10
falcon 2 2 10
falcon 2 2 10

Topic 5 Data Cleaning

我们先构造一个包含确实数据的 DataFrame:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
import numpy as np

data = np.arange(10,38).reshape(7,4)
rows = 'cake make fake sake wake lake take'.split()
cols = list('abcd')
df = pd.DataFrame(data=data, index=rows, columns=cols)
df['e'] = np.nan
df['f'] = np.nan
df.at['make','e'] = 100
df.at['wake','e'] = 300
df.loc['jake'] = np.nan
df.at['jake','c'] = 200

print('我们的数据是:')
print(df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
我们的数据是:
a b c d e f
cake 10.0 11.0 12.0 13.0 NaN NaN
make 14.0 15.0 16.0 17.0 100.0 NaN
fake 18.0 19.0 20.0 21.0 NaN NaN
sake 22.0 23.0 24.0 25.0 NaN NaN
wake 26.0 27.0 28.0 29.0 300.0 NaN
lake 30.0 31.0 32.0 33.0 NaN NaN
take 34.0 35.0 36.0 37.0 NaN NaN
jake NaN NaN 200.0 NaN NaN NaN

然后, 我们看一下那些列有 NaN 数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
import numpy as np

data = np.arange(10,38).reshape(7,4)
rows = 'cake make fake sake wake lake take'.split()
cols = list('abcd')
df = pd.DataFrame(data=data, index=rows, columns=cols)
df['e'] = np.nan
df['f'] = np.nan
df.at['make','e'] = 100
df.at['wake','e'] = 300
df.loc['jake'] = np.nan
df.at['jake','c'] = 200

print('每一列含空数据的情况:')
print(df.isnull().sum())

输出结果是:

1
2
3
4
5
6
7
每一列含空数据的情况:
a 1
b 1
c 0
d 1
e 6
f 8

5.1 Deleting NaN Data

我们主要使用 dropna() 函数来删除 NaN 数据, 看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd
import numpy as np

data = np.arange(10,38).reshape(7,4)
rows = 'cake make fake sake wake lake take'.split()
cols = list('abcd')
df = pd.DataFrame(data=data, index=rows, columns=cols)
df['e'] = np.nan
df['f'] = np.nan
df.at['make','e'] = 100
df.at['wake','e'] = 300
df.loc['jake'] = np.nan
df.at['jake','c'] = 200

print('我们的数据是:')
print(df)
print('\n')


df2 = df.dropna()
print('删除含 NaN 的行之后的数据:')
print(df2)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
我们的数据是:
a b c d e f
cake 10.0 11.0 12.0 13.0 NaN NaN
make 14.0 15.0 16.0 17.0 100.0 NaN
fake 18.0 19.0 20.0 21.0 NaN NaN
sake 22.0 23.0 24.0 25.0 NaN NaN
wake 26.0 27.0 28.0 29.0 300.0 NaN
lake 30.0 31.0 32.0 33.0 NaN NaN
take 34.0 35.0 36.0 37.0 NaN NaN
jake NaN NaN 200.0 NaN NaN NaN


删除含 NaN 的行之后的数据:
Empty DataFrame
Columns: [a, b, c, d, e, f]
Index: []

所有数据都没有了… 这样不是很好, 我们设置 thresh 来设定删除阈值, 看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd
import numpy as np

data = np.arange(10,38).reshape(7,4)
rows = 'cake make fake sake wake lake take'.split()
cols = list('abcd')
df = pd.DataFrame(data=data, index=rows, columns=cols)
df['e'] = np.nan
df['f'] = np.nan
df.at['make','e'] = 100
df.at['wake','e'] = 300
df.loc['jake'] = np.nan
df.at['jake','c'] = 200

print('我们的数据是:')
print(df)
print('\n')


print('列上至少有两个非 NaN 的列留下:')
df2 = df.dropna(axis='columns', thresh=2)
print(df2)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
我们的数据是:
a b c d e f
cake 10.0 11.0 12.0 13.0 NaN NaN
make 14.0 15.0 16.0 17.0 100.0 NaN
fake 18.0 19.0 20.0 21.0 NaN NaN
sake 22.0 23.0 24.0 25.0 NaN NaN
wake 26.0 27.0 28.0 29.0 300.0 NaN
lake 30.0 31.0 32.0 33.0 NaN NaN
take 34.0 35.0 36.0 37.0 NaN NaN
jake NaN NaN 200.0 NaN NaN NaN


列上至少有两个非 NaN 的列留下:
a b c d e
cake 10.0 11.0 12.0 13.0 NaN
make 14.0 15.0 16.0 17.0 100.0
fake 18.0 19.0 20.0 21.0 NaN
sake 22.0 23.0 24.0 25.0 NaN
wake 26.0 27.0 28.0 29.0 300.0
lake 30.0 31.0 32.0 33.0 NaN
take 34.0 35.0 36.0 37.0 NaN
jake NaN NaN 200.0 NaN NaN

5.2 Filling NaN Data

我们主要是用 DataFrame.fillna() 函数对缺失值进行填充, 有这么几种方法:

  • 使用 0 (或任意值) 填充缺失值

    df.fillna(0)

  • 用一个字符串来代替缺失值

    df.fillna('missing')

  • 用前一个数据代替缺失值

    df.fillna(method='pad')

  • 用后一个数据替代缺失值, 我们可以设置 limit 参数来限制替代缺失值的次数

    df.fillna(method='bfill', limit=2)

  • 我们还可以使用描述性统计量来代替缺失值

    df.fillna(df.mean())

    我们还可以指定某一列的描述性统计量来填充所有缺失值

    df.fillna(df.mean()['e'])

5.3 Deleting Duplicated Data

我们可以首先使用 DataFrame.duplicated() 来查看 DataFrame 中是否存在重复的数据. 然后再使用 DataFrame.drop_duplicates() 来移除重复数据. 看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import pandas as pd

fruit = ["apple", "pearl", "watermelon"] * 4
price = [2.50, 3.00, 2.75] * 4
df = pd.DataFrame({"fruit": fruit, "price" : price})
print('我们的数据是:')
print(df)
print('\n')

print('查看数据重复情况:', df.duplicated().sum())
print(df.duplicated())
print('\n')

print('移除重复数据:')
print(df.drop_duplicates())

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
我们的数据是:
fruit price
0 apple 2.50
1 pearl 3.00
2 watermelon 2.75
3 apple 2.50
4 pearl 3.00
5 watermelon 2.75
6 apple 2.50
7 pearl 3.00
8 watermelon 2.75
9 apple 2.50
10 pearl 3.00
11 watermelon 2.75


查看数据重复情况: 9
0 False
1 False
2 False
3 True
4 True
5 True
6 True
7 True
8 True
9 True
10 True
11 True


移除重复数据:
fruit price
0 apple 2.50
1 pearl 3.00
2 watermelon 2.75

5.4 Transform Data

DataFrame 里的数据未必是原始数据, 例如采集时设定了一些协议, 1代表某某、2代表另一个事务或内容, 那么当开发者得到这些协议后的编码, 需要做一些数据上的变换, 以便真实的反映数据本身.

5.4.1 Series.map()

map() 是一个 Series 的函数,DataFrame结构中没有map(). map() 将一个自定义函数应用于 Series 结构中的每个元素(elements). 我们看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import numpy as np

df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
'key2' : ['one', 'two', 'one', 'two', 'one'],
'data1' : np.arange(5),
'data2' : np.arange(5,10)})
print('我们的数据是:')
print(df)
print('\n')

print('我们现在用map来对列 data1 改成保留小数点后三位')
df['data1'] = df['data1'].map(lambda x: '%.3f'%x)

print('用map把key1的a改成c,b改成d')
df['key1'] = df['key1'].map({'a':'c','b':'d'})
print('\n')
print('修改后的数据是:')
print(df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
我们的数据是:
key1 key2 data1 data2
0 a one 0 5
1 a two 1 6
2 b one 2 7
3 b two 3 8
4 a one 4 9


我们现在用map来对列 data1 改成保留小数点后三位
用map把key1的a改成c,b改成d


修改后的数据是:
key1 key2 data1 data2
0 c one 0.000 5
1 c two 1.000 6
2 d one 2.000 7
3 d two 3.000 8
4 c one 4.000 9

5.4.2 DataFrame.replace()

之前我们将的 fillna() 函数可以将NaN数据填充为0,这里的replace函数可以将数据替换成其他数据. replace函数的使用方式有很多, 可以一对一的替换也可一对多的替换数据. 用法如下:

1
2
3
4
5
6
7
8
DataFrame.replace(self, to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad')

# 参数说明
# to_replace: 将要被替换的值, 可以是 str, regex, dict 以及 list. 若是 dict, 那么 value 参数应该设置为 None.
# value: 用于替换 to_replace 中匹配到的值
# inplace: 是否修改原 DataFrame, 默认为 False, 也就是返回一个新的 DataFrame
# method: 要使用这个 to_replace 必须是标量, 而且 value 设置为 None. method 有以下几个选项: 'mad', 'bfill', 'ffill', 'None'
# limit: 向后或向前填充的数量

我们看一个正则表达式的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import pandas as pd
import numpy as np

df = pd.DataFrame({'A': ['bat', 'foo', 'bait'],
'B': ['abc', 'bar', 'xyz']})
print('我们的数据是:')
print(df)
print('\n')

print('替换后的数据是:')
df1 = df.replace(to_replace=r'^ba.$',value='new',regex=True)
print(df1)

# 下面这三种方式也是一样的效果
df1 = df.replace(regex=r'^ba.$', value='new')
df1 = df.replace(regex={r'^ba.$': 'new', 'foo': 'xyz'})
df1 = df.replace(regex=[r'^ba.$', 'foo'], value='new')

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
我们的数据是:
A B
0 bat abc
1 foo bar
2 bait xyz


替换后的数据是:
A B
0 new abc
1 foo new
2 bait xyz

5.4.3 DataFrame.apply()

apply() 将一个函数作用于DataFrame中的每个行或者列, 看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
import numpy as np

df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
'key2' : ['one', 'two', 'one', 'two', 'one'],
'data1' : np.arange(5),
'data2' : np.arange(5,10)})
print('我们的数据是:')
print(df)
print('\n')

print('使用 apply() 求每列的和')
print('使用 apply() 对列 data1, data2 进行相加')

df.loc['total'] = df[['data1','data2']].apply(lambda x: x.sum(), axis=0)
df['total'] = df[['data1','data2']].apply(lambda x: x.sum(), axis=1)
print('\n')

print('修改之后的数据:')
print(df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
我们的数据是:
key1 key2 data1 data2
0 a one 0 5
1 a two 1 6
2 b one 2 7
3 b two 3 8
4 a one 4 9


使用 apply() 求每列的和
使用 apply() 对列 data1, data2 进行相加


修改之后的数据:
key1 key2 data1 data2 total
0 a one 0.0 5.0 5.0
1 a two 1.0 6.0 7.0
2 b one 2.0 7.0 9.0
3 b two 3.0 8.0 11.0
4 a one 4.0 9.0 13.0
total NaN NaN 10.0 35.0 45.0

5.4.5 DataFrame.applymap()

将函数作用于 DataFrame 中的所有元素(elements), 看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import pandas as pd
import numpy as np

df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
'key2' : ['one', 'two', 'one', 'two', 'one'],
'data1' : np.arange(5),
'data2' : np.arange(5,10)})
print('我们的数据是:')
print(df)
print('\n')

def addA(x):
return 'A' + str(x)

df2 = df.applymap(addA)
print('修改后的数据是:')
print(df2)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
我们的数据是:
key1 key2 data1 data2
0 a one 0 5
1 a two 1 6
2 b one 2 7
3 b two 3 8
4 a one 4 9


修改后的数据是:
key1 key2 data1 data2
0 Aa Aone A0 A5
1 Aa Atwo A1 A6
2 Ab Aone A2 A7
3 Ab Atwo A3 A8
4 Aa Aone A4 A9

5.5 Data Concatenation

这里主要有两个函数:

  • DataFrame.concat()
  • DataFrame.merge()

5.5.1 pandas.concat()

concat() 函数的用法如下:

1
2
3
4
5
6
7
8
9
pandas.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None, names=None, verify_integrity=False)

# 参数说明
# objs: series, dataframe或者是panel构成的序列list
# axis: 需要合并链接的轴,0是行, 1是列
# join: 连接方式 inner(交集) 或者 outer(并集)
# keys: 用于指明数据分别来自哪个 DataFrame
# join_axes: 以哪张表的行 index 为基准
# ignore_index: 如果两个表的index都没有实际含义, 使用ignore_index参数. 合并的两个表就根据列字段对齐, 然后合并, 最后再重新整理一个新的index

我们竖直拼接的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import numpy as np
import pandas as pd

df1 = pd.DataFrame({'A':['A0','A1','A2','A3'],
'B':['B0','B1','B2','B3'],
'C':['C0','C1','C2','C3'],
'D':['D0','D1','D2','D3']}, index=[0,1,2,3])

df2 = pd.DataFrame({'A':['A4','A5','A6','A7'],
'B':['B4','B5','B6','B7'],
'C':['C4','C5','C6','C7'],
'D':['D4','D5','D6','D7']}, index=[4,5,6,7])

df3 = pd.DataFrame({'A':['A8','A9','A10','A11'],
'B':['B8','B9','B10','B11'],
'C':['C8','C9','C10','C11'],
'D':['D8','D9','D10','D11']}, index=[8,9,10,11])

print('我们的三个 DataFrame 分别是:')
print(df1)
print()
print(df2)
print()
print(df3)

print('\n')
print('我们竖直拼接三个 DataFrame, 并指明其来源:')
print(pd.concat([df1,df2,df3], axis=0, keys=['df1','df2','df3']))

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
我们的三个 DataFrame 分别是:
A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3

A B C D
4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7

A B C D
8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11


我们竖直拼接三个 DataFrame, 并指明其来源:
A B C D
df1 0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
df2 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
df3 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11

我们看一个水平拼接的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import numpy as np
import pandas as pd

df1 = pd.DataFrame({'A':['A0','A1','A2','A3'],
'B':['B0','B1','B2','B3'],
'C':['C0','C1','C2','C3'],
'D':['D0','D1','D2','D3']}, index=[0,1,2,3])

df2 = pd.DataFrame({'A1':['A4','A5','A6','A7'],
'B2':['B4','B5','B6','B7'],
'C2':['C4','C5','C6','C7'],
'D2':['D4','D5','D6','D7']}, index=[0,1,2,3])

df3 = pd.DataFrame({'A3':['A8','A9','A10','A11'],
'B3':['B8','B9','B10','B11'],
'C3':['C8','C9','C10','C11'],
'D3':['D8','D9','D10','D11']}, index=[0,1,2,3])

print('我们的三个 DataFrame 分别是:')
print(df1)
print()
print(df2)
print()
print(df3)

print('\n')
print('我们水平拼接三个 DataFrame, 并指明其来源:')
print(pd.concat([df1,df2,df3], axis=1, keys=['df1','df2','df3']))

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
我们的三个 DataFrame 分别是:
A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3

A1 B2 C2 D2
0 A4 B4 C4 D4
1 A5 B5 C5 D5
2 A6 B6 C6 D6
3 A7 B7 C7 D7

A3 B3 C3 D3
0 A8 B8 C8 D8
1 A9 B9 C9 D9
2 A10 B10 C10 D10
3 A11 B11 C11 D11


我们水平拼接三个 DataFrame, 并指明其来源:
df1 df2 df3
A B C D A1 B2 C2 D2 A3 B3 C3 D3
0 A0 B0 C0 D0 A4 B4 C4 D4 A8 B8 C8 D8
1 A1 B1 C1 D1 A5 B5 C5 D5 A9 B9 C9 D9
2 A2 B2 C2 D2 A6 B6 C6 D6 A10 B10 C10 D10
3 A3 B3 C3 D3 A7 B7 C7 D7 A11 B11 C11 D11

5.5.2 pandas.merge()

concat函数可以实现内外连接, 而pandas的merge函数可以真正实现数据库的内外连接, 且外连接还可以有左右连接的特性. 用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
pandas.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=('_x','_y'), copy=True, indicator=False)


# 参数说明
# left: 拼接的左侧DataFrame对象
# right: 拼接的右侧DataFrame对象
# on: 要加入的列或索引级别名称. 必须在左侧和右侧DataFrame对象中找到. 如果未传递且left_index和right_index为False, 则DataFrame中的列的交集将被推断为连接键.
# left_on: 左侧DataFrame中的列或索引级别用作键.
# right_on: 右侧DataFrame中的列或索引级别用作键.
# left_index: 如果为True,则使用左侧DataFrame中的索引(行标签)作为其连接键.
# right_index: 与left_index功能相似.
# how: One of 'left', 'right', 'outer', 'inner'. 默认inner. inner是取交集,outer取并集.
# copy: 始终从传递的DataFrame对象复制数据 (默认为True), 即使不需要重建索引也是如此.

我们看一个简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd

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']})
result = pd.merge(left, right, on='key')
print('左表是:')
print(left)
print('\n')

print('右表示:')
print(right)
print('\n')

print('拼接结果是:')
print(result)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
左表是:
key A B
0 K0 A0 B0
1 K1 A1 B1
2 K2 A2 B2
3 K3 A3 B3


右表是:
key C D
0 K0 C0 D0
1 K1 C1 D1
2 K2 C2 D2
3 K3 C3 D3


拼接结果是:
key A B C D
0 K0 A0 B0 C0 D0
1 K1 A1 B1 C1 D1
2 K2 A2 B2 C2 D2
3 K3 A3 B3 C3 D3

传入的 on 也可以是列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd

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'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']})
result = pd.merge(left, right, on=['key1','key2'])
print('左表是:')
print(left)
print('\n')

print('右表是:')
print(right)
print('\n')

print('拼接结果是:')
print(result)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
左表是:
key1 key2 A B
0 K0 K0 A0 B0
1 K0 K1 A1 B1
2 K1 K0 A2 B2
3 K2 K1 A3 B3


右表是:
key1 key2 C D
0 K0 K0 C0 D0
1 K1 K0 C1 D1
2 K1 K0 C2 D2
3 K2 K0 C3 D3


拼接结果是:
key1 key2 A B C D
0 K0 K0 A0 B0 C0 D0
1 K1 K0 A2 B2 C1 D1
2 K1 K0 A2 B2 C2 D2

左外连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd

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'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']})
result = pd.merge(left, right, how='left', on=['key1','key2'])
print('左表是:')
print(left)
print('\n')

print('右表是:')
print(right)
print('\n')

print('拼接结果是:')
print(result)

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
左表是:
key1 key2 A B
0 K0 K0 A0 B0
1 K0 K1 A1 B1
2 K1 K0 A2 B2
3 K2 K1 A3 B3


右表是:
key1 key2 C D
0 K0 K0 C0 D0
1 K1 K0 C1 D1
2 K1 K0 C2 D2
3 K2 K0 C3 D3


拼接结果是:
key1 key2 A B C D
0 K0 K0 A0 B0 C0 D0
1 K0 K1 A1 B1 NaN NaN
2 K1 K0 A2 B2 C1 D1
3 K1 K0 A2 B2 C2 D2
4 K2 K1 A3 B3 NaN NaN

5.6 Reforming Data

5.6.1 DataFrame.pivot()

返回按给定索引/列以及制定的列值的重新构造的 pivot table. 如果作为 columns 的列具有重复值, 那么在使用 pivot 函数的时候就会报错, 此时我们需要使用DataFrame.pivot_table.

DataFrame.pivot() 的用法如下:

1
2
3
4
5
6
DataFrame.pivot(self, index=None, columns=None, values=None)

# 参数说明
# index: 用于制作新 frame 索引的列. 如果为None, 则使用现有索引.
# columns: 用于制作新 frame columns的列.
# values: 用于填充新frame值的列. 如果未指定, 将使用所有剩余的列, 并且结果将具有按层次结构索引的列.

看个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd
import numpy as np

df = pd.DataFrame({'foo': ['one', 'one', 'one', 'two', 'two',
'two'],
'bar': ['A', 'B', 'C', 'A', 'B', 'C'],
'baz': [1, 2, 3, 4, 5, 6],
'zoo': ['x', 'y', 'z', 'q', 'w', 't']})

print('我们的数据是:')
print(df)
print('\n')

print('使用 pivot 函数:')
print(df.pivot(index='foo', columns='bar'))

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
我们的数据是:
foo bar baz zoo
0 one A 1 x
1 one B 2 y
2 one C 3 z
3 two A 4 q
4 two B 5 w
5 two C 6 t


使用 pivot 函数:
baz zoo
bar A B C A B C
foo
one 1 2 3 x y z
two 4 5 6 q w t

5.6.2 DataFrame.pivot_table()

pivot 相比,该方法可以汇总多个重复条目的数据. 我们可以用均值、中位数或者其他汇总函数来计算重复条目的数值. pivot_table 方法需要传递一个新的参数 aggfunc, 该参数用于指明转换时所需的汇总函数. 我们看个图解:

image-20200820012507360

该函数的用法如下

1
2
3
4
5
6
7
8
9
DataFrame.pivot_table(self, index=None, columns=None, values=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False)

# 参数说明
# index: 用于制作新 pivot table 索引的列. 如果为None, 则使用现有索引.
# columns: 用于制作新 pivot table columns的列.
# values: 要汇总的列
# aggfunc: 如何处理重复数据
# fill_value: 替换缺失值
# margins: 添加行/列小计和总计

我们来看一个 NBA 的例子, 先读取数据

1
2
3
4
5
import pandas as pd
import numpy as np

df = pd.read_csv('James_Harden.csv',encoding='utf-8')
df.head()

输出结果是:

image-20200820190107889

然后我们看一下哈登对阵每个队伍的情况

1
df.pivot_table(index=u'对手').head()

输出结果是:

image-20200820190455915

让我们继续深入, 不同对手以及主客场情况下的得分概况

1
df.pivot_table(index=[u'对手',u'主客场'])

输出结果是:

image-20200820190654432

看完上面几个操作, Index就是层次字段, 要通过透视表获取什么信息就按照相应的顺序设置字段,所以在进行pivot之前你也需要足够了解你的数据.

当我们未设置 aggfunc 时, 它默认 aggfunc='mean' 计算均值. 我们还想要获得james harden在主客场和不同胜负情况下的总得分、总篮板、总助攻概况

1
df.pivot_table(index=[u'主客场',u'胜负'],values=[u'得分',u'助攻',u'篮板'],aggfunc=[np.sum,np.mean])

输出结果是:

image-20200820191134830

Columns类似Index可以设置列层次字段, 它不是一个必要参数, 作为一种分割数据的可选方式.

1
df.pivot_table(index=[u'主客场'],columns=[u'对手'],values=[u'得分'],aggfunc=[np.sum],fill_value=0,margins=1)

输出结果是:

image-20200820191513716

最后看一个综合的例子

1
df.pivot_table(index=[u'对手',u'胜负'],columns=[u'主客场'],values=[u'得分',u'助攻',u'篮板'],aggfunc=[np.mean],fill_value=0).head()

输出结果是:

image-20200820191913922

5.7 Aggregating Data

5.7.1 DataFrame.groupby()

在SQL语言里有group by功能,在Pandas里有groupby函数与之功能相对应. DataFrame数据对象经groupby()之后返回的结果是一个 DataFrameGroupBy 对象, 而不是一个 DataFrame 或者 Series 对象, 所以, 它们中的一些方法或者函数是无法直接调用的, 需要按照 GroupBy 对象中具有的函数和方法进行调用.

  • ngroups 反应的是分组的个数
  • groups 类似 dict 结构
  • size() 则是可以返回所有分组的数据个数.
  • count() 可以统计分组后各列数据项个数
  • get_group() 可以返回指定组的数据信息
  • discribe() 可以返回分组后的数据的统计数据

我们创建一个 DataFrame

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
import pandas as pd

name = ['Alen','Bob','Cidy','Daniel','Ellen','Frankie','Gate','Hebe']
gender = ['Male','Male','Female','Male','Female','Male','Male','Female']
age = [18,19,18,20,17,21,20,22]
score = [80,90,93,87,96,100,88,98]

df = pd.DataFrame(data={'Name':name,'Gender':gender,'Age':age,'Score':score})
print('我们的数据是:')
print(df)

输出结果是:

1
2
3
4
5
6
7
8
9
10
我们的数据是:
Name Gender Age Score
0 Alen Male 18 80
1 Bob Male 19 90
2 Cidy Female 18 93
3 Daniel Male 20 87
4 Ellen Female 17 96
5 Frankie Male 21 100
6 Gate Male 20 88
7 Hebe Female 22 98

我们使用 groupby() 函数

1
2
3
grouped = df.groupby('Gender')
print(type(grouped))
print(grouped)

输出结果是:

1
2
<class 'pandas.core.groupby.generic.DataFrameGroupBy'>
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x7fb650d31490>

分组时, 不仅仅可以指定一个列名, 也可以指定多个列名

1
2
3
4
5
6
grouped = df.groupby('Gender')
grouped_muti = df.groupby(['Gender', 'Age'])

print(grouped.size())
print('\n')
print(grouped_muti.size())

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Gender
Female 3
Male 5
dtype: int64


Gender Age
Female 17 1
18 1
22 1
Male 18 1
19 1
20 2
21 1
dtype: int64

指定多个列名个单个列名后的区别在于, 分组的索引 (index) 将一个是单个主键, 另一个则是一个元组的形式

1
2
3
4
5
6
a = grouped.get_group('Female')
b = grouped_muti.get_group(('Female',17))

print(a)
print('\n')
print(b)

输出结果是:

1
2
3
4
5
6
7
8
	Name  Age  Score
2 Cidy 18 93
4 Ellen 17 96
7 Hebe 22 98


Name Gender Age Score
4 Ellen Female 17 96

注: 通过调用get_group()函数可以返回一个按照分组得到的DataFrame对象, 所以接下来的使用就可以按照·DataFrame·对象来使用. 如果想让这个DataFrame对象的索引重新定义可以通过:

1
print(grouped.get_group('Female').reset_index())

输出结果是:

1
2
3
4
   index   Name  Age  Score
0 2 Cidy 18 93
1 4 Ellen 17 96
2 7 Hebe 22 98

5.7.2 DataFrame.agg()

在对数据进行分组之后, 可以对分组后的数据进行聚合处理统计. 用法如下:

1
2
3
4
5
6
7
8
9
DataFrame.agg(func, axis=0, *args, **kwargs)

# 参数说明
# func: 用于聚合数据的函数
# - 字符串函数名称
# - 函数
# - 函数列表
# - 列名称:函数或函数列表的字典
# axis: 0-->竖直, 1-->水平

看个例子, 求 age 和 score 的 mean 和 sum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import numpy as np
import pandas as pd

name = ['Alen','Bob','Cidy','Daniel','Ellen','Frankie','Gate','Hebe']
gender = ['Male','Male','Female','Male','Female','Male','Male','Female']
age = [18,19,18,20,17,21,20,22]
score = [80,90,93,87,96,100,88,98]

df = pd.DataFrame(data={'Name':name,'Gender':gender,'Age':age,'Score':score})
print('我们的数据是:')
print(df)
print('\n')

print('使用 agg 函数:')
print(df.agg({'Age':['sum','mean'],'Score':['sum','mean']}))
print('\n')

print('我们也可以使用自定义的 lambda 函数:')
get_max = lambda x: x.sort_values(ascending=False).iloc[0]
get_max.__name__ = 'get_max'
print(df.agg({'Age':[get_max],'Score':[get_max]}))

输出结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
我们的数据是:
Name Gender Age Score
0 Alen Male 18 80
1 Bob Male 19 90
2 Cidy Female 18 93
3 Daniel Male 20 87
4 Ellen Female 17 96
5 Frankie Male 21 100
6 Gate Male 20 88
7 Hebe Female 22 98


使用 agg 函数:
Age Score
sum 155.000 732.0
mean 19.375 91.5


我们也可以使用自定义的 lambda 函数:
Age Score
get_max 22 100

5.7.3 DataFrame.transform()

调用func自己产生一个改变值的和自己的相同的轴长度的DataFrame.

直接看例子:

假设我们有下面的销售数据, 有三个不同的 订单id (10001, 10005和10006), 每个 订单id又含有多个产品.

1
2
3
4
5
6
import pandas as pd
import numpy as np

df = pd.read_excel('sales_transactions.xlsx')
print('我们的数据是:')
print(df)

输出结果是:

image-20200821153859613

我们现在要求解的问题是: 每个订单中各个单品费用分布及占比. 例如订单10001总价$576.12,细分一下:

1
2
3
B1-20000 = $235.83 or 40.9%
S1-27722 = $232.32 or 40.3%
B1-86481 = $107.97 or 18.7%

解决这个问题用两种方式:

第一种新建 DataFrame 然后 merge 两个 DataFrame. 代码如下:

1
2
3
4
5
6
7
8
9
10
11
order_total = df.groupby('order')["ext price"].sum().rename("Order_Total").reset_index()

df_1 = df.merge(order_total)
df_1["Percent_of_Order"] = df_1["ext price"] / df_1["Order_Total"]

print('新建的 DataFrame 是:')
print(order_total)
print('\n')

print('我们的结果是:')
print(df_1)

输出结果是:

新建的 DataFrame 是:

image-20200821163934164

我们的结果是:

image-20200821163951790

第二种就是使用 DataFrame.transform() 这个函数:

1
2
3
4
5
6
7
8
import pandas as pd
import numpy as np

df = pd.read_excel('sales_transactions.xlsx')

df["Percent_of_Order"] = df["ext price"] / df.groupby('order')["ext price"].transform('sum')
print('我们的结果是:')
print(df)

输出结果是:

我们的结果是:

image-20200821164332003

Topic 6 Pandas IO

平时工作中, 我们会接触到不同的数据文件, 比如很常见的excel文件(后缀名为xls和xlsx), csv、txt等文本文件, json文件以及sql文件等等. pandas读取这些数据文件的方法如表格所示:

读取方法 描述 写入方法
read_csv 读取 csv 文件, 逗号是默认分隔符 to_csv
read_table 读取通用分隔符分割的数据文件, 默认为制表符 \t to_csv
read_excel 读取 xls 或者 xlsx 表格文件 to_excel
read_json 读取 json 文件 to_json
read_sql 从 SQL 请求读取或者读取数据库中的表 to_sql
read_sql_table 读取数据库中的表 to_sql
read_sql_query 从 SQL 请求读取数据 to_sql

6.1 pandas.read_csv()

read_csv()方法用来读取 csv格式的数据文件, read_table()方法则是读取通用分隔符分隔的数据文件, 它们的参数相同, 语法如下:

1
2
3
4
5
6
7
8
9
10
11
pandas.read_csv(filepath_or_buffer, sep=',', delimiter=None, header='infer', names=None, index_col=None, usecols=None, skiprows=None)

# 参数说明
# filepath_or_buffer: str, 表示文件所在位置的字符串, URL等.
# sep: str, 表示分隔符, 分隔符号可以有多个, 比如分隔符为"+,+"三个符号, 则sep = '+,+', 即正则表达式. read_csv默认分隔符为",", read_table默认为制表符"\t"
# delimitter: sep的别名
# header: int, 表示列名的行号. 如果没有传递列名, 则header = 0, 列名为文件的第一行. 如果显式传递了列名, 则header = None
# names: 指定列名
# index_col: int,sequence或False. 表示索引列的位置, 取值为sequence则代表多重索引
# usecols: array, 指定读取的列
# skiprows: 从文件开头算, 需要跳过的行数