Python之Pandas详解

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:拷贝数据,默认为Falseimport 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]]

多谢!多谢!
笔者不才,请多交流!!!

欢迎大家关注预览我的博客Blog:HeartLoveLife
能力有限,敬请谅解!!

你可能感兴趣的:(Python,Python基础,python,pandas,开发语言)