PandasPython语言的一个扩展程序库,用于数据分析。

Pandas是一个开放源码、BSD许可的库,提供高性能、易于使用的数据结构和数据分析工具。

Pandas名字衍生自术语 “panel data“(面板数据)和 “Python data analysis“(Python数据分析)。

Pandas一个强大的分析结构化数据的工具集,基础是NumPy(提供高性能的矩阵运算)。

Pandas可以从各种文件格式比如CSVJSONSQLMicrosoft Excel 导入数据。

Pandas可以对各种数据进行运算操作,比如归并、再成形、选择,还有数据清洗和数据加工特征。

Pandas广泛应用在学术、金融、统计学等各个数据分析领域。

Pandas主要包括以下几个特点:

  • 它提供了一个简单、高效、带有默认标签(也可以自定义标签)的DataFrame对象。
  • 能够快速从不同格式的文件中加载数据(比如 ExcelCSVSQL文件),然后转换为可处理的对象;
  • 能够按数据的行、列标签进行分组,并对分组后的对象执行聚合和转换操作;
  • 能够很方便地实现数据归一化操作和缺失值处理;
  • 能够很方便地对DataFrame的数据列进行增加、修改或者删除的操作;
  • 能够处理不同格式的数据集,比如矩阵数据、异构数据表、时间序列等;
  • 提供了多种处理数据集的方式,比如构建子集、切片、过滤、分组以及重新排序等。

⛄Pandas数据结构

Pandas的主要数据结构是Series(一维数据)与DataFrame(二维数据),这两种数据结构足以处理金融、统计、社会科学、工程等领域里的大多数典型用例。

**Series**是一种类似于一维数组的对象,它由一组数据(各种Numpy数据类型)以及一组与之相关的数据标签(即索引)组成。

**DataFrame**是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame既有行索引也有列索引,它可以被看做由Series组成的字典(共同用一个索引)。

⛄Pandas Series

Pandas Series类似表格中的一个列(column),类似于一维数组,由一组数据值(value)和一组标签组成,其中标签与数据值之间是一一对应的关系。Series可以保存任何数据类型,比如整数、字符串、浮点数、Python对象等,它的标签默认为整数,从0开始依次递增。

👀创建Series对象

Series由索引(index)和列组成,函数如下:

pandas.Series(data, index, dtype, name, copy)
参数说明:
data:一组数据(ndarray类型)。
index:数据索引标签,如果不指定,默认从0开始。
dtype:数据类型,默认会自己判断。
name:设置名称。
copy:拷贝数据,默认为False

import pandas as pd
a = [1, 2, 3]
myvar = pd.Series(a)
print(myvar)
print(myvar[1])

# 输出结果:第一列为索引,第二列为数据
# 如果没有指定索引,索引值就从0开始,我们可以根据索引值读取数据:
0 1
1 2
2 3
dtype: int64
2

我们也可以使用数组、字典、标量值或者Python对象来创建Series对象。

(1)创建一个空Series对象

import pandas as pd
#输出数据为空
s = pd.Series()
print(s)

# 输出结果
Series([], dtype: float64)

(2)ndarray创建Series对象

ndarrayNumPy中的数组类型,当datandarry时,传递的索引必须具有与数组相同的长度。如果没有指定索引(隐式索引),索引值就从0开始(索引值将使用是range(n) 生成,其中n代表数组长度);我们可以根据索引值读取数据。可以指定索引值(显式索引),如下实例。

import pandas as pd
import numpy as np

# 指定索引值
a = np.array(["Google", "Runoob", "Wiki"])
myvar = pd.Series(a, index = ["x", "y", "z"])
print(myvar)
print(myvar["y"])

#输出结果
x Google
y Runoob
z Wiki
dtype: object
Runoob

(3)dict创建Series对象

我们也可以使用key/value对象,类似字典来创建Series

import pandas as pd

# 使用字典创建Series
# 没有传递索引,字典的key变成了索引值。
sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar1 = pd.Series(sites)
print(myvar1)
# 如果我们只需要字典中的一部分数据,只需要指定需要数据的索引即可,如下实例:
myvar2 = pd.Series(sites, index = [1,2])
print(myvar2)
# 当传递的索引值无法找到与其对应的值时,使用NaN(非数字)填充。
myvar3 = pd.Series(sites, index = [1,3,2,4])
print(myvar3)

# 输出结果
1 Google
2 Runoob
3 Wiki
dtype: object
1 Google
2 Runoob
dtype: object
1 Google
3 Wiki
2 Runoob
4 NaN
dtype: object

当传递的索引值无法找到与其对应的值时,使用NaN(非数字)填充。

(4)标量创建Series对象

如果data是标量值,则必须提供索引,示例如下:

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

# 输出结果
0 5
1 5
2 5
3 5
dtype: int64

标量值按照index的数量进行重复,并与其一一对应。

设置Series名称参数:

import pandas as pd

sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar = pd.Series(sites, index = [1, 2], name="RUNOOB-Series-TEST" )
print(myvar)

# 输出结果
1 Google
2 Runoob
Name: RUNOOB-Series-TEST, dtype: object

👀访问Series数据

(1)位置索引访问

这种访问方式与ndarraylist相同,使用元素自身的下标进行访问。我们知道数组的索引计数从0开始,这表示第一个元素存储在第0个索引位置上,以此类推,就可以获得Series序列中的每个元素。

import pandas as pd
s = pd.Series([5,2,3,4,5],index = ['a','b','c','d','e'])
print(s[0]) # 位置下标
print(s['a']) # 标签下标
# 通过切片的方式访问Series序列中的数据
print(s[:3])
# 获取最后三个元素
print(s[-3:])

# 输出结果
5
5
a 5
b 2
c 3
dtype: int64
c 3
d 4
e 5
dtype: int64

(2)索引标签访问

Series类似于固定大小的dict,把index中的索引标签当做key,而把Series序列中的元素值当做value,然后通过index索引标签来访问或者修改元素值。

import pandas as pd
# 使用索标签访问单个元素值
s = pd.Series([16,17,18,19,20],index = ['a','b','c','d','e'])
print(s['a'])
# 使用索引标签访问多个元素值
print(s[['a','c','d']])
# 如果使用了index中不包含的标签,则会触发异常
print(s['f'])

# 输出结果
16
a 16
c 18
d 19
dtype: int64
......
KeyError: 'f'

👀Series常用属性

Series的常用属性和方法:

名称 属性
axes 以列表的形式返回所有行索引标签
dtype 返回对象的数据类型
empty 返回一个空的Series对象
ndim 返回输入数据的维数
size 返回输入数据的元素数量
values ndarray的形式返回Series对象
index 返回一个RangeIndex对象,用来描述索引的取值范围
import pandas as pd
import numpy as np
s = pd.Series(np.random.randn(6))
print(s)
print("*"*20)
# axes属性
print(s.axes)
print("*"*20)
# dtype属性
print(s.dtype)
print("*"*20)
# empty
print(s.empty)
print("*"*20)
# ndim,Series是一维数据结构,因此它始终返回1
print(s.ndim)
print("*"*20)
# size返回Series对象的大小(长度)
print(s.size)
print("*"*20)
# value以数组的形式返回Series对象中的数据
print(s.values)
print("*"*20)
# index该属性用来查看Series中索引的取值范围
#显示索引
s1 = pd.Series([1,2,5,8],index = ['a','b','c','d'])
print(s1.index)
#隐式索引
s2 = pd.Series([1,2,5,8])
print(s2.index)

# 输出结果
0 -0.674501
1 1.030106
2 -1.636359
3 -1.540996
4 1.312837
5 -0.735986
dtype: float64
********************
[RangeIndex(start=0, stop=6, step=1)]
********************
float64
********************
False
********************
1
********************
6
********************
[-0.67450078 1.03010573 -1.63635856 -1.54099596 1.31283698 -0.73598645]
********************
Index(['a', 'b', 'c', 'd'], dtype='object')
RangeIndex(start=0, stop=4, step=1)

👀Series常用方法

(1)head()&tail()查看数据

如果想要查看Series的某一部分数据,可以使用head()或者tail()方法。其中head()返回前n行数据,默认显示前5行数据。tail()返回的是后n行数据,默认为后5行。

import pandas as pd
import numpy as np
s = pd.Series(np.random.randn(5))
print (s)
# 返回前三行数据
print(s.head(3))
# 返回后两行数据
print(s.tail(3))

# 输出结果
0 -0.264915
1 -1.120671
2 0.621638
3 -0.449170
4 0.533876
dtype: float64
0 -0.264915
1 -1.120671
2 0.621638
dtype: float64
2 0.621638
3 -0.449170
4 0.533876
dtype: float64

(2)isnull()&notnull()检测缺失值

isnull()notnull()用于检测Series中的缺失值。所谓缺失值,顾名思义就是值不存在、丢失、缺少。

  • isnull():如果为值不存在或者缺失,则返回True
  • notnull():如果值不存在或者缺失,则返回False

其实不难理解,在实际的数据分析任物中,数据的收集往往要经历一个繁琐的过程。在这个过程中难免会因为一些不可抗力,或者人为因素导致数据丢失的现象。这时,我们可以使用相应的方法对缺失值进行处理,比如均值插值、数据补齐等方法。上述两个方法就是帮助我们检测是否存在缺失值。

import pandas as pd
#None代表缺失数据
s = pd.Series([1,6,None,8,None])
print(pd.isnull(s)) #是空值返回True
print(pd.notnull(s)) #空值返回False

# 输出结果
0 False
1 False
2 True
3 False
4 True
dtype: bool
0 True
1 True
2 False
3 True
4 False
dtype: bool

⛄Pandas DataFrame

DataFrame是表格型的数据结构,既有行标签(index),又有列标签(columns),它也被称异构数据表。

它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame既有行索引也有列索引,它可以被看做由Series组成的字典(共同用一个索引),每一行数据都可以看成一个Series结构,DataFrame为这些行中每个数据值增加了一个列标签。

Series一样,DataFrame自带行标签索引,默认为“隐式索引”即从0开始依次递增,行标签与DataFrame中的数据项一一对应。DataFrame数据结构的特点:

  • DataFrame每一列的标签值允许使用不同的数据类型;
  • DataFrame是表格型的数据结构,具有行和列;
  • DataFrame中的每个数据值都可以被修改;
  • DataFrame结构的行数、列数允许增加或者删除;
  • DataFrame有两个方向的标签轴,分别是行标签和列标签;
  • DataFrame可以对行和列执行算术运算。

👀创建DF对象

DataFrame构造方法如下:

pandas.DataFrame(data, index, columns, dtype, copy)
参数说明:
data:一组数据(ndarray、series, map, lists, dict等类型)。
index:索引值,或者可以称为行标签。
columns:列标签,默认为RangeIndex(0, 1, 2, …, n) 。
dtype:数据类型。
copy:拷贝数据,默认为False

Pandas DataFrame是一个二维的数组结构,类似二维数组。

Pandas提供了多种创建DataFrame对象的方式,主要包含以下五种:

(1)创建空的DataFrame对象

import pandas as pd
df = pd.DataFrame()
print(df)
# 输出结果
Empty DataFrame
Columns: []
Index: []

(2)列表创建DataFame对象

可以使用单一列表或嵌套列表来创建一个DataFrame

import pandas as pd

# 单一列表创建DataFrame对象
data1 = [6,7,8,9,10]
df1 = pd.DataFrame(data1)
print(df1)
# 嵌套列表创建DataFrame对象,并指定数值元素的数据类型为float
data2 = [['Google',10],['Runoob',12],['Wiki',13]]
df2 = pd.DataFrame(data2,columns = ['Site','Age'],dtype = float)
print(df2)

# 输出结果
0
0 6
1 7
2 8
3 9
4 10
Site Age
0 Google 10.0
1 Runoob 12.0
2 Wiki 13.0

(3)字典嵌套列表创建DataFame对象

dict字典中,键对应的值的元素长度必须相同(也就是列表长度相同)。如果传递了索引,那么索引的长度应该等于数组的长度;如果没有传递索引,那么默认情况下,索引将是range(n),其中n代表数组长度。

import pandas as pd

# 这里使用了默认行标签,也就是range(n)。它生成了0,1,2,3,并分别对应了列表中的每个元素值
data = {'Site':['Google', 'Runoob', 'Wiki'], 'Age':[10, 12, 13]}
df = pd.DataFrame(data)
print(df)
# 添加自定义的行标签,index参数为每行分配了一个索引
df2 = pd.DataFrame(data,index = ['one','two','three'])
print(df2)

# 输出结果
Site Age
0 Google 10
1 Runoob 12
2 Wiki 13
Site Age
one Google 10
two Runoob 12
three Wiki 13

从以上输出结果可以知道, DataFrame数据类型一个表格,包含rows(行)和columns(列)。

(4)列表嵌套字典创建DataFrame对象

列表嵌套字典可以作为输入数据传递给DataFrame构造函数。默认情况下,字典的键被用作列名。

import pandas as pd

# 列表嵌套字典
data1 = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]
# 字典嵌套列表
data2 = {'a':[1, 5], 'b':[2, 10], 'c':[15, 20]}
df1 = pd.DataFrame(data1)
print(df1)
df2 = pd.DataFrame(data2)
print(df2)
# 添加行标签索引
df3 = pd.DataFrame(data1,index = ['one','two'])
print(df3)
# 行标签索引
# 注意:因为'abc'在字典键中不存在,所以对应值为NaN
df4 = pd.DataFrame(data1,index = ['one','two'],columns = ['a','abc'])
print(df4)

# 输出结果,没有对应的部分数据为NaN。
a b c
0 1 2 NaN
1 5 10 20.0
a b c
0 1 2 15
1 5 10 20
a b c
one 1 2 NaN
two 5 10 20.0
a abc
one 1 NaN
two 5 NaN

(5)Series创建DataFrame对象

可以传递一个字典形式的Series,从而创建一个DataFrame对象,其输出结果的行索引是所有index的合集。

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)

# 输出结果,对于one列而言,此处虽然显示了行索引'd',但由于没有与其对应的值,所以它的值为NaN
one two
a 1.0 1
b 2.0 2
c 3.0 3
d NaN 4

👀列索引操作DF对象

DataFrame可以使用列索(columns index)引来完成数据的选取、添加和删除操作。

(1)列索引选取数据列

import pandas as pd

data = {
"calories": [420, 380, 390],
"duration": [50, 40, 45]
}
# 数据载入到DataFrame对象
df = pd.DataFrame(data, index = ['a', 'b', 'c'])
print(df)
# 返回第一列
print(df['calories'])

# 输出结果
calories duration
a 420 50
b 380 40
c 390 45
a 420
b 380
c 390
Name: calories, dtype: int64

(2)列索引添加数据列

使用columns列索引表标签可以实现添加新的数据列。

import pandas as pd

data = {
"calories": [420, 380, 390],
"duration": [50, 40, 45]
}
# 数据载入到DataFrame对象
df = pd.DataFrame(data, index = ['a', 'b', 'c'])
print(df)
# 返回第一列
print("*"*20)
# 使用df['列']=值,插入新的数据列
df['height'] = pd.Series([160,170,180], index = ['a', 'b', 'c'])
print(df)
print("*"*20)
# 将已经存在的数据列做相加运算
df['sums'] = df['calories'] + df['duration']
print(df)

# 输出结果
calories duration
a 420 50
b 380 40
c 390 45
********************
calories duration height
a 420 50 160
b 380 40 170
c 390 45 180
********************
calories duration height sums
a 420 50 160 470
b 380 40 170 420
c 390 45 180 435

我们初次使用了DataFrame的算术运算,这和NumPy非常相似。除了使用df[]=value的方式外,您还可以使用insert()方法插入新的列.

import pandas as pd
info = [['Jack',18],['Helen',19],['John',17]]
df = pd.DataFrame(info,columns = ['name','age'])
print(df)
# 注意是column参数
# 数值1代表插入到columns列表的索引位置
df.insert(1,column = 'score',value = [91,90,75])
print(df)

# 输出结果
name age
0 Jack 18
1 Helen 19
2 John 17
name score age
0 Jack 91 18
1 Helen 90 19
2 John 75 17

(3)列索引删除数据列

通过delpop()都能够删除DataFrame中的数据列。示例如下:

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']),
'three': pd.Series([10,20,30], index = ['a','b','c'])}
df = pd.DataFrame(d)
print(df)
print("*"*20)
# 使用del删除
del df['one']
print(df)
print("*"*20)
# 使用pop方法删除
df.pop('two')
print(df)

# 输出结果
one two three
a 1.0 1 10.0
b 2.0 2 20.0
c 3.0 3 30.0
d NaN 4 NaN
********************
two three
a 1 10.0
b 2 20.0
c 3 30.0
d 4 NaN
********************
three
a 10.0
b 20.0
c 30.0
d NaN

👀行索引操作DF对象

Pandas可以使用**loc**函数返回指定行的数据,如果没有设置索引,第一行索引为0,第二行索引为1,以此类推。

(1)标签索引选取

通过将行标签传递给loc函数,来选取数据。

loc允许接两个参数分别是行和列,参数之间需要使用“逗号”隔开,但该函数只能接收标签索引

import pandas as pd

data = {
"calories": [420, 380, 390],
"duration": [50, 40, 45]
}
# 数据载入到 DataFrame 对象
df = pd.DataFrame(data, index = ['a', 'b', 'c'])
print(df)
print('*'*20)
print(df.loc['a'])

# 输出结果
calories duration
a 420 50
b 380 40
c 390 45
********************
calories 420
duration 50
Name: a, dtype: int64

(2)整数索引选取

通过将数据行所在的索引位置传递给iloc函数,也可以实现数据行选取。

iloc允许接受两个参数分别是行和列,参数之间使用“逗号”隔开,但该函数只能接收整数索引

import pandas as pd

data = {
"calories": [420, 380, 390],
"duration": [50, 40, 45]
}
# 数据载入到 DataFrame 对象
df = pd.DataFrame(data, index = ['a', 'b', 'c'])
print(df)
print('*'*20)
# 返回第一行,返回结果其实就是一个Pandas Series数据。
print(df.iloc[0])
print('*'*20)
# 返回第二行,返回结果其实就是一个Pandas Series数据。
print(df.iloc[1])
print('*'*20)
# 也可以返回多行数据,使用[[ ... ]] 格式,... 为各行的索引,以逗号隔开:
# 返回第一行和第二行,返回结果其实就是一个Pandas DataFrame数据。
print(df.iloc[[0, 1]])

# 输出结果
calories duration
a 420 50
b 380 40
c 390 45
********************
calories 420
duration 50
Name: a, dtype: int64
********************
calories 380
duration 40
Name: b, dtype: int64
********************
calories duration
a 420 50
b 380 40

(3)切片操作多行数据

通过使用切片的方式同时选取多行。

import pandas as pd

data = {
"calories": [420, 380, 390],
"duration": [50, 40, 45]
}
# 数据载入到 DataFrame 对象
df = pd.DataFrame(data, index = ['a', 'b', 'c'])
print(df)
print('*'*20)
# 左闭右开
print(df[1:3])

# 输出结果
calories duration
a 420 50
b 380 40
c 390 45
********************
calories duration
b 380 40
c 390 45

(4)添加数据行

使用append()函数,可以将新的数据行添加到DataFrame中,该函数会在行末追加数据行。

import pandas as pd
df = pd.DataFrame([[1, 2], [3, 4]], index = ['one','two'], columns = ['a','b'])
df2 = pd.DataFrame([[5, 6], [7, 8]], index = ['one','two'], columns = ['a','b'])
# 在行末追加新数据行
df = df.append(df2)
print(df)

# 输出结果
a b
one 1 2
two 3 4
one 5 6
two 7 8

(5)删除数据行

使用行索引标签,从DataFrame中删除某一行数据。如果索引标签存在重复,那么它们将被一起删除。

import pandas as pd
df = pd.DataFrame([[1, 2], [3, 4]], index = ['one','two'], columns = ['a','b'])
df2 = pd.DataFrame([[5, 6], [7, 8]], index = ['one','two'], columns = ['a','b'])
# 在行末追加新数据行
df = df.append(df2)
print(df)
print('*'*20)
# 注意此处调用了drop()方法,drop('one')同时删除了两行数据
df1 = df.drop('one')
print(df1)

# 输出结果
a b
one 1 2
two 3 4
one 5 6
two 7 8
********************
a b
two 3 4
two 7 8

👀DF对象属性和方法

DataFrame的属性和方法,与Series相差无几。

名称 属性方法描述
T 行和列转置
axes 返回一个仅以行轴标签和列轴标签为成员的列表
dtypes 返回每列数据的数据类型
empty DataFrame中没有数据或者任意坐标轴的长度为0,则返回True
ndim 轴的数量,也指数组的维数。
shape 返回一个元组,表示了DataFrame维度
size DataFrame中的元素数量
values 使用numpy数组表示DataFrame中的元素值
head() 返回前n行数据
tail() 返回后n行数据
shift() 将行或列移动指定的步幅长度
import pandas as pd
import numpy as np
d = {'Name':pd.Series(['小汤','小王',"小明",'小红','小小','小微','小黄']),
'years':pd.Series([2005,2006,2015,2008,2003,2009,2003]),
'height':pd.Series([180,175,178,179,176,170,173])}
# 构建DataFrame
df = pd.DataFrame(d)
# 输出
print(df)
print('*'*20)
# T(Transpose)转置,返回DataFrame的转置,也就是把行和列进行交换
print(df.T)
print('*'*20)
# 返回一个行标签、列标签组成的列表
print(df.axes)
print('*'*20)
# 返回每一列的数据类型
print(df.dtypes)
print('*'*20)
# 返回一个布尔值,判断输出的数据对象是否为空,若为True表示对象为空
print(df.empty)
print('*'*20)
# 返回数据对象的维数。DataFrame是一个二维数据结构
print(df.ndim)
print('*'*20)
# 返回一个代表DataFrame维度的元组。返回值元组(a,b),其中a表示行数,b表示列数
print(df.shape)
print('*'*20)
# 返回DataFrame中的元素数量
print(df.size)
print('*'*20)
# 以ndarray数组的形式返回DataFrame中的数据
print(df.values)
print('*'*20)

# 输出结果
Name years height
0 小汤 2005 180
1 小王 2006 175
2 小明 2015 178
3 小红 2008 179
4 小小 2003 176
5 小微 2009 170
6 小黄 2003 173
********************
0 1 2 3 4 5 6
Name 小汤 小王 小明 小红 小小 小微 小黄
years 2005 2006 2015 2008 2003 2009 2003
height 180 175 178 179 176 170 173
********************
[RangeIndex(start=0, stop=7, step=1), Index(['Name', 'years', 'height'], dtype='object')]
********************
Name object
years int64
height int64
dtype: object
********************
False
********************
2
********************
(7, 3)
********************
21
********************
[['小汤' 2005 180]
['小王' 2006 175]
['小明' 2015 178]
['小红' 2008 179]
['小小' 2003 176]
['小微' 2009 170]
['小黄' 2003 173]]
********************

head()&tail()查看数据。如果想要查看DataFrame的一部分数据,可以使用head()或者tail()方法。head()返回前n行数据,默认显示前5行数据。tail()返回后n行数据。

import pandas as pd
import numpy as np
d = {'Name':pd.Series(['小汤','小王',"小明",'小红','小小','小微','小黄']),
'years':pd.Series([2005,2006,2015,2008,2003,2009,2003]),
'height':pd.Series([180,175,178,179,176,170,173])}
# 构建DataFrame
df = pd.DataFrame(d)
# 输出
print(df)
print('*'*20)
# 获取前3行数据
print(df.head(3))
print('*'*20)
# 获取后2行数据
print(df.tail(2))

# 输出结果
Name years height
0 小汤 2005 180
1 小王 2006 175
2 小明 2015 178
3 小红 2008 179
4 小小 2003 176
5 小微 2009 170
6 小黄 2003 173
********************
Name years height
0 小汤 2005 180
1 小王 2006 175
2 小明 2015 178
********************
Name years height
5 小微 2009 170
6 小黄 2003 173

shift()移动行或列。如果您想要移动DataFrame中的某一行/列,可以使用shift()函数实现。它提供了一个periods参数,该参数表示在特定的轴上移动指定的步幅。

DataFrame.shift(periods=1, freq=None, axis=0)  
参数说明:
peroids 类型为int,表示移动的幅度,可以是正数,也可以是负数,默认值为1
freq 日期偏移量,默认值为None,适用于时间序。取值为符合时间规则的字符串。
axis 如果是0或者"index"表示上下移动,如果是1或者"columns"则会左右移动。
fill_value 该参数用来填充缺失值。
import pandas as pd
import numpy as np
d = {'Name':pd.Series(['小汤','小王',"小明",'小红','小小','小微','小黄']),
'years':pd.Series([2005,2006,2015,2008,2003,2009,2003]),
'height':pd.Series([180,175,178,179,176,170,173])}
# 构建DataFrame
df = pd.DataFrame(d)
# 输出
print(df)
print('*'*20)
# 移动幅度为3
print(df.shift(periods=3))
print('*'*20)
# 使用fill_value参数填充DataFrame中的缺失值
print(df.shift(periods=3,fill_value=52))
print('*'*20)
print(df.shift(periods=3,axis=1,fill_value=52))

# 输出结果
Name years height
0 小汤 2005 180
1 小王 2006 175
2 小明 2015 178
3 小红 2008 179
4 小小 2003 176
5 小微 2009 170
6 小黄 2003 173
********************
Name years height
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 小汤 2005.0 180.0
4 小王 2006.0 175.0
5 小明 2015.0 178.0
6 小红 2008.0 179.0
********************
Name years height
0 52 52 52
1 52 52 52
2 52 52 52
3 小汤 2005 180
4 小王 2006 175
5 小明 2015 178
6 小红 2008 179
********************
Name years height
0 52 52 52
1 52 52 52
2 52 52 52
3 52 52 52
4 52 52 52
5 52 52 52
6 52 52 52

⛄Pandas函数操作

👀Panel结构(了解)

Panel是一个用来承载数据的三维数据结构,它有三个轴,分别是items(0轴),major_axis(1轴),而 minor_axis(2轴)。这三个轴为描述、操作Panel提供了支持,其作用介绍如下:

  • items:axis =0,Panel 中的每个items都对应一个DataFrame
  • major_axis:axis=1,用来描述每个DataFrame的行索引。
  • minor_axis:axis=2,用来描述每个DataFrame的列索引。
pandas.Panel(data, items, major_axis, minor_axis, dtype, copy)
参数说明:
data 输入数据,可以是 ndarray,Series,列表,字典,或者 DataFrame。
items axis=0
major_axis axis=1
minor_axis axis=2
dtype 每一列的数据类型。
copy 默认为 False,表示是否复制数据。

Pandas 0.25版本后, Panel结构已经被废弃。

👀描述性统计函数

函数名称 描述说明
count() 统计某个非空值的数量
sum() 求和
mean() 求均值
median() 求中位数
mode() 求众数
std() 求标准差
min() 求最小值
max() 求最大值
abs() 求绝对值
prod() 求所有数值的乘积
cumsum() 计算累计和,axis=0,按照行累加;axis=1,按照列累加
cumprod() 计算累计积,axis=0,按照行累积;axis=1,按照列累积
corr() 计算数列或变量之间的相关系数,取值-1到1,值越大表示关联性越强
describe() 显示与DataFrame数据列相关的统计信息摘要

DataFrame中,使用聚合类方法时需要指定轴(axis)参数。下面介绍两种传参方式:

  • 对行操作,默认使用axis=0或者使用 “index“;
  • 对列操作,默认使用axis=1或者使用 “columns“。
  • axis=0表示按垂直方向进行计算,而axis=1则表示按水平方向。

describe()函数输出了平均值、stdIQR值(四分位距)等一系列统计信息。通过describe()提供的include能够筛选字符列或者数字列的摘要信息。include相关参数值说明如下:

  • object: 表示对字符列进行统计信息描述;
  • number:表示对数字列进行统计信息描述;
  • all:汇总所有列的统计信息。
import pandas as pd
import numpy as np
d = {'Name':pd.Series(['小汤','小王',"小明",'小红','小小','小微','小黄']),
'years':pd.Series([2005,2006,2015,2008,2003,2009,2003]),
'height':pd.Series([180,175,178,179,176,170,173])}
# 构建DataFrame
df = pd.DataFrame(d)
# 输出
print(df)
print('*'*20)
# 求出数据的所有描述信息
print(df.describe())
print('*'*20)
print(df.describe(include=["object"]))
print('*'*20)
print(df.describe(include="all"))

# 输出结果
Name years height
0 小汤 2005 180
1 小王 2006 175
2 小明 2015 178
3 小红 2008 179
4 小小 2003 176
5 小微 2009 170
6 小黄 2003 173
********************
years height
count 7.000000 7.000000
mean 2007.000000 175.857143
std 4.203173 3.532165
min 2003.000000 170.000000
25% 2004.000000 174.000000
50% 2006.000000 176.000000
75% 2008.500000 178.500000
max 2015.000000 180.000000
********************
Name
count 7
unique 7
top 小汤
freq 1
********************
Name years height
count 7 7.000000 7.000000
unique 7 NaN NaN
top 小汤 NaN NaN
freq 1 NaN NaN
mean NaN 2007.000000 175.857143
std NaN 4.203173 3.532165
min NaN 2003.000000 170.000000
25% NaN 2004.000000 174.000000
50% NaN 2006.000000 176.000000
75% NaN 2008.500000 178.500000
max NaN 2015.000000 180.000000

👀自定义函数

如果想要应用自定义的函数,或者把其他库中的函数应用到Pandas对象中,有以下三种方法:

  • 操作整个DataFrame的函数:pipe()
  • 操作行或者列的函数:apply()
  • 操作单一元素的函数:applymap()

(1)操作整个数据表

通过给pipe()函数传递一个自定义函数和适当数量的参数值,从而操作DataFrme中的所有元素。下面示例,实现了数据表中的元素值依次加 6。

import pandas as pd
import numpy as np
# 自定义函数
def addsum(a1,a2):
return a1 + a2
# 操作DataFrame
df = pd.DataFrame([[120,130,150],[90,100,110],[60,70,80]],columns=['c1','c2','c3'])
# 相加前
print(df)
# 相加后
print(df.pipe(addsum,6))

# 输出结果
c1 c2 c3
0 120 130 150
1 90 100 110
2 60 70 80
c1 c2 c3
0 126 136 156
1 96 106 116
2 66 76 86

(2)操作行或列

如果要操作DataFrame的某一行或者某一列,可以使用apply()方法,该方法与描述性统计方法类似,都有可选参数axis,并且默认按列操作。示例如下:

import pandas as pd
import numpy as np
# 操作DataFrame
df = pd.DataFrame([[120,130,150],[90,100,110],[60,70,80]],columns=['c1','c2','c3'])
print(df)
print('*'*20)
# 默认按列操作,计算每一列均值
print(df.apply(np.mean))
print('*'*20)
# 传递轴参axis=1,表示逐行进行操作
print(df.apply(np.mean,axis=1))
print('*'*20)
# 求每一列中,最大值与最小值之差
print(df.apply(lambda x: x.max() - x.min()))

# 输出结果
c1 c2 c3
0 120 130 150
1 90 100 110
2 60 70 80
********************
c1 90.000000
c2 100.000000
c3 113.333333
dtype: float64
********************
0 133.333333
1 100.000000
2 70.000000
dtype: float64
********************
c1 60
c2 60
c3 70
dtype: int64

(3)操作单一元素

DataFrame数据表结构的applymap()Series系列结构的map()类似,它们都可以接受一个Python函数,并返回相应的值。

import pandas as pd
# 操作DataFrame
df = pd.DataFrame([[120,130,150],[90,100,110],[60,70,80]],columns=['c1','c2','c3'])
print(df)
print('*'*20)
# 自定义函数lambda函数
print(df['c1'].map(lambda x:x*10))
print('*'*20)
# 使用了applymap()函数
print(df.applymap(lambda x:x*10))

# 输出结果
c1 c2 c3
0 120 130 150
1 90 100 110
2 60 70 80
********************
0 1200
1 900
2 600
Name: c1, dtype: int64
********************
c1 c2 c3
0 1200 1300 1500
1 900 1000 1100
2 600 700 800

👀reindex重置索引

重置索引(reindex)可以更改原DataFrame的行标签或列标签,并使更改后的行、列标签与DataFrame中的数据逐一匹配。通过重置索引操作,您可以完成对现有数据的重新排序。如果重置的索引标签在原DataFrame中不存在,那么该标签对应的元素值将全部填充为NaN

(1)重置行列标签

import pandas as pd
# 操作DataFrame
df = pd.DataFrame([[120,130,150],[90,100,110],[60,70,80]],columns=['c1','c2','c3'])
print(df)
print('*'*20)
# 重置行、列索引标签
df_reindexed = df.reindex(index=[0,1], columns=['c1', 'c3'])
print(df_reindexed)

# 输出结果
c1 c2 c3
0 120 130 150
1 90 100 110
2 60 70 80
********************
c1 c3
0 120 150
1 90 110

现有a、b两个DataFrame对象,如果想让a的行索引与b相同,您可以使用reindex_like() 方法。示例如下:

import pandas as pd
import numpy as np
a = pd.DataFrame(np.random.randn(10,3),columns=['col1','col2','col3'])
b = pd.DataFrame(np.random.randn(7,3),columns=['col1','col2','col3'])
# a会按照b的形式重建行索引。需要特别注意的是,a与b的列索引标签必须相同。
a= a.reindex_like(b)
print(a)

# 输出结果
col1 col2 col3
0 0.669617 0.010243 -0.091776
1 -0.333395 -1.521432 0.292087
2 -0.174709 -0.623413 1.291384
3 1.033132 -0.383137 1.280788
4 1.052466 -1.326848 -1.390581
5 1.828058 0.422678 -0.734622
6 0.988210 -1.047092 -1.959839

(2)填充元素值

reindex_like()提供了一个可选的参数method,使用它来填充相应的元素值,参数值介绍如下:

  • pad/ffill:向前填充值;
  • bfill/backfill:向后填充值;
  • nearest:从距离最近的索引值开始填充。

reindex_like()还提供了一个额外参数limit,该参数用来控制填充的最大行数。示例如下:

import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.random.randn(6,3),columns=['col1','col2','col3'])
df2 = pd.DataFrame(np.random.randn(2,3),columns=['col1','col2','col3'])
# 使df2和df1行标签相同
print(df2.reindex_like(df1))
print('*'*20)
# 向前填充
print(df2.reindex_like(df1,method='ffill'))
print('*'*20)
# 向后填充
print(df2.reindex_like(df1,method='backfill'))
print('*'*20)
# limit限制填充行数
print(df2.reindex_like(df1,method='ffill',limit=2))

# 输出结果
col1 col2 col3
0 0.552991 1.230408 0.403586
1 -0.135228 1.065911 -0.624843
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
5 NaN NaN NaN
********************
col1 col2 col3
0 0.552991 1.230408 0.403586
1 -0.135228 1.065911 -0.624843
2 -0.135228 1.065911 -0.624843
3 -0.135228 1.065911 -0.624843
4 -0.135228 1.065911 -0.624843
5 -0.135228 1.065911 -0.624843
********************
col1 col2 col3
0 0.552991 1.230408 0.403586
1 -0.135228 1.065911 -0.624843
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
5 NaN NaN NaN
********************
col1 col2 col3
0 0.552991 1.230408 0.403586
1 -0.135228 1.065911 -0.624843
2 -0.135228 1.065911 -0.624843
3 -0.135228 1.065911 -0.624843
4 NaN NaN NaN
5 NaN NaN NaN

(3)重命名标签

rename()方法允许您使用某些映射(dictSeries)或任意函数来对行、列标签重新命名,示例如下:

import pandas as pd
# 操作DataFrame
df = pd.DataFrame([[120,130,150],[90,100,110],[60,70,80]],columns=['c1','c2','c3'])
print(df)
print('*'*20)
# 对行和列重新命名
print(df.rename(columns={'c1':'cc1','c2':'cc2'},index = {0:'one',1:'two',2:'three'}))

# 输出结果
c1 c2 c3
0 120 130 150
1 90 100 110
2 60 70 80
********************
cc1 cc2 c3
one 120 130 150
two 90 100 110
three 60 70 80

rename()方法提供了一个inplace参数,默认值为False,表示拷贝一份原数据,并在复制后的数据上做重命名操作。若inplace=True则表示在原数据的基础上重命名。

👀iteration遍历操作

Pandas是如何遍历SeriesDataFrame结构呢?对于Series而言,您可以把它当做一维数组进行遍历操作;而像DataFrame这种二维数据表结构,则类似于遍历Python字典。

Pandas中同样也是使用for循环进行遍历。通过for遍历后,Series可直接获取相应的value,而DataFrame则会获取列标签。示例如下:

import pandas as pd
# 操作DataFrame
df = pd.DataFrame([[120,130,150],[90,100,110],[60,70,80]],columns=['c1','c2','c3'])
print(df)
print('*'*20)
for col in df:
print (col)

# 输出结果
c1 c2 c3
0 120 130 150
1 90 100 110
2 60 70 80
********************
c1
c2
c3

如果想要遍历DataFrame的每一行,我们下列函数:

  • iteritems():以键值对 (key,value) 的形式遍历;
  • iterrows():以 (row_index,row) 的形式遍历行;
  • itertuples():使用已命名元组的方式对行遍历。

iteritems()以键值对的形式遍历DataFrame对象,以列标签为键,以对应列的元素为值。

import pandas as pd
# 操作DataFrame
df = pd.DataFrame([[120,130,150],[90,100,110],[60,70,80]],columns=['c1','c2','c3'])
print(df)
print('*'*20)
for key,value in df.iteritems():
print(key)
print(value)

# 输出结果
c1 c2 c3
0 120 130 150
1 90 100 110
2 60 70 80
********************
c1
0 120
1 90
2 60
Name: c1, dtype: int64
c2
0 130
1 100
2 70
Name: c2, dtype: int64
c3
0 150
1 110
2 80
Name: c3, dtype: int64

iterrows()方法按行遍历,返回一个迭代器,以行索引标签为键,以每一行数据为值。

import pandas as pd
# 操作DataFrame
df = pd.DataFrame([[120,130,150],[90,100,110],[60,70,80]],columns=['c1','c2','c3'])
print(df)
print('*'*20)
# iterrows()遍历行,其中0,1,2是行索引而c1,c2,c3是列索引。
for row_index,value in df.iterrows():
print(row_index)
print(value)

# 输出结果
c1 c2 c3
0 120 130 150
1 90 100 110
2 60 70 80
********************
0
c1 120
c2 130
c3 150
Name: 0, dtype: int64
1
c1 90
c2 100
c3 110
Name: 1, dtype: int64
2
c1 60
c2 70
c3 80
Name: 2, dtype: int64

itertuples()同样将返回一个迭代器,该方法会把DataFrame每一行生成一个元组,示例如下:

import pandas as pd
# 操作DataFrame
df = pd.DataFrame([[120,130,150],[90,100,110],[60,70,80]],columns=['c1','c2','c3'])
print(df)
print('*'*20)
for row in df.itertuples():
print(row)

# 输出结果
c1 c2 c3
0 120 130 150
1 90 100 110
2 60 70 80
********************
Pandas(Index=0, c1=120, c2=130, c3=150)
Pandas(Index=1, c1=90, c2=100, c3=110)
Pandas(Index=2, c1=60, c2=70, c3=80)

迭代器返回的是原对象的副本,如果在迭代过程中修改元素值,不会影响原对象。

👀排序和去重

👁排序sorting

Pandas提供了两种排序方法,分别是按标签排序和按数值排序。

(1)按行标签排序

使用sort_index()方法对行标签排序,指定轴参数(axis)或者排序顺序。或者可以对DataFrame进行排序。默认情况下,按照行标签序排序。通过将布尔值传递给ascending参数,可以控制排序的顺序(行号顺序)。

import pandas as pd
import numpy as np
# 行标签乱序排列,列标签乱序排列
unsorted_df = pd.DataFrame(np.random.randn(6,2),index=[1,4,2,3,5,0],columns=['col2','col1'])
print(unsorted_df)
print('*'*20)
sorted_df1 = unsorted_df.sort_index()
print(sorted_df1)
print('*'*20)
sorted_df2 = unsorted_df.sort_index(ascending=False)
print(sorted_df2)

# 输出结果
col2 col1
1 -0.458463 0.422606
4 0.809682 2.489952
2 1.609935 0.096181
3 1.087255 1.215676
5 0.436520 0.389565
0 0.536720 0.820746
********************
col2 col1
0 0.536720 0.820746
1 -0.458463 0.422606
2 1.609935 0.096181
3 1.087255 1.215676
4 0.809682 2.489952
5 0.436520 0.389565
********************
col2 col1
5 0.436520 0.389565
4 0.809682 2.489952
3 1.087255 1.215676
2 1.609935 0.096181
1 -0.458463 0.422606
0 0.536720 0.820746

(2)按列标签排序

通过给axis轴参数传递0或1,可以对列标签进行排序。默认情况下,axis=0表示按行排序;而axis=1则表示按列排序。

import pandas as pd
import numpy as np
# 行标签乱序排列,列标签乱序排列
unsorted_df = pd.DataFrame(np.random.randn(6,2),index=[1,4,2,3,5,0],columns=['col2','col1'])
print(unsorted_df)
print('*'*20)
sorted_df1 = unsorted_df.sort_index(axis=1)
print(sorted_df1)

# 输出结果
col2 col1
1 0.891755 1.006258
4 0.232999 0.549146
2 0.158894 0.246825
3 0.653124 -1.695749
5 -0.774252 -0.525881
0 0.082147 0.384929
********************
col1 col2
1 1.006258 0.891755
4 0.549146 0.232999
2 0.246825 0.158894
3 -1.695749 0.653124
5 -0.525881 -0.774252
0 0.384929 0.082147

(3)按值排序

与标签排序类似,sort_values()表示按值排序。它接受一个by参数,该参数值是要排序数列的DataFrame列名。示例如下:

import pandas as pd
# 行标签乱序排列,列标签乱序排列
unsorted_df = pd.DataFrame({'col1':[2,1,1,1],'col2':[1,3,2,4]})
print(unsorted_df)
print('*'*20)
sorted_df1 = unsorted_df.sort_values(by='col1')
print(sorted_df1)
print('*'*20)
# 注意:当对col1列排序时,相应的col2列的元素值和行索引也会随col1一起改变。by参数可以接受一个列表参数值
sorted_df2 = unsorted_df.sort_values(by=['col1','col2'])
print(sorted_df2)

# 输出结果
col1 col2
0 2 1
1 1 3
2 1 2
3 1 4
********************
col1 col2
1 1 3
2 1 2
3 1 4
0 2 1
********************
col1 col2
2 1 2
1 1 3
3 1 4
0 2 1

(4)排序算法

sort_values()提供了参数kind用来指定排序算法。这里有三种排序算法:

  • mergesort
  • heapsort
  • quicksort

默认为quicksort(快速排序) ,其中Mergesort归并排序是最稳定的算法。

import pandas as pd
# 行标签乱序排列,列标签乱序排列
unsorted_df = pd.DataFrame({'col1':[2,1,1,1],'col2':[1,3,2,4]})
print(unsorted_df)
print('*'*20)
sorted_df1 = unsorted_df.sort_values(by='col1',kind='mergesort')
print(sorted_df1)

# 输出结果
col1 col2
0 2 1
1 1 3
2 1 2
3 1 4
********************
col1 col2
1 1 3
2 1 2
3 1 4
0 2 1

👁去重drop_duplicates()

“去重”通过字面意思不难理解,就是删除重复的数据。在一个数据集中,找出重复的数据删并将其删除,最终只保存一个唯一存在的数据项,这就是数据去重的整个过程。

Panda DataFrame对象提供了一个数据去重的函数drop_duplicates()

df.drop_duplicates(subset=['A','B','C'],keep='first',inplace=True)
参数说明如下:
subset:表示要进去重的列名,默认为None
keep:有三个可选参数,分别是first、last、False,默认为first,表示只保留第一次出现的重复项,删除其余重复项,last表示只保留最后一次出现的重复项,False则表示删除所有重复项。
inplace:布尔值参数,默认为False表示删除重复项后返回一个副本,若为Ture则表示直接在原数据上删除重复项。

删除重复项后,行标签使用的数字是原来的,并没有从0重新开始,那么我们应该怎么从0重置索引呢?Pandas提供的reset_index()函数会直接使用重置后的索引。

import pandas as pd
data = {'col1':[1,0,1,1],'col2':[0,2,5,0],'col3':[4,0,4,4],'col4':[1,0,1,1]}
df = pd.DataFrame(data)
print(df)
print('*'*20)
# 默认保留第一次出现的重复项,默认为first
print(df.drop_duplicates())
print('*'*20)
# keep=False删除所有重复项
df1 = df.drop_duplicates(keep=False)
print(df1)
print('*'*20)
# 重置索引,从0重新开始
print(df1.reset_index(drop=True))
print('*'*20)
# 指定多列同时去重
print(df.drop_duplicates(['col3','col4'],keep='last'))

# 输出结果
col1 col2 col3 col4
0 1 0 4 1
1 0 2 0 0
2 1 5 4 1
3 1 0 4 1
********************
col1 col2 col3 col4
0 1 0 4 1
1 0 2 0 0
2 1 5 4 1
********************
col1 col2 col3 col4
1 0 2 0 0
2 1 5 4 1
********************
col1 col2 col3 col4
0 0 2 0 0
1 1 5 4 1
********************
col1 col2 col3 col4
1 0 2 0 0
3 1 0 4 1

👀字符串处理

Pandas提供了一系列的字符串函数,因此能够很方便地对字符串进行处理。

函数名称 函数功能和描述
lower() 将的字符串转换为小写
upper() 将的字符串转换为大写
len() 得出字符串的长度
strip() 去除字符串两边的空格(包含换行符)
split() 用指定的分割符分割字符串
cat(sep="") 用给定的分隔符连接字符串元素
get_dummies() 返回一个带有独热编码值的DataFrame结构
contains(pattern) 如果子字符串包含在元素中,则为每个元素返回一个布尔值True,否则为False
replace(a,b) 将值a替换为值b
count(pattern) 返回每个字符串元素出现的次数
startswith(pattern) 如果Series中的元素以指定的字符串开头,则返回True
endswith(pattern) 如果Series中的元素以指定的字符串结尾,则返回True
findall(pattern) 以列表的形式返出现的字符串
swapcase() 交换大小写
islower() 返回布尔值,检查Series中组成每个字符串的所有字符是否都为小写
issupper() 返回布尔值,检查Series中组成每个字符串的所有字符是否都为大写
isnumeric() 返回布尔值,检查Series中组成每个字符串的所有字符是否都为数字
repeat(value) 以指定的次数重复每个元素
find(pattern) 返回字符串第一次出现的索引位置

注意:上述所有字符串函数全部适用于DataFrame对象,同时也可以与Python内置的字符串函数一起使用,这些函数在处理Series/DataFrame对象的时候会自动忽略缺失值数据(NaN)。

import pandas as pd
import numpy as np
s = pd.Series(['C ', ' Python', 'java', 'go', np.nan, '1125 ','javascript'])
print(s.str.lower)
print('*'*20)
print(s.str.len())
print('*'*20)
print(s.str.strip())
print('*'*20)
print(s.str.split(" "))
print('*'*20)
print(s.str.cat(sep="_"))
print('*'*20)
print(s.str.get_dummies())
print('*'*20)
print(s.str.contains(" "))
print('*'*20)
print(s.str.repeat(3))
print('*'*20)
print(s.str.startswith("j"))
print('*'*20)
# 如果返回-1表示该字符串中没有出现指定的字符
print(s.str.find("j"))
print('*'*20)
print(s.str.swapcase())
print('*'*20)
print(s.str.isnumeric())

# 输出结果
0 c
1 python
2 java
3 go
4 NaN
5 1125
6 javascript
dtype: object
********************
0 2.0
1 7.0
2 4.0
3 2.0
4 NaN
5 5.0
6 10.0
dtype: float64
********************
0 C
1 Python
2 java
3 go
4 NaN
5 1125
6 javascript
dtype: object
********************
0 [C, ]
1 [, Python]
2 [java]
3 [go]
4 NaN
5 [1125, ]
6 [javascript]
dtype: object
********************
C _ Python_java_go_1125 _javascript
********************
Python 1125 C go java javascript
0 0 0 1 0 0 0
1 1 0 0 0 0 0
2 0 0 0 0 1 0
3 0 0 0 1 0 0
4 0 0 0 0 0 0
5 0 1 0 0 0 0
6 0 0 0 0 0 1
********************
0 True
1 True
2 False
3 False
4 NaN
5 True
6 False
dtype: object
********************
0 C C C
1 Python Python Python
2 javajavajava
3 gogogo
4 NaN
5 1125 1125 1125
6 javascriptjavascriptjavascript
dtype: object
********************
0 False
1 False
2 True
3 False
4 NaN
5 False
6 True
dtype: object
********************
0 -1.0
1 -1.0
2 0.0
3 -1.0
4 NaN
5 -1.0
6 0.0
dtype: float64
********************
0 c
1 pYTHON
2 JAVA
3 GO
4 NaN
5 1125
6 JAVASCRIPT
dtype: object
********************
0 False
1 False
2 False
3 False
4 NaN
5 False
6 False
dtype: object

👀设置数据显示格式

在用Pandas做数据分析的过程中,总需要打印数据分析的结果,如果数据体量较大就会存在输出内容不全(部分内容省略)或者换行错误等问题。Pandas为了解决上述问题,允许你对数据显示格式进行设置。下面列出了五个用来设置显示格式的函数,分别是:

函数名称 说明
get_option() 获取解释器的默认参数值
set_option() 更改解释器的默认参数值
reset_option() 解释器的参数重置为默认值
describe_option() 输出参数的描述信息
option_context() 临时设置解释器参数,当退出使用的语句块时,恢复为默认值

上述函数常用的参数项:

参数 说明
display.max_rows 最大显示行数,超过该值用省略号代替,为None时显示所有行
display.max_columns 最大显示列数,超过该值用省略号代替,为None时显示所有列
display.expand_frame_repr 输出数据宽度超过设置宽度时,表示是否对其要折叠,False不折叠,True要折叠
display.max_colwidth 单列数据宽度,以字符个数计算,超过时用省略号表示
display.precision 设置输出数据的小数点位数
display.width 数据显示区域的宽度,以总字符数计算
display.show_dimensions 当数据量大需要以truncate(带引号的省略方式)显示时,该参数表示是否在最后显示数据的维数,默认True显示,False不显示。

👀loc和iloc用法详解

在数据分析过程中,很多时候需要从数据表中提取出相应的数据,而这么做的前提是需要先“索引”出这一部分数据。虽然通过Python提供的索引操作符"[]"和属性操作符"."可以访问Series或者DataFrame中的数据,但这种方式只适应与少量的数据,为了解决这一问题,Pandas提供了两种类型的索引方式来实现数据的访问。

方法名称 说明
.loc[] 基于标签索引选取数据
.iloc[] 基于整数索引选取数据

df.loc[]只能使用标签索引,不能使用整数索引。当通过标签索引的切片方式来筛选数据时,它的取值前闭后闭,也就是只包括边界值标签(开始和结束)。

.loc[]具有多种访问方法,如下所示:

  • 一个标量标签
  • 标签列表
  • 切片对象
  • 布尔数组

loc[]接受两个参数,并以','分隔。第一个位置表示行,第二个位置表示列。

import pandas as pd

data = {
"name": ['Tom', 'Rose', 'Mike', 'Twg'],
"calories": [420, 380, 390, 500],
"duration": [50, 40, 45, 60]
}
# 数据载入到 DataFrame 对象
df = pd.DataFrame(data, index = ['a', 'b', 'c', 'd'])
print(df)
print('*'*20)
# 对行操作,等同于df.loc['a':'b']
print(df.loc['a':'b',:])
print('*'*20)
# 对列操作
print(df.loc[:,'name'])
print('*'*20)
# 对行、列操作
print(df.loc[['a','d'],['name','duration']])
print('*'*20)
# 布尔值操作
print(df.loc[:,'duration'] > 45)

# 输出结果
name calories duration
a Tom 420 50
b Rose 380 40
c Mike 390 45
d Twg 500 60
********************
name calories duration
a Tom 420 50
b Rose 380 40
********************
a Tom
b Rose
c Mike
d Twg
Name: name, dtype: object
********************
name duration
a Tom 50
d Twg 60
********************
a True
b False
c False
d True
Name: duration, dtype: bool

df.iloc[]只能使用整数索引,不能使用标签索引,通过整数索引切片选择数据时,前闭后开(不包含边界结束值)。同PythonNumPy一样,它们的索引都是从0开始。

.iloc[]提供了以下方式来选择数据:

  • 整数索引
  • 整数列表
  • 数值范围
import pandas as pd

data = {
"name": ['Tom', 'Rose', 'Mike', 'Twg'],
"calories": [420, 380, 390, 500],
"duration": [50, 40, 45, 60]
}
# 数据载入到 DataFrame 对象
df = pd.DataFrame(data, index = ['a', 'b', 'c', 'd'])
print(df)
print('*'*20)
print(df.iloc[2:,:])
print('*'*20)
print(df.iloc[[0,2],[1,2]])
print('*'*20)
print(df.iloc[:,:2])

# 输出结果
name calories duration
a Tom 420 50
b Rose 380 40
c Mike 390 45
d Twg 500 60
********************
name calories duration
c Mike 390 45
d Twg 500 60
********************
calories duration
a 420 50
c 390 45
********************
name calories
a Tom 420
b Rose 380
c Mike 390
d Twg 500

👀日期时间操作

👁Pandas时间序列

顾名思义,时间序列(time series),就是由时间构成的序列,它指的是在一定时间内按照时间顺序测量的某个变量的取值序列,比如一天内的温度会随时间而发生变化,或者股票的价格会随着时间不断的波动,这里用到的一系列时间,就可以看做时间序列。时间序列包含三种应用场景,分别是:

  • 特定的时刻(timestamp),也就是时间戳;
  • 固定的日期(period),比如某年某月某日;
  • 时间间隔(interval),每隔一段时间具有规律性;

在处理时间序列的过程中,我们一般会遇到两个问题,第一,如何创建时间序列;第二,如何更改已生成时间序列的频率。 Pandas为解决上述问题提供了一套简单、易用的方法。

# Python内置的datetime模块来获取当前时间,通过该模块提供的now()方法即可实现。
from datetime import datetime
# 数据类型为datetime
print(datetime.now())

# 输出结果
2023-03-19 17:42:39.528176

创建时间戳:TimeStamp(时间戳) 是时间序列中的最基本的数据类型,它将数值与时间点完美结合在一起。

创建时间间隔:通过date_range()方法可以创建某段连续的时间或者固定间隔的时间时间段。该函数提供了三个参数,分别是:start开始时间;end结束时间;freq时间频率,默认为 “D”(天)。

import pandas as pd
# 创建时间戳
print(pd.Timestamp('2023-03-16'))
# 可以将整型或浮点型表示的时间转换为时间戳。默认的单位是纳秒(时间戳单位)
print(pd.Timestamp(1687687255,unit='s'))
print('*'*20)
# 创建时间范围,freq表示时间频率,每30min变化一次
print(pd.date_range("9:00", "18:10", freq="30min").time)
# 修改为按小时
print(pd.date_range("9:00", "18:10", freq="H").time)
print('*'*20)
# 使用to_datetime()函数将series或list转换为日期对象,其中list会转换为DatetimeIndex
# 输出中,注意:NaT表示的不是时间 ,它等效于NaN
# 传入series,生成Datetimeindex
print(pd.to_datetime(pd.Series(['Jun 3, 2020','2020-12-10', None])))
# 传入list,生成Datetimeindex
print(pd.to_datetime(['Jun 30, 2020','2020-12-10', None]))

# 输出结果
2023-03-16 00:00:00
2023-06-25 10:00:55
********************
[datetime.time(9, 0) datetime.time(9, 30) datetime.time(10, 0)
datetime.time(10, 30) datetime.time(11, 0) datetime.time(11, 30)
datetime.time(12, 0) datetime.time(12, 30) datetime.time(13, 0)
datetime.time(13, 30) datetime.time(14, 0) datetime.time(14, 30)
datetime.time(15, 0) datetime.time(15, 30) datetime.time(16, 0)
datetime.time(16, 30) datetime.time(17, 0) datetime.time(17, 30)
datetime.time(18, 0)]
[datetime.time(9, 0) datetime.time(10, 0) datetime.time(11, 0)
datetime.time(12, 0) datetime.time(13, 0) datetime.time(14, 0)
datetime.time(15, 0) datetime.time(16, 0) datetime.time(17, 0)
datetime.time(18, 0)]
********************
0 2020-06-03
1 2020-12-10
2 NaT
dtype: datetime64[ns]
DatetimeIndex(['2020-06-30', '2020-12-10', 'NaT'], dtype='datetime64[ns]', freq=None)

频率和周期转换:Time Periods表示时间跨度,一段时间周期,它被定义在Pandas Periods类中,通过该类提供的方法可以实现将频率转换为周期。比如Periods()方法,可以将频率 “M“(月)转换为 Period(时间段)。使用asfreq()start参数,打印 “01“ ,若使用end参数,则打印 “31“。对于常用的时间序列频率,Pandas为其规定了一些字符串别名,我们将这些别名称为“offset(偏移量)”。

别名 描述 别名 描述
B 工作日频率 BQS 工作季度开始频率
D 日历日频率 A 年终频率
W 每周频率 BA 工作年度结束频率
M 月末频率 BAS 工作年度开始频率
SM 半月结束频率 BH 营业时间频率
BM 工作月结束频率 H 小时频率
MS 月开始频率 T,min 每分钟频率
SMS 半月开始频率 S 每秒钟频率
BMS 工作月开始频率 L,ms 毫秒
Q 季末频率 U,us 微秒
BQ 工作季度结束频率 N 纳秒
QS 季度开始频率

周期计算:指的是对时间周期进行算术运算,所有的操作将在“频率”的基础上执行。

创建时间周期:可以使用period_range()方法来创建时间周期范围。

时间序列转换:如果想要把字符串日期转换为Period,首先需要将字符串转换为日期格式,然后再将日期转换为Period

import pandas as pd 
# S表示秒
x = pd.Period('2014', freq='S')
print(x)
# 加1s的时间
print(x+1)
# 使用period_range()方法来创建时间周期范围
p = pd.period_range('2016','2018', freq='Y')
print(p)

# 输出结果
2014-01-01 00:00:00
2014-01-01 00:00:01
PeriodIndex(['2016', '2017', '2018'], dtype='period[A-DEC]', freq='A-DEC')

👁日期时间格式化

当进行数据分析时,我们会遇到很多带有日期、时间格式的数据集,在处理这些数据集时,可能会遇到日期格式不统一的问题,此时就需要对日期时间做统一的格式化处理。比如”Wednesday, June 6, 2020“可以写成”6/6/20“,或者写成”06-06-2020“。

(1)日期格式化符号

在对时间进行格式化处理时,它们都有固定的表示格式,比如小时的格式化符号为%H ,分钟简写为%M ,秒简写为%S

符号 说明 符号 说明
%y 两位数的年份表示(00-99) %Y 四位数的年份表示(000-9999)
%m 月份(01-12) %d 月内中的一天(0-31)
%H 24小时制小时数(0-23) %I 12小时制小时数(01-12)
%M 分钟数(00=59) %S 秒(00-59)
%a 本地英文缩写星期名称 %A 本地英文完整星期名称
%b 本地缩写英文的月份名称 %B 本地完整英文的月份名称
%w 星期(0-6),星期天为星期的开始 %W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示 %X 本地相应的时间表示
%Z 当前时区的名称 %U 一年中的星期数(00-53)星期天为星期的开始
%j 年内的一天(001-366) %c 本地相应的日期表示和时间表示

(2)日期格式化处理函数

Python内置的strptime()方法能够将字符串日期转换为datetime类型。

from datetime import datetime
# 将日期定义为字符串
date_str1 = 'Wednesday,July 18,2020'
date_str2 = '18/7/20'
date_str3 = '18-07-2020'
# 将日期转化为datetime对象
dmy_dt1 = datetime.strptime(date_str1, '%A,%B %d,%Y')
dmy_dt2 = datetime.strptime(date_str2, '%d/%m/%y')
dmy_dt3 = datetime.strptime(date_str3, '%d-%m-%Y')
# 处理为相同格式,并打印输出
print(dmy_dt1)
print(dmy_dt2)
print(dmy_dt3)

# 输出结果
2020-07-18 00:00:00
2020-07-18 00:00:00
2020-07-18 00:00:00

除了使用Python内置的strptime()方法外,你还可以使用Pandas模块的pd.to_datetime()pd.DatetimeIndex()进行转换。

import pandas as pd
import numpy as np
# 通过to_datetime()直接转换为 datetime 类型
date1 = ['2012-05-06 11:00:00','2012-05-16 11:00:00']
pd_date1 = pd.to_datetime(date1)
df1 = pd.Series(np.random.randn(2),index=pd_date1)
print(pd_date1)
print(df1)
print('*'*20)
# 使用Datetimeindex()函数设置时间序
date2 = pd.DatetimeIndex(['1/1/2008', '1/2/2008', '1/3/2008', '1/4/2008', '1/5/2008'])
dt2 = pd.DataFrame(np.random.randn(5),index=date2, columns=['value'])
print(date2)
print(dt2)

# 输出结果
DatetimeIndex(['2012-05-06 11:00:00', '2012-05-16 11:00:00'], dtype='datetime64[ns]', freq=None)
2012-05-06 11:00:00 2.115566
2012-05-16 11:00:00 -0.145139
dtype: float64
********************
DatetimeIndex(['2008-01-01', '2008-01-02', '2008-01-03', '2008-01-04',
'2008-01-05'],
dtype='datetime64[ns]', freq=None)
value
2008-01-01 0.828022
2008-01-02 -1.873516
2008-01-03 1.940921
2008-01-04 1.563612
2008-01-05 0.964914

👁Timedelta时间差

Timedelta表示时间差(或者时间增量),我们可以使用不同的时间单位来表示它,比如,天、小时、分、秒。时间差的最终的结果可以是正时间差,也可以是负时间差。

import pandas as pd
import numpy as np
# 通过传递字符串可以创建Timedelta对象
print(pd.Timedelta('5 days 8 hours 6 minutes 59 seconds'))
# 通过传递整数值和unit参数也可以创建一个Timedelta对象。
print(pd.Timedelta(19,unit='h'))
# 数据偏移量, 比如,周(weeks)、天(days)、小时(hours)、分钟(minutes)、秒(milliseconds)、毫秒、微秒、纳秒都可以使用。
print(pd.Timedelta(days=2,hours=6))
print('*'*20)
# 您可以使用pd.to_timedelta()方法,将具有timedelta格式的值 (标量、数组、列表或Series)转换为Timedelta类型。如果输入是Series,则返回Series;如果输入是标量,则返回值也为标量,其他情况输出TimedeltaIndex。
print(pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan']))
print(pd.to_timedelta(np.arange(5), unit='s'))

# 输出结果
5 days 08:06:59
0 days 19:00:00
2 days 06:00:00
********************
TimedeltaIndex(['1 days 06:05:01.000030', '0 days 00:00:00.000015', NaT], dtype='timedelta64[ns]', freq=None)
TimedeltaIndex(['00:00:00', '00:00:01', '00:00:02', '00:00:03', '00:00:04'], dtype='timedelta64[ns]', freq=None)

通过对datetime64[ns]类型的时间序列或时间戳做算术运算,其运算结果依然是datetime64[ns]数据类型。接下来,我们创建一个带有TimedeltadatetimeDataFrame对象,并对其做一些算术运算。

import pandas as pd
s = pd.Series(pd.date_range('2020-1-1', periods=5, freq='D'))
# 推导式用法
td = pd.Series([ pd.Timedelta(days=i) for i in range(5)])
df = pd.DataFrame(dict(A = s, B = td))
print(df)
print('*'*20)
# 加法运算
df['C']=df['A']+df['B']
print(df)
print('*'*20)
# 减法运算
df['D']=df['C']-df['B']
print(df)

# 输出结果
A B
0 2020-01-01 0 days
1 2020-01-02 1 days
2 2020-01-03 2 days
3 2020-01-04 3 days
4 2020-01-05 4 days
********************
A B C
0 2020-01-01 0 days 2020-01-01
1 2020-01-02 1 days 2020-01-03
2 2020-01-03 2 days 2020-01-05
3 2020-01-04 3 days 2020-01-07
4 2020-01-05 4 days 2020-01-09
********************
A B C D
0 2020-01-01 0 days 2020-01-01 2020-01-01
1 2020-01-02 1 days 2020-01-03 2020-01-02
2 2020-01-03 2 days 2020-01-05 2020-01-03
3 2020-01-04 3 days 2020-01-07 2020-01-04
4 2020-01-05 4 days 2020-01-09 2020-01-05

👀数据样本处理

👁Pandas缺失值处理

稀疏数据,指的是在数据库或者数据集中存在大量缺失数据或者空值,我们把这样的数据集称为稀疏数据集。稀疏数据不是无效数据,只不过是信息不全而已,只要通过适当的方法就可以“变废为宝”。

检查缺失值Pandas提供了isnull()notnull()两个函数,它们同时适用于SeriesDataFrame对象。

缺失数据计算:计算缺失数据时,需要注意两点:首先数据求和时,将NA值视为0,其次,如果要计算的数据为NA,那么结果就是NA。

清理并填充缺失值Pandas提供了多种方法来清除缺失值。fillna()函数可以实现用非空数据“填充”NaN值;ffill()向前填充和bfill()向后填充,使用这两个函数也可以处理NA值。replace()DataFrame中的通用值替换成特定值。

删除缺失值:使用dropna()函数与参数axis可以实现删除缺失值。在默认情况下,按照axis=0来按行处理,这意味着如果某一行中存在NaN值将会删除整行数据。

👁Pandas随机样本选择

随机抽样,是统计学中常用的一种方法,它可以帮助我们从大量的数据中快速地构建出一组数据分析模型。在Pandas中,如果想要对数据集进行随机抽样,需要使用sample()函数。该函数返回与数据集类型相同的新对象,相当于numpy.random.choice()

DataFrame.sample(n=None,frac=None,replace=False,weights=None,random_state=None,axis=None)
参数说明
n 表示要抽取的行数。
frac 表示抽取的比例,比如frac=0.5,代表抽取总体数据的50%。
replace 布尔值参数,表示是否以有放回抽样的方式进行选择,默认为False,取出数据后不再放回。
weights 可选参数,代表每个样本的权重值,参数值是字符串或者数组。
random_state 可选参数,控制随机状态,默认为None,表示随机数据不会重复;若为1表示会取得重复数据。
axis 表示在哪个方向上抽取数据(axis=1表示列/axis=0表示行)。

👁Pandas数据重采样

数据重采样是将时间序列从一个频率转换至另一个频率的过程,它主要有两种实现方式,分别是降采样和升采样,降采样指将高频率的数据转换为低频率,升采样则与其恰好相反,说明如下:

方法 说明
降采样 将高频率(间隔短)数据转换为低频率(间隔长)。
升采样 将低频率数据转换为高频率。

Pandas提供了resample()函数来实现数据的重采样。

asfreq()方法不仅能够实现频率转换,还可以保留原频率对应的数值,同时它也可以单独使用。

插值处理,升采样的结果会产生缺失值,那么就需要对缺失值进行处理,一般有以下几种处理方式:

方法 说明
pad/ffill 用前一个非缺失值去填充缺失值。
backfill/bfill 用后一个非缺失值去填充缺失值。
interpolater('linear') 线性插值方法。
fillna(value) 指定一个值去替换缺失值。

👁Pandas分类对象

通常情况下,数据集中会存在许多同一类别的信息,比如相同国家、相同行政编码、相同性别等,当这些相同类别的数据多次出现时,就会给数据处理增添许多麻烦,导致数据集变得臃肿,不能直观、清晰地展示数据。

Pandas提供了分类对象(Categorical Object),该对象能够实现有序排列、自动去重的功能,但是它不能执行运算。通过Category的构造函数,您可以创建一个类别对象。

pandas.Categorical(values, categories, ordered)
参数说明
values:以列表的形式传参,表示要分类的值。
ordered:布尔值,默认为False,若为Ture,表示对分类的数据进行排序。
dtype:返回一个category类型,表示分类对象。

describe():对已经分类的数据使用describe()方法,得到和数据统计相关的摘要信息。

categories:使用obj.categories命令可以获取对象的类别信息。

Series.cat.categories:对类别实现重命名。

Series.cat.add_categories():追加新类别。

Series.cat.remove_categories():删除不需要的类别。

👀其它函数

👁Pandas统计函数

Pandas的本质是统计学原理在计算机领域的一种应用实现,通过编程的方式达到分析、描述数据的目的。而统计函数则是统计学中用于计算和分析数据的一种工具。在数据分析的过程中,使用统计函数有助于我们理解和分析数据。常见的统计函数,比如百分比函数、协方差函数、相关系数等。

  • pct_change()SeriesDatFrames都可以使用pct_change()函数。该函数将每个元素与其前一个元素进行比较,并计算前后数值的百分比变化。默认情况下,pct_change()对列进行操作,如果想要操作行,则需要传递参数axis=1参数。
  • cov()Series对象提供了一个cov方法用来计算Series对象之间的协方差。同时,该方法也会将缺失值(NAN)自动排除。当应用于DataFrame时,协方差(cov)将计算所有列之间的协方差。
  • corr():相关系数显示任意两个Series之间的线性关系。Pandas提供了计算相关性的三种方法,分别是pearson(default)spearman()kendall()。注意:如果DataFrame存在非数值(NAN),该方法会自动将其删除。
  • rank() :按照某种规则(升序或者降序)对序列中的元素值排名,该函数的返回值的也是一个序列,包含了原序列中每个元素值的名次。如果序列中包含两个相同的的元素值,那么会为其分配两者的平均排名。

👁Pandas窗口函数

为了能更好地处理数值型数据,Pandas提供了几种窗口函数:

  • 移动函数(rolling
  • 扩展函数(expanding
  • 指数加权函数(ewm

窗口是一种形象化的叫法,这些函数在执行操作时,就如同窗口一样在数据区间上移动。

如何在DataFrameSeries对象上应用窗口函数:

  • rolling() :移动窗口函数,它可以与meancountsummedianstd等聚合函数一起使用。

    rolling(window=n, min_periods=None, center=False)
    参数说明
    window 默认值为1,表示窗口的大小,也就是观测值的数量,
    min_periods 表示窗口的最小观察值,默认与window的参数值相等。
    center 是否把中间值做为窗口标准,默认值为False
  • expanding() :扩展窗口函数,扩展是指由序列的第一个元素开始,逐个向后计算元素的聚合值。

  • ewm():(全称 Exponentially Weighted Moving)表示指数加权移动。ewn()函数先会对序列元素做指数加权运算,其次计算加权后的均值。该函数通过指定comspan或者halflife参数来实现指数加权移动。

在数据分析的过程中,使用窗口函数能够提升数据的准确性,并且使数据曲线的变化趋势更加平滑,从而让数据分析变得更加准确、可靠。

👁Pandas聚合函数

窗口函数可以与聚合函数一起使用,聚合函数指的是对一组数据求总和、最大值、最小值以及平均值的操作,本节重点讲解聚合函数的应用。

import pandas as pd
import numpy as np

data = {'col1':[1,0,1,1],'col2':[0,2,5,0],'col3':[4,0,4,4],'col4':[1,0,1,1]}
df = pd.DataFrame(data)
print(df)
print("*"*20)
# 窗口大小为3,min_periods最小观测值为1
r1 = df.rolling(window=3,min_periods=1)
# min_periods默认与window的参数值相等
r2 = df.rolling(window=3)
print(r1.sum())
print(r2.sum())
print("*"*20)
# 把一个聚合函数传递给DataFrame
# 对整体聚合,使用aggregate()聚合操作
print(r1.aggregate(np.sum))
print("*"*20)
# 对任意某一列聚合
print(r1['col1'].aggregate(np.sum))
print("*"*20)
# 对多列数据聚合
print(r1['col1','col2'].aggregate(np.sum))
print("*"*20)
# 对单列应用多个函数
print(r1['col1'].aggregate([np.sum,np.mean]))
print("*"*20)
# 对不同列应用多个函数
print(r1['col1','col2'].aggregate([np.sum,np.mean]))
print("*"*20)
# 对不同列应用不同函数
print(r1.aggregate({'col1':np.sum,'col2':np.mean}))

# 输出结果
col1 col2 col3 col4
0 1 0 4 1
1 0 2 0 0
2 1 5 4 1
3 1 0 4 1
********************
col1 col2 col3 col4
0 1.0 0.0 4.0 1.0
1 1.0 2.0 4.0 1.0
2 2.0 7.0 8.0 2.0
3 2.0 7.0 8.0 2.0
col1 col2 col3 col4
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 2.0 7.0 8.0 2.0
3 2.0 7.0 8.0 2.0
********************
col1 col2 col3 col4
0 1.0 0.0 4.0 1.0
1 1.0 2.0 4.0 1.0
2 2.0 7.0 8.0 2.0
3 2.0 7.0 8.0 2.0
********************
0 1.0
1 1.0
2 2.0
3 2.0
Name: col1, dtype: float64
********************
col1 col2
0 1.0 0.0
1 1.0 2.0
2 2.0 7.0
3 2.0 7.0
********************
sum mean
0 1.0 1.000000
1 1.0 0.500000
2 2.0 0.666667
3 2.0 0.666667
********************
col1 col2
sum mean sum mean
0 1.0 1.000000 0.0 0.000000
1 1.0 0.500000 2.0 1.000000
2 2.0 0.666667 7.0 2.333333
3 2.0 0.666667 7.0 2.333333
********************
col1 col2
0 1.0 0.000000
1 1.0 1.000000
2 2.0 2.333333
3 2.0 2.333333

👁groupby分组操作

在数据分析中,经常会遇到这样的情况:根据某一列(或多列)标签把数据划分为不同的组别,然后再对其进行数据分析。比如,某网站对注册用户的性别或者年龄等进行分组,从而研究出网站用户的画像(特点)。在Pandas 中,要完成数据的分组操作,需要使用groupby()函数,它和SQLGROUP BY操作非常相似。 在划分出来的组(group)上应用一些统计函数,从而达到数据分析的目的,比如对分组数据进行聚合、转换,或者过滤。这个过程主要包含以下三步:

  • 拆分(Spliting):表示对数据进行分组;
  • 应用(Applying):对分组数据应用聚合函数,进行相应计算;
  • 合并(Combining):最后汇总计算结果。

使用groupby()可以沿着任意轴分组。您可以把分组时指定的键(key)作为每组的组名,方法如下所示:

  • df.groupby("key")
  • df.groupby("key",axis=1)
  • df.groupby(["key1","key2"])
import pandas as pd
import numpy as np
data = {'name': ['John', 'Helen', 'John', 'Ella'],
'score': [82, 98, 91, 87],
'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
print(df)
print("*"*20)
# 生成分组groupby对象
print(df.groupby('score'))
print("*"*20)
# 查看分组,通过调用groups属性查看分组结果
print(df.groupby('score').groups)
print("*"*20)
# 多个列标签分组
print(df.groupby(['name','score']).groups)
print("*"*20)
# 通过 get_group()方法可以选择组内的具体数据项
print(df.groupby('score').get_group(91))
print("*"*20)
# 遍历分组数据
grouped=df.groupby('score')
for label, option_course in grouped:
# 其中key代表分组后字典的键,也就是score
print(label)
# 字典对应的值选修的科目
print(option_course)
print("*"*20)
# 通过agg()函数可以对分组对象应用多个聚合函数
grouped_name = df.groupby('name')
# 应用一个聚合函数求均值
print(grouped_name['score'].agg(np.mean))
# 应用多个聚合函数求均值
print(grouped_name['score'].agg([np.size,np.mean,np.std]))
print("*"*20)
# 组的数据过滤操作,筛选出名字出现超过两次的人名
print(grouped_name.filter(lambda x: len(x) >= 2))

# 输出结果
name score option_course
0 John 82 C#
1 Helen 98 Python
2 John 91 Java
3 Ella 87 C
********************
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001CB3F4CD948>
********************
{82: Int64Index([0], dtype='int64'), 87: Int64Index([3], dtype='int64'), 91: Int64Index([2], dtype='int64'), 98: Int64Index([1], dtype='int64')}
********************
{('Ella', 87): Int64Index([3], dtype='int64'), ('Helen', 98): Int64Index([1], dtype='int64'), ('John', 82): Int64Index([0], dtype='int64'), ('John', 91): Int64Index([2], dtype='int64')}
********************
name score option_course
2 John 91 Java
********************
82
name score option_course
0 John 82 C#
87
name score option_course
3 Ella 87 C
91
name score option_course
2 John 91 Java
98
name score option_course
1 Helen 98 Python
********************
name
Ella 87.0
Helen 98.0
John 86.5
Name: score, dtype: float64
size mean std
name
Ella 1 87.0 NaN
Helen 1 98.0 NaN
John 2 86.5 6.363961
********************
name score option_course
0 John 82 C#
2 John 91 Java

组的转换操作:通过transform()函数可以实现组的转换,在组的行或列上可以执行转换操作,最终会返回一个与组大小相同的索引对象。

组的数据过滤操作:通过filter()函数可以实现数据的筛选,该函数根据定义的条件过滤数据并返回一个新的数据集。

👁merge合并操作

Pandas提供的merge()函数能够进行高效的合并操作,这与SQL关系型数据库的MERGE用法非常相似。从字面意思上不难理解,merge翻译为“合并”,指的是将两个DataFrame数据表按照指定的规则进行连接,最后拼接成一个新的DataFrame数据表。merge()函数的法格式如下:

pd.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)

参数说明
left/right: 两个不同的DataFrame对象。
on: 指定用于连接的键(即列标签的名字),该键必须同时存在于左右两个DataFrame中,如果没有指定,并且其他参数也未指定, 那么将会以两个DataFrame的列名交集做为连接键。
left_on: 指定左侧DataFrame中作连接键的列名。该参数在左、右列标签名不相同,但表达的含义相同时非常有用。
right_on: 指定左侧DataFrame中作连接键的列名。
left_index: 布尔参数,默认为False。如果为True 则使用左侧DataFrame的行索引作为连接键,若DataFrame具有多层索引(MultiIndex),则层的数量必须与连接键的数量相等。
right_index: 布尔参数,默认为False。如果为True 则使用左侧DataFrame的行索引作为连接键。
how: 要执行的合并类型,从{'left','right','outer','inner'} 中取值,默认为“inner”内连接。
sort: 布尔值参数,默认为True,它会将合并后的数据进行排序;若设置为False,则按照how给定的参数值进行排序。
suffixes: 字符串组成的元组。当左右DataFrame存在相同列名时,通过该参数可以在相同的列名后附加后缀名,默认为('_x','_y')。
copy: 默认为True,表示对数据进行复制。

注意:Pandas库的merge()支持各种内外连接,与其相似的还有join()函数(默认为左连接)。

👁concat连接操作

Pandas通过concat()函数能够轻松地将SeriesDataFrame对象组合在一起,函数的语法格式如下:

pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False)

参数说明
objs: 一个序列或者是Series、DataFrame对象。
axis: 表示在哪个轴方向上(行或者列)进行连接操作,默认axis=0表示行方向。
join: 指定连接方式,取值为{"inner","outer"},默认为outer表示取并集,inner代表取交集。
ignore_index: 布尔值参数,默认为False,如果为True,表示不在连接的轴上使用索引。
join_axes: 表示索引对象的列表。

append(): 如果要连接SeriesDataFrame对象,有一个最方便、快捷的方法,就是append()方法。该方法沿着axis=0(行方向)进行操作;append()函数也可接收多个对象。

👀Pandas绘图

PandasMatplotlib绘图软件包的基础上单独封装了一个plot()接口,通过调用该接口可以实现常用的绘图操作。

import pandas as pd
import numpy as np
# 创建包含时间序列的数据
df = pd.DataFrame(np.random.randn(8,4),index=pd.date_range('2/1/2020',periods=8), columns=list('ABCD'))
df.plot()
# 如果行索引中包含日期,Pandas会自动调用gct().autofmt_xdate()来格式化x轴。

除了使用默认的线条绘图外,您还可以使用其他绘图方式,如下所示:

  • 柱状图:bar()barh()
  • 直方图:hist()
  • 箱状箱:box()
  • 区域图:area()
  • 散点图:scatter()

通过关键字参数kind可以把上述方法传递给plot()

(1)柱状图

import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.rand(10,4),columns=['a','b','c','d'])
# 或使用df.plot(kind="bar")
df.plot.bar()
# 通过设置参数stacked=True可以生成柱状堆叠图
# 或者使用df.plot.bar(stacked="True")
df.plot(kind="bar",stacked=True)
# 如果要绘制水平柱状图
df.plot.barh(stacked=True)

(2)直方图

plot.hist()可以实现绘制直方图,并且它还可以指定bins(构成直方图的箱数)。

import pandas as pd
import numpy as np
df = pd.DataFrame({'A':np.random.randn(100)+2,'B':np.random.randn(100),'C':np.random.randn(100)-2,'D':np.random.randn(100)+3},columns=['A', 'B', 'C','D'])
print(df)
# 指定箱数为15
df.plot.hist(bins=15)
# 给每一列数据都绘制一个直方图
df.diff().hist(color="r",alpha=0.5,bins=15)

(3)箱线图

通过调用Series.box.plot()DataFrame.box.plot()或者DataFrame.boxplot()方法来绘制箱型图,它将每一列数据的分布情况,以可视化的图像展现出来。

import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.rand(10, 4), columns=['A', 'B', 'C', 'D'])
df.plot.box()

(4)区域图

使用Series.plot.area()DataFrame.plot.area()方法来绘制区域图。

import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.rand(5, 4), columns=['a', 'b', 'c', 'd'])
df.plot.area()

(5)散点图

使用DataFrame.plot.scatter()方法来绘制散点图。

import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.rand(30, 4), columns=['a', 'b', 'c', 'd'])
df.plot.scatter(x='a',y='b')

(6)饼状图

通过DataFrame.plot.pie()方法来绘制。

import pandas as pd
import numpy as np
df = pd.DataFrame(3 * np.random.rand(4), index=['go', 'java', 'c++', 'c'], columns=['L'])
df.plot.pie(subplots=True)

⛄Pandas和NumPy的比较

PandasNumPy被认为是科学计算与机器学习中必不可少的库,因为它们具有直观的语法和高性能的矩阵计算能力。

比较项 Pandas NumPy
适应性 Pandas主要用来处理类表格数据。 NumPy主要用来处理数值数据。
工具 Pandas提供了SeriesDataFrame数据结构。 NumPy构建了ndarray array来容纳数据。
性能 Pandas对于处理50万行以上的数据更具优势。 NumPy则对于50万以下或者更少的数据,性能更佳。
内存利用率 NumPy相比,Pandas会消耗大量的内存。 NumPy会消耗较少的内存。
对象 Pandas提供了DataFrame 2D数据表对象。 NumPy则提供了一个多维数组ndarray对象

在某些情况下,需要执行一些NumPy数值计算的高级函数,这个时候您可以使用to_numpy()函数,将DataFrame对象转换为NumPy ndarray数组,并将其返回。

DataFrame.to_numpy(dtype=None, copy=False)   
参数说明如下:
dtype:可选参数,表示数据类型;
copy:布尔值参数,默认值为 Fales,表示返回值不是其他数组的视图。

import pandas as pd
#创建DataFrame对象
info = pd.DataFrame([[17,62,35],[25,36,54],[42,20,15],[48,62,76]], columns=['x','y','z'])
print('DataFrame\n----------\n', info)
#转换DataFrame为数组array
arr = info.to_numpy()
print('\nNumpy Array\n----------\n', arr)

# 输出结果
DataFrame
----------
x y z
0 17 62 35
1 25 36 54
2 42 20 15
3 48 62 76

Numpy Array
----------
[[17 62 35]
[25 36 54]
[42 20 15]
[48 62 76]]