Pandas
Pandas 包在 Numpy 数组的基础上添加了与 Excel 类似的行列标签。
对象的创建
- 导入 Pandas 时,通常给其一个别名 "pd",即
import pandas as pd - 作为标签库,Pandas 对象在 Numpy 数组基础上给予其行列标签,可以说,列表之于字典,就如 Numpy 之于 Pandas。
- Pandas 中,所有数组特性仍在,Pandas 的数据以 Numpy 数组的方式存储。
一维对象的创建
字典创建法
NumPy中,可以通过 np.array()函数,将Python列表转化为NumPy数组;同样,Pandas中,可以通过pd.Series()函数,将Python字典转化为Series对象。
import pandas as pd
# 创建字典
dict_v = { 'a':0, 'b':0.25, 'c':0.5, 'd':0.75, 'e':1 }
# 用字典创建对象
sr = pd.Series( dict_v )
sr
a 0.00
b 0.25
c 0.50
d 0.75
e 1.00
dtype: float64
数组创建法
最直接的创建方法即直接给pd.Series()函数参数,其需要两个参数。第一个参数是值values(列表、数组、张量均可),第二个参数是键index(索引)。
# 先定义键与值
v = [0, 0.25, 0.5, 0.75, 1]
k = ['a', 'b', 'c', 'd', 'e']
# 用列表创建对象
sr = pd.Series( v, index=k )
sr
a 0.00
b 0.25
c 0.50
d 0.75
e 1.00
dtype: float64
sr.values
array([0. , 0.25, 0.5 , 0.75, 1. ])
# 其中,参数 index 可以省略,省略后索引即从 0 开始的顺序数字。
sr = pd.Series( v )
sr
0 0.00
1 0.25
2 0.50
3 0.75
4 1.00
dtype: float64
一维对象的属性
Series对象有两个属性:values与index。
import numpy as np
import pandas as pd
# 用数组创建 sr
v = np.array( [ 53, 64, 72, 82 ] )
k = ['1 号', '2 号', '3 号', '4 号']
sr = pd.Series( v, index=k )
sr
1 号 53
2 号 64
3 号 72
4 号 82
dtype: int64
# 查看 values 属性
sr.values
array([53, 64, 72, 82])
# 查看 index 属性
sr.index
Index(['1 号', '2 号', '3 号', '4 号'], dtype='object')
事实上,无论是用列表、数组还是张量来创建对象,最终valus均为数组。
import pandas as pd
import torch
# 用张量创建 sr
v = torch.tensor( [ 53, 64, 72, 82 ] )
k = ['1 号', '2 号', '3 号', '4 号']
sr = pd.Series( v, index=k )
sr
1 号 53
2 号 64
3 号 72
4 号 82
dtype: int64
# 查看 values 的属性
sr.values
array([53, 64, 72, 82])
可见,虽然 Pandas 对象的第一个参数 values 可以传入列表、数组与张量,但传进去后默认的存储方式是 NumPy 数组。这一点更加提醒我们,Pandas 是建立在 NumPy 基础上的库,没有 NumPy 数组库就没有 Pandas 数据处理库。
当想要 Pandas 退化为 NumPy 时,查看其 values 属性即可。
二维对象的创建
二维对象将面向矩阵,其不仅有行标签 index,还有列标签 columns。
字典创建法
用字典创建二维对象时,必须基于多个Series对象,每一个Series就是一列数据,相当于对一列一列的数据进行拼接。
- 创建Series对象时,字典的键是index,其延展方向是竖直的;
- 创建DataFrame对象时,字典的键是columns,其延展方向是水平的。
import pandas as pd
# 创建 sr1:各个病人的年龄
v1 = [ 53, 64, 72, 82 ]
i = [ '1 号', '2 号', '3 号', '4 号' ]
sr1 = pd.Series( v1, index=i )
sr1
1 号 53
2 号 64
3 号 72
4 号 82
dtype: int64
# 创建 sr2:各个病人的性别
v2 = [ '女', '男', '男', '女' ]
i = [ '1 号', '2 号', '3 号', '4 号' ]
sr2 = pd.Series( v2, index=i )
sr2
1 号 女
2 号 男
3 号 男
4 号 女
dtype: object
# 创建 df 对象
df = pd.DataFrame( { '年龄':sr1, '性别':sr2 } )
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 53 | 女 |
| 2 号 | 64 | 男 |
| 3 号 | 72 | 男 |
| 4 号 | 82 | 女 |
如果 sr1 和 sr2 的index不完全一致,那么二维对象的 index 会取 sr1 与 sr2 的所有 index,相应的,该对象就会产生一定数量的缺失值(NaN)。
import pandas as pd
# 创建 sr1:各个病人的年龄
v1 = [ 53, 64, 72, 82 ]
i = [ '1 号', '2 号', '3 号', '4 号' ]
sr1 = pd.Series( v1, index=i )
# 创建 sr2:各个病人的性别
v2 = [ '女', '男', '男', '女' ]
i = [ '1 号', '2 号', '3 号', '5 号' ]
sr2 = pd.Series( v2, index=i )
# 创建 df 对象
df = pd.DataFrame( { '年龄':sr1, '性别':sr2 } )
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 53.0 | 女 |
| 2 号 | 64.0 | 男 |
| 3 号 | 72.0 | 男 |
| 4 号 | 82.0 | NaN |
| 5 号 | NaN | 女 |
数组创建法
最直接的创建方法即直接给pd.DataFrame函数参数,其需要三个参数。第一个参数是值values(数组),第二个参数是行标签index,第三个参数是列标签columns。其中,index和columns参数可以忽略,省略后即从0开始的顺序数字。
import numpy as np
import pandas as pd
# 设定键值
v = np.array( [ [53, '女'], [64, '男'], [72, '男'], [82, '女'] ] )
i = [ '1 号', '2 号', '3 号', '4 号' ]
c = [ '年龄', '性别' ]
# 数组创建法
df = pd.DataFrame( v, index=i, columns=c )
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 53 | 女 |
| 2 号 | 64 | 男 |
| 3 号 | 72 | 男 |
| 4 号 | 82 | 女 |
细心的同学可能会发现端倪,NumPy 数组居然又含数字又含字符串,上次课中明明讲过数组只能容纳一种变量类型。这里的原理是,数组默默把数字转为了字符串,于是 v 就是一个字符串型数组。
二维对象的属性
DataFrame 对象有三个属性:values、index 与 columns。
import pandas as pd
# 设定键值
v = [ [53, '女'], [64, '男'], [72, '男'], [82, '女'] ]
i = [ '1 号', '2 号', '3 号', '4 号' ]
c = [ '年龄', '性别' ]
# 数组创建法
df = pd.DataFrame( v, index=i, columns=c )
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 53 | 女 |
| 2 号 | 64 | 男 |
| 3 号 | 72 | 男 |
| 4 号 | 82 | 女 |
# 查看 values 属性
df.values
array([[53, '女'],
[64, '男'],
[72, '男'],
[82, '女']], dtype=object)
# 查看 index 属性
df.index
Index(['1 号', '2 号', '3 号', '4 号'], dtype='object')
# 查看 columns 属性
df.columns
Index(['年龄', '性别'], dtype='object')
当想要 Pandas 退化为 NumPy 时,查看其 values 属性即可。
# 提取完整的数组
arr = df.values
print(arr)
[[53 '女']
[64 '男']
[72 '男']
[82 '女']]
# 提取第[0]列,并转化为一个整数型数组
arr = arr[:,0].astype(int)
print(arr)
[53 64 72 82]
对象的索引
在学习 Pandas 的索引之前,需要知道
- Pandas 的索引分为显式索引与隐式索引。显式索引是使用 Pandas 对象提供的索引,而隐式索引是使用数组本身自带的从 0 开始的索引。
- 现假设某演示代码中的索引是整数,这个时候显式索引和隐式索引可能会出乱子。于是,Pandas 作者发明了索引器 loc(显式)与 iloc(隐式),手动告诉程序自己这句话是显式索引还是隐式索引。
- 本章示例中,若代码块出现两栏,则左侧为显式索引,右侧为隐式索引,左右两列属于平行关系,任选其一均可。
一维对象的索引
访问元素
import pandas as pd
# 创建 sr
v = [ 53, 64, 72, 82 ]
k = ['1 号', '2 号', '3 号', '4 号']
sr = pd.Series( v, index=k )
sr
1 号 53
2 号 64
3 号 72
4 号 82
dtype: int64
# 通过显式索引访问元素
sr.loc[ '3 号' ]
np.int64(72)
# 通过隐式索引访问元素
sr.iloc[ 2 ]
np.int64(72)
# 通过显式索引进行花式索引
sr.loc[['1 号', '3 号']]
1 号 53
3 号 72
dtype: int64
# 通过隐式索引进行花式索引
sr.iloc[[0, 2]]
1 号 53
3 号 72
dtype: int64
# 通过显式索引修改元素
sr.loc['3 号'] = 100
sr
1 号 53
2 号 64
3 号 100
4 号 82
dtype: int64
# 通过隐式索引修改元素
sr.iloc[2] = 200
sr
1 号 53
2 号 64
3 号 200
4 号 82
dtype: int64
访问切片
使用显式索引时,'1 号':'3 号'可以覆盖最后一个'3 号',但隐式与之前一样。
import pandas as pd
# 创建 sr
v = [ 53, 64, 72, 82 ]
k = ['1 号', '2 号', '3 号', '4 号']
sr = pd.Series( v, index=k )
sr
1 号 53
2 号 64
3 号 72
4 号 82
dtype: int64
# 访问切片
sr.loc[ '1 号':'3 号' ]
1 号 53
2 号 64
3 号 72
dtype: int64
# 访问切片,可以看到还是左闭右开的
sr.iloc[ 0:3 ]
1 号 53
2 号 64
3 号 72
dtype: int64
# 切片仅是视图,改变切片实际上改变的是原数据
cut = sr.loc[ '1 号':'3 号' ]
cut.loc['1 号'] = 100
sr
1 号 100
2 号 64
3 号 72
4 号 82
dtype: int64
# 切片仅是视图
cut = sr.iloc[ 0:3 ]
cut.iloc[0] = 200
sr
1 号 200
2 号 64
3 号 72
4 号 82
dtype: int64
# 对象赋值仅是绑定,并非拷贝
cut = sr
cut.loc['3 号'] = 200
sr
1 号 200
2 号 64
3 号 200
4 号 82
dtype: int64
# 对象赋值仅是绑定
cut = sr
cut.iloc[2] = 300
sr
1 号 200
2 号 64
3 号 300
4 号 82
dtype: int64
若想创建新变量,与 NumPy 一样,使用.copy()方法即可。
如果去掉 .loc 和 .iloc ,此时与 NumPy 中的索引语法完全一致。
二维对象的索引
访问元素
import pandas as pd
# 字典创建法
i = [ '1 号', '2 号', '3 号', '4 号' ]
v1 = [ 53, 64, 72, 82 ]
v2 = [ '女', '男', '男', '女' ]
sr1 = pd.Series( v1, index=i )
sr2 = pd.Series( v2, index=i )
df = pd.DataFrame( { '年龄':sr1, '性别':sr2 } )
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 53 | 女 |
| 2 号 | 64 | 男 |
| 3 号 | 72 | 男 |
| 4 号 | 82 | 女 |
# 访问元素
df.loc[ '1 号', '年龄' ]
np.int64(53)
# 访问元素
df.iloc[ 0, 0 ]
np.int64(53)
# 花式索引
df.loc[ ['1 号', '3 号'] , ['性别','年龄'] ]
| 性别 | 年龄 | |
|---|---|---|
| 1 号 | 女 | 53 |
| 3 号 | 男 | 72 |
# 花式索引
df.iloc[ [0,2], [1,0] ]
| 性别 | 年龄 | |
|---|---|---|
| 1 号 | 女 | 53 |
| 3 号 | 男 | 72 |
# 修改元素
df.loc[ '3 号', '年龄' ] = 100
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 53 | 女 |
| 2 号 | 64 | 男 |
| 3 号 | 100 | 男 |
| 4 号 | 82 | 女 |
# 修改元素
df.iloc[ 2, 0 ] = 200
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 53 | 女 |
| 2 号 | 64 | 男 |
| 3 号 | 200 | 男 |
| 4 号 | 82 | 女 |
在 NumPy 数组中,花式索引输出的是一个向量。但在 Pandas 对象中,考虑到其行列标签的信息不能丢失,所以输出一个向量就不行了,所以这里才输出一个二维对象。
访问切片
# 数组创建法
v = [ [53, '女'], [64, '男'], [72, '男'], [82, '女'] ]
i = [ '1 号', '2 号', '3 号', '4 号' ]
c = [ '年龄', '性别' ]
df = pd.DataFrame( v, index=i, columns=c )
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 53 | 女 |
| 2 号 | 64 | 男 |
| 3 号 | 72 | 男 |
| 4 号 | 82 | 女 |
# 切片
df.loc[ '1 号':'3 号' , '年龄' ]
1 号 53
2 号 64
3 号 72
Name: 年龄, dtype: int64
# 切片
df.iloc[ 0:3 , 0 ]
1 号 53
2 号 64
3 号 72
Name: 年龄, dtype: int64
# 提取二维对象的行
df.loc[ '3 号' , : ]
年龄 72
性别 男
Name: 3 号, dtype: object
# 提取二维对象的行
df.iloc[ 2 , : ]
年龄 72
性别 男
Name: 3 号, dtype: object
# 提取矩阵对象的列
df.loc[ : , '年龄' ]
1 号 53
2 号 64
3 号 72
4 号 82
Name: 年龄, dtype: int64
# 提取矩阵对象的列
df.iloc[ : , 0 ]
1 号 53
2 号 64
3 号 72
4 号 82
Name: 年龄, dtype: int64
在显示索引中,提取矩阵的行或列还有一种简便写法,即
- 提取二维对象的行:
df.loc['3 号'](原理是省略后面的冒号,隐式也可以) - 提取二维对象的列:
df ['年龄'](原理是列标签本身就是二维对象的键)
对象的变形
对象的转置
有时候提供的大数据很畸形,行是特征,列是个体,这必须要先进行转置。
import pandas as pd
# 创建畸形 df
v = [ [53, 64, 72, 82], [ '女', '男', '男', '女' ] ]
i = [ '年龄', '性别' ]
c = [ '1 号', '2 号', '3 号', '4 号' ]
df = pd.DataFrame( v, index=i, columns=c )
df
| 1 号 | 2 号 | 3 号 | 4 号 | |
|---|---|---|---|---|
| 年龄 | 53 | 64 | 72 | 82 |
| 性别 | 女 | 男 | 男 | 女 |
# 转置
df = df.T
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 53 | 女 |
| 2 号 | 64 | 男 |
| 3 号 | 72 | 男 |
| 4 号 | 82 | 女 |
对象的翻转
紧接上面的例子,对Pandas对象进行左右翻转与上下翻转。
# 左右翻转
df = df.iloc[ : , : : -1 ]
df
| 性别 | 年龄 | |
|---|---|---|
| 1 号 | 女 | 53 |
| 2 号 | 男 | 64 |
| 3 号 | 男 | 72 |
| 4 号 | 女 | 82 |
# 上下翻转
df = df.iloc[ : : -1 , : ]
df
| 性别 | 年龄 | |
|---|---|---|
| 4 号 | 女 | 82 |
| 3 号 | 男 | 72 |
| 2 号 | 男 | 64 |
| 1 号 | 女 | 53 |
对象的重塑
考虑到对象是含有行列标签的,.reshape()已经不再适用,因此对象的重塑没有那么灵活。但可以做到将 sr 并入 df,也可以将 df 割出 sr。
# 数组法创建 sr
i = [ '1 号', '2 号', '3 号', '4 号' ]
v1 = [ 10, 20, 30, 40 ]
v2 = [ '女', '男', '男', '女' ]
v3 = [ 1, 2, 3, 4 ]
sr1 = pd.Series( v1, index=i )
sr2 = pd.Series( v2, index=i )
sr3 = pd.Series( v3, index=i )
sr1, sr2, sr3
(1 号 10
2 号 20
3 号 30
4 号 40
dtype: int64,
1 号 女
2 号 男
3 号 男
4 号 女
dtype: object,
1 号 1
2 号 2
3 号 3
4 号 4
dtype: int64)
# 字典法创建 df
df = pd.DataFrame( { '年龄':sr1, '性别':sr2 } )
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 10 | 女 |
| 2 号 | 20 | 男 |
| 3 号 | 30 | 男 |
| 4 号 | 40 | 女 |
# 把 sr 并入 df 中
df['牌照'] = sr3
df
| 年龄 | 性别 | 牌照 | |
|---|---|---|---|
| 1 号 | 10 | 女 | 1 |
| 2 号 | 20 | 男 | 2 |
| 3 号 | 30 | 男 | 3 |
| 4 号 | 40 | 女 | 4 |
# 把 df['年龄']分离成 sr4
sr4 = df['年龄']
sr4
1 号 10
2 号 20
3 号 30
4 号 40
Name: 年龄, dtype: int64
对象的拼接
Pandas中有一个pd.concat()函数,与np.concatenate()函数语法类似。
一维对象的合并
import pandas as pd
# 创建 sr1 和 sr2
v1 = [10, 20, 30, 40]
v2 = [40, 50, 60]
k1 = [ '1 号', '2 号', '3 号', '4 号' ]
k2 = [ '4 号', '5 号', '6 号' ]
sr1 = pd.Series( v1, index= k1 )
sr2 = pd.Series( v2, index= k2 )
sr1, sr2
(1 号 10
2 号 20
3 号 30
4 号 40
dtype: int64,
4 号 40
5 号 50
6 号 60
dtype: int64)
# 合并
pd.concat( [sr1, sr2] )
1 号 10
2 号 20
3 号 30
4 号 40
4 号 40
5 号 50
6 号 60
dtype: int64
值得注意的是,上面输出的键中出现了两个“4 号”,这是因为 Pandas 对象的属性,放弃了集合与字典索引中“不可重复”的特性,实际中,这可以拓展大数据分析与处理的应用场景。那么,如何保证索引是不重复的呢?对对象的属性 .index 或 .columns 使用 .is_unique 即可检查,返回 True表示行或列不重复,False 表示有重复。
一维对象与二维对象的合并
一维对象与二维对象的合并,即可理解为:给二维对象加上一列或者一行。因此,不必使用pd.concat()函数,只需要借助千问”二维对象的索引“语法。
# 首先,创建好二维对象
import pandas as pd
# 创建 sr1 与 sr2
v1 = [ 10, 20, 30]
v2 = [ '女', '男', '男']
sr1 = pd.Series( v1, index=[ '1 号', '2 号', '3 号'] )
sr2 = pd.Series( v2, index=[ '1 号', '2 号', '3 号'] )
sr1, sr2
(1 号 10
2 号 20
3 号 30
dtype: int64,
1 号 女
2 号 男
3 号 男
dtype: object)
# 创建 df
df = pd.DataFrame( { '年龄':sr1, '性别':sr2 } )
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 10 | 女 |
| 2 号 | 20 | 男 |
| 3 号 | 30 | 男 |
# 其次,为二维对象加上一列特征,可以是列表、数组、张量或一维对象。
# 加上一列
df['牌照'] = [1, 2, 3]
df
| 年龄 | 性别 | 牌照 | |
|---|---|---|---|
| 1 号 | 10 | 女 | 1 |
| 2 号 | 20 | 男 | 2 |
| 3 号 | 30 | 男 | 3 |
# 最后,为二维对象加上一行个体,可以是列表、数组、张量或一维对象。
# 加上一行
df.loc['4 号'] = [40, '女', 4]
df
| 年龄 | 性别 | 牌照 | |
|---|---|---|---|
| 1 号 | 10 | 女 | 1 |
| 2 号 | 20 | 男 | 2 |
| 3 号 | 30 | 男 | 3 |
| 4 号 | 40 | 女 | 4 |
二维对象的合并
二维对象合并仍然用 pd.concat()函数,不过其多了一个 axis 参数。
# 设定 df1、df2、df3
v1 = [ [10, '女'], [20, '男'], [30, '男'], [40, '女'] ]
v2 = [ [1, '是'], [2, '是'], [3, '是'], [4, '否'] ]
v3 = [ [50, '男', 5, '是'], [60, '女', 6, '是'] ]
i1 = [ '1 号', '2 号', '3 号', '4 号' ]
i2 = [ '1 号', '2 号', '3 号', '4 号' ]
i3 = [ '5 号', '6 号' ]
c1 = [ '年龄', '性别' ]
c2 = [ '牌照', 'ikun' ]
c3 = [ '年龄', '性别', '牌照', 'ikun' ]
df1 = pd.DataFrame( v1, index=i1, columns=c1 )
df2 = pd.DataFrame( v2, index=i2, columns=c2 )
df3 = pd.DataFrame( v3, index=i3, columns=c3 )
df1, df2, df3
( 年龄 性别
1 号 10 女
2 号 20 男
3 号 30 男
4 号 40 女,
牌照 ikun
1 号 1 是
2 号 2 是
3 号 3 是
4 号 4 否,
年龄 性别 牌照 ikun
5 号 50 男 5 是
6 号 60 女 6 是)
# 合并列对象(添加列特征)
df = pd.concat( [df1,df2], axis=1 )
df
| 年龄 | 性别 | 牌照 | ikun | |
|---|---|---|---|---|
| 1 号 | 10 | 女 | 1 | 是 |
| 2 号 | 20 | 男 | 2 | 是 |
| 3 号 | 30 | 男 | 3 | 是 |
| 4 号 | 40 | 女 | 4 | 否 |
# 合并行对象(添加行个体)
df = pd.concat( [df,df3] )
df
| 年龄 | 性别 | 牌照 | ikun | |
|---|---|---|---|---|
| 1 号 | 10 | 女 | 1 | 是 |
| 2 号 | 20 | 男 | 2 | 是 |
| 3 号 | 30 | 男 | 3 | 是 |
| 4 号 | 40 | 女 | 4 | 否 |
| 5 号 | 50 | 男 | 5 | 是 |
| 6 号 | 60 | 女 | 6 | 是 |
对象的运算
对象与系数之间的运算
下列演示代码中,左侧为一维对象,右侧为二维对象。
import pandas as pd
# 创建 sr
sr = pd.Series( [ 53, 64, 72 ] , index=['1 号', '2 号', '3 号'] )
sr
1 号 53
2 号 64
3 号 72
dtype: int64
# 创建 df
v = [ [53, '女'], [64, '男'], [72, '男'] ]
df = pd.DataFrame( v, index=[ '1 号', '2 号', '3 号' ], columns=[ '年龄', '性别' ] )
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 53 | 女 |
| 2 号 | 64 | 男 |
| 3 号 | 72 | 男 |
# 对一维对象进行操作
sr = sr + 10
sr
1 号 63
2 号 74
3 号 82
dtype: int64
# 对二维对象进行操作
df['年龄'] = df['年龄'] + 10
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 63 | 女 |
| 2 号 | 74 | 男 |
| 3 号 | 82 | 男 |
sr = sr * 10
sr
1 号 630
2 号 740
3 号 820
dtype: int64
df['年龄'] = df['年龄'] * 10
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 630 | 女 |
| 2 号 | 740 | 男 |
| 3 号 | 820 | 男 |
sr = sr ** 2
sr
1 号 396900
2 号 547600
3 号 672400
dtype: int64
df['年龄'] = df['年龄'] ** 2
df
| 年龄 | 性别 | |
|---|---|---|
| 1 号 | 396900 | 女 |
| 2 号 | 547600 | 男 |
| 3 号 | 672400 | 男 |
对象与对象之间的运算
对象做运算,必须保证其都是数字型对象,两个对象之间的维度可以不同。
一维对象之间的运算
import pandas as pd
# 创建 sr1
v1 = [10, 20, 30, 40]
k1 = [ '1 号', '2 号', '3 号', '4 号' ]
sr1 = pd.Series( v1, index= k1 )
sr1
1 号 10
2 号 20
3 号 30
4 号 40
dtype: int64
# 创建 sr2
v2 = [1, 2, 3 ]
k2 = [ '1 号', '2 号', '3 号' ]
sr2 = pd.Series( v2, index= k2 )
sr2
1 号 1
2 号 2
3 号 3
dtype: int64
sr1 + sr2 # 加法
1 号 11.0
2 号 22.0
3 号 33.0
4 号 NaN
dtype: float64
sr1 - sr2 # 减法
1 号 9.0
2 号 18.0
3 号 27.0
4 号 NaN
dtype: float64
sr1 * sr2 # 乘法
1 号 10.0
2 号 40.0
3 号 90.0
4 号 NaN
dtype: float64
sr1 / sr2 # 除法
1 号 10.0
2 号 10.0
3 号 10.0
4 号 NaN
dtype: float64
sr1 ** sr2 # 幂方
1 号 10.0
2 号 400.0
3 号 27000.0
4 号 NaN
dtype: float64
二维对象之间的运算
import pandas as pd
# 设定 df1 和 df2
v1 = [ [10, '女'], [20, '男'], [30, '男'], [40, '女'] ]
v2 = [ 1, 2 ,3, 6 ]
i1 = [ '1 号', '2 号', '3 号', '4 号' ]; c1 = [ '年龄', '性别' ]
i2 = [ '1 号', '2 号', '3 号', '6 号' ]; c2 = [ '牌照' ]
df1 = pd.DataFrame( v1, index=i1, columns=c1 )
df2 = pd.DataFrame( v2, index=i2, columns=c2 )
df1, df2
( 年龄 性别
1 号 10 女
2 号 20 男
3 号 30 男
4 号 40 女,
牌照
1 号 1
2 号 2
3 号 3
6 号 6)
# 加法
df1['加法'] = df1['年龄'] + df2['牌照']
df1
| 年龄 | 性别 | 加法 | |
|---|---|---|---|
| 1 号 | 10 | 女 | 11.0 |
| 2 号 | 20 | 男 | 22.0 |
| 3 号 | 30 | 男 | 33.0 |
| 4 号 | 40 | 女 | NaN |
# 减法、乘法、除法、幂方
df1['减法'] = df1['年龄'] - df2['牌照']
df1['乘法'] = df1['年龄'] * df2['牌照']
df1['除法'] = df1['年龄'] / df2['牌照']
df1['幂方'] = df1['年龄'] ** df2['牌照']
df1
| 年龄 | 性别 | 加法 | 减法 | 乘法 | 除法 | 幂方 | |
|---|---|---|---|---|---|---|---|
| 1 号 | 10 | 女 | 11.0 | 9.0 | 10.0 | 10.0 | 10.0 |
| 2 号 | 20 | 男 | 22.0 | 18.0 | 40.0 | 10.0 | 400.0 |
| 3 号 | 30 | 男 | 33.0 | 27.0 | 90.0 | 10.0 | 27000.0 |
| 4 号 | 40 | 女 | NaN | NaN | NaN | NaN | NaN |
本章的最后,补充两点内容,读者可自行尝试。
- 使用 np.abs()、np.cos()、np.exp()、np.log() 等数学函数时,会保留索引;
- Pandas 中仍然存在布尔型对象,用法与 NumPy 无异,会保留索引。
import pandas as pd
import numpy as np
# 创建一个带有自定义索引的 Series
data = pd.Series([-1.5, 0, 2.5, -3.0], index=['a', 'b', 'c', 'd'])
print("原始数据 (Original Data):")
print(data)
print("-" * 30)
# 验证 np.abs() - 绝对值
print("使用 np.abs() 后 (索引保留):")
print(np.abs(data))
print("-" * 30)
# 验证 np.exp() - 指数
print("使用 np.exp() 后 (索引保留):")
print(np.exp(data))
print("-" * 30)
# 验证 np.log() - 对数 (注意:log(0) 和 log(负数) 会产生 inf 或 nan,但不影响索引保留)
print("使用 np.log() 后 (索引保留):")
# 为了演示 log,我们换一组正数数据
data_pos = pd.Series([1, 2.718, 10], index=['x', 'y', 'z'])
print(np.log(data_pos))
原始数据 (Original Data):
a -1.5
b 0.0
c 2.5
d -3.0
dtype: float64
------------------------------
使用 np.abs() 后 (索引保留):
a 1.5
b 0.0
c 2.5
d 3.0
dtype: float64
------------------------------
使用 np.exp() 后 (索引保留):
a 0.223130
b 1.000000
c 12.182494
d 0.049787
dtype: float64
------------------------------
使用 np.log() 后 (索引保留):
x 0.000000
y 0.999896
z 2.302585
dtype: float64
import pandas as pd
import numpy as np
# 创建一个 Series
s = pd.Series([10, -5, 0, 20, -15], index=['A', 'B', 'C', 'D', 'E'])
print("原始数据:")
print(s)
print("-" * 30)
# 1. 生成布尔对象 (Boolean Object)
# 用法与 NumPy 无异:直接比较
bool_mask = s > 0
print("布尔对象 (s > 0):")
print(bool_mask)
# 注意看:结果是一个 Series,且索引 ['A', 'B', ...] 被完整保留了
print("-" * 30)
# 2. 布尔运算 (Logical Operations)
# 用法与 NumPy 无异:使用 & (与), | (或), ~ (非)
# 比如:找出 大于0 且 小于15 的数
complex_mask = (s > 0) & (s < 15)
print("复杂布尔运算 ((s > 0) & (s < 15)):")
print(complex_mask)
print("-" * 30)
# 3. 布尔索引 (Boolean Indexing)
# 使用上面的布尔对象来筛选数据
filtered_data = s[bool_mask]
print("筛选后的数据 (s[s > 0]):")
print(filtered_data)
# 注意看:筛选出来的结果,其索引依然是原始的 'A' 和 'D',而不是重置为 0, 1
原始数据:
A 10
B -5
C 0
D 20
E -15
dtype: int64
------------------------------
布尔对象 (s > 0):
A True
B False
C False
D True
E False
dtype: bool
------------------------------
复杂布尔运算 ((s > 0) & (s < 15)):
A True
B False
C False
D False
E False
dtype: bool
------------------------------
筛选后的数据 (s[s > 0]):
A 10
D 20
dtype: int64
对象的缺失值
发现缺失值
发现缺失值使用.isnull()方法。
import pandas as pd
# 创建 sr
v = [ 53, None, 72, 82 ]
k = ['1 号', '2 号', '3 号', '4 号']
sr = pd.Series( v, index=k )
sr
1 号 53.0
2 号 NaN
3 号 72.0
4 号 82.0
dtype: float64
# 创建 df
v = [ [None, 1], [64, None], [72, 3], [82, 4] ]
i = [ '1 号', '2 号', '3 号', '4 号' ]
c = [ '年龄', '牌照' ]
df = pd.DataFrame( v, index=i, columns=c )
df
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | NaN | 1.0 |
| 2 号 | 64.0 | NaN |
| 3 号 | 72.0 | 3.0 |
| 4 号 | 82.0 | 4.0 |
# 发现 sr 的缺失值
sr.isnull()
1 号 False
2 号 True
3 号 False
4 号 False
dtype: bool
# 发现 df 的缺失值
df.isnull()
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | True | False |
| 2 号 | False | True |
| 3 号 | False | False |
| 4 号 | False | False |
# 发现 df 的非缺失值
~df.isnull()
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | False | True |
| 2 号 | True | False |
| 3 号 | True | True |
| 4 号 | True | True |
df.notnull()
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | False | True |
| 2 号 | True | False |
| 3 号 | True | True |
| 4 号 | True | True |
除了.isnull() 方法,还有一个与之相反的 .notnull() 方法,但不如在开头加一个非号“~”即可。
剔除缺失值
剔除缺失值使用 .dropna() 方法,一维对象很好剔除;二维对象比较复杂,要么单独剔除 df 中含有缺失值的行,要么剔除 df 中含有缺失值的列。
import pandas as pd
# 创建 sr
v = [ 53, None, 72, 82 ]
k = ['1 号', '2 号', '3 号', '4 号']
sr = pd.Series( v, index=k )
sr
1 号 53.0
2 号 NaN
3 号 72.0
4 号 82.0
dtype: float64
# 创建 df
v = [ [None, None], [64, None], [72, 3], [82, 4] ]
i = [ '1 号', '2 号', '3 号', '4 号' ]
c = [ '年龄', '牌照' ]
df = pd.DataFrame( v, index=i, columns=c )
df
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | NaN | NaN |
| 2 号 | 64.0 | NaN |
| 3 号 | 72.0 | 3.0 |
| 4 号 | 82.0 | 4.0 |
# 剔除 sr 的缺失值
sr.dropna()
1 号 53.0
3 号 72.0
4 号 82.0
dtype: float64
# 剔除 df 含缺失值的行
df.dropna()
| 年龄 | 牌照 | |
|---|---|---|
| 3 号 | 72.0 | 3.0 |
| 4 号 | 82.0 | 4.0 |
把含有 NaN 的行剔除掉了,你也可以通过 df.dropna(axis='columns')的方式剔除列。但请警惕,一般都是剔除行,只因大数据中行是个体,列是特征。
有些同学认为,只要某行含有一个 NaN 就剔除该个体太过残忍,我们可以设定一个参数,只有当该行全部是 NaN,才剔除该列特征。
# 剔除 df 全是 NaN 的个体
df.dropna(how='all')
| 年龄 | 牌照 | |
|---|---|---|
| 2 号 | 64.0 | NaN |
| 3 号 | 72.0 | 3.0 |
| 4 号 | 82.0 | 4.0 |
填补缺失值
填充缺失值使用 .fillna() 方法,实际的数据填充没有统一的方法,很灵活。
一维对象
import pandas as pd
# 创建 sr
v = [ 53, None, 72, 82 ]
sr = pd.Series( v, index=['1 号', '2 号', '3 号', '4 号'] )
sr
1 号 53.0
2 号 NaN
3 号 72.0
4 号 82.0
dtype: float64
# 用常数(0)填充
sr.fillna(0)
1 号 53.0
2 号 0.0
3 号 72.0
4 号 82.0
dtype: float64
# 用常数(均值)填充
import numpy as np
sr.fillna(np.mean(sr))
1 号 53.0
2 号 69.0
3 号 72.0
4 号 82.0
dtype: float64
# 用前值填充
sr.fillna(method='ffill')
/tmp/ipykernel_55/89089568.py:2: FutureWarning: Series.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
sr.fillna(method='ffill')
1 号 53.0
2 号 53.0
3 号 72.0
4 号 82.0
dtype: float64
# 用后值填充
sr.fillna(method='bfill')
/tmp/ipykernel_55/568087098.py:2: FutureWarning: Series.fillna with 'method' is deprecated and will raise in a future version. Use obj.ffill() or obj.bfill() instead.
sr.fillna(method='bfill')
1 号 53.0
2 号 72.0
3 号 72.0
4 号 82.0
dtype: float64
二维对象
import pandas as pd
# 设定 df
v = [ [None, None], [64, None], [72, 3], [82, 4] ]
i = [ '1 号', '2 号', '3 号', '4 号' ]; c = [ '年龄', '牌照' ]
df = pd.DataFrame( v, index=i, columns=c )
df
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | NaN | NaN |
| 2 号 | 64.0 | NaN |
| 3 号 | 72.0 | 3.0 |
| 4 号 | 82.0 | 4.0 |
# 用常数(0)填充
df.fillna(0)
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | 0.0 | 0.0 |
| 2 号 | 64.0 | 0.0 |
| 3 号 | 72.0 | 3.0 |
| 4 号 | 82.0 | 4.0 |
# 用常数(均值)填充
import numpy as np
df.fillna( np.mean(df) )
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | 45.0 | 45.0 |
| 2 号 | 64.0 | 45.0 |
| 3 号 | 72.0 | 3.0 |
| 4 号 | 82.0 | 4.0 |
似乎此处的结果并不像教程中所示,np.mean(df)计算了所有数值的平均值并以此填充了所有缺失字段,而没有按照每一列计算均值并填充。
使用df.mean()反而能实现我们预期的效果。
# 用常数(均值)填充
df.fillna( df.mean() )
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | 72.666667 | 3.5 |
| 2 号 | 64.000000 | 3.5 |
| 3 号 | 72.000000 | 3.0 |
| 4 号 | 82.000000 | 4.0 |
# 用前值填充
df.ffill()
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | NaN | NaN |
| 2 号 | 64.0 | NaN |
| 3 号 | 72.0 | 3.0 |
| 4 号 | 82.0 | 4.0 |
# 用后值填充
df.bfill()
| 年龄 | 牌照 | |
|---|---|---|
| 1 号 | 64.0 | 3.0 |
| 2 号 | 64.0 | 3.0 |
| 3 号 | 72.0 | 3.0 |
| 4 号 | 82.0 | 4.0 |
导入Excel文件
创建Excel文件
导入信息的命令如示例所示。
import pandas as pd
import pandas as pd
# 读取 Excel 文件
df_1 = pd.read_excel('/kaggle/input/datasets/frechen026/jie-pandas/Data.xlsx')
df_2 = pd.read_excel('/kaggle/input/datasets/frechen026/jie-pandas/Data_1773733480020.xlsx')
df_3 = pd.read_excel('/kaggle/input/datasets/frechen026/jie-pandas/test1.xlsx')
df_4 = pd.read_excel('/kaggle/input/datasets/frechen026/jie-pandas/test2.xlsx')
# 保存为 CSV 文件
df_1.to_csv('/kaggle/working/Data1.csv', index=False, encoding='utf-8-sig')
df_2.to_csv('/kaggle/working/Data2.csv', index=False, encoding='utf-8-sig')
df_3.to_csv('/kaggle/working/test1.csv', index=False, encoding='utf-8-sig')
df_4.to_csv('/kaggle/working/test2.csv', index=False, encoding='utf-8-sig')
# 导入 Pandas 对象
df = pd.read_csv('/kaggle/working/Data1.csv', index_col=0)
df
| age | gender | num | kun | |
|---|---|---|---|---|
| Unnamed: 0 | ||||
| 1号 | 10 | 女 | 1 | 是 |
| 2号 | 20 | 男 | 2 | 是 |
| 3号 | 30 | 男 | 3 | 是 |
| 4号 | 40 | 女 | 4 | 否 |
| 5号 | 50 | 男 | 5 | 是 |
| 6号 | 60 | 女 | 6 | 是 |
# 提取纯数组
arr = df.values
arr
array([[10, '女', 1, '是'],
[20, '男', 2, '是'],
[30, '男', 3, '是'],
[40, '女', 4, '否'],
[50, '男', 5, '是'],
[60, '女', 6, '是']], dtype=object)
数据分析
导入信息
首先,准备好Excel数据表格。
发现没有行标签,因此需要在最左侧快速填充一列顺序数字。
接着,按照第六章的方法,将其另存为 CSV 文件,并放置项目文件夹中。
最后,导入该表格至 Jupyter 中。
import pandas as pd
# 导入 Pandas 对象
pd.read_csv('/kaggle/working/test2.csv', index_col=0)
| 发现时间 | 发现数量 | 观测方法 | 行星质量 | 距地距离 | 轨道周期 | |
|---|---|---|---|---|---|---|
| Unnamed: 0 | ||||||
| 0 | 1989 | 1 | 径向速度 | 11.680 | 40.57 | 83.888000 |
| 1 | 1992 | 3 | 脉冲星计时 | NaN | NaN | 25.262000 |
| 2 | 1992 | 3 | 脉冲星计时 | NaN | NaN | 66.541900 |
| 3 | 1994 | 3 | 脉冲星计时 | NaN | NaN | 98.211400 |
| 4 | 1995 | 1 | 径向速度 | 0.472 | 15.36 | 4.230785 |
| ... | ... | ... | ... | ... | ... | ... |
| 1030 | 2014 | 1 | 凌日 | NaN | NaN | 2.465020 |
| 1031 | 2014 | 1 | 凌日 | NaN | NaN | 68.958400 |
| 1032 | 2014 | 1 | 凌日 | NaN | 1056.00 | 1.720861 |
| 1033 | 2014 | 1 | 凌日 | NaN | NaN | 66.262000 |
| 1034 | 2014 | 1 | 凌日 | NaN | 470.00 | 0.925542 |
1035 rows × 6 columns
聚合方法
可在输出df时,对其使用.head()方法,使其仅仅输出前5行。
import pandas as pd
# 导入 Pandas 对象
df = pd.read_csv('/kaggle/working/test2.csv', index_col=0)
df.head()
| 发现时间 | 发现数量 | 观测方法 | 行星质量 | 距地距离 | 轨道周期 | |
|---|---|---|---|---|---|---|
| Unnamed: 0 | ||||||
| 0 | 1989 | 1 | 径向速度 | 11.680 | 40.57 | 83.888000 |
| 1 | 1992 | 3 | 脉冲星计时 | NaN | NaN | 25.262000 |
| 2 | 1992 | 3 | 脉冲星计时 | NaN | NaN | 66.541900 |
| 3 | 1994 | 3 | 脉冲星计时 | NaN | NaN | 98.211400 |
| 4 | 1995 | 1 | 径向速度 | 0.472 | 15.36 | 4.230785 |
NumPy 中所有的聚合函数对 Pandas 对象均适用。此外,Pandas 将这些函数变为对象的方法,这样,不导入 NumPy 也可使用。
# 最大值函数 np.max( )
df.max()
发现时间 2014
发现数量 7
观测方法 轨道亮度调制
行星质量 25.0
距地距离 8500.0
轨道周期 730000.0
dtype: object
# 最小值函数 np.min( )
df.min()
发现时间 1989
发现数量 1
观测方法 凌日
行星质量 0.0036
距地距离 1.35
轨道周期 0.090706
dtype: object
# 均值函数 np.mean( )
df.mean(numeric_only=True)
# 在 mean() 函数中添加参数 numeric_only=True。这会告诉 Pandas 自动忽略所有非数值类型的列,只对数字列计算均值。
# 可能是版本原因我这里需要添加该参数。
发现时间 2009.070531
发现数量 1.785507
行星质量 2.638161
距地距离 264.069282
轨道周期 2002.917596
dtype: float64
# 求和函数 np.sum( )
df.sum(numeric_only=True)
发现时间 2.079388e+06
发现数量 1.848000e+03
行星质量 1.353376e+03
距地距离 2.133680e+05
轨道周期 1.986894e+06
dtype: float64
描述方法
在数据分析中,用以上方法挨个查看未免太过麻烦,可以使用 .describe() 方法直接查看所有聚合函数的信息。
# 导入 Pandas 对象
df = pd.read_csv('/kaggle/working/test2.csv', index_col=0)
df.head()
| 发现时间 | 发现数量 | 观测方法 | 行星质量 | 距地距离 | 轨道周期 | |
|---|---|---|---|---|---|---|
| Unnamed: 0 | ||||||
| 0 | 1989 | 1 | 径向速度 | 11.680 | 40.57 | 83.888000 |
| 1 | 1992 | 3 | 脉冲星计时 | NaN | NaN | 25.262000 |
| 2 | 1992 | 3 | 脉冲星计时 | NaN | NaN | 66.541900 |
| 3 | 1994 | 3 | 脉冲星计时 | NaN | NaN | 98.211400 |
| 4 | 1995 | 1 | 径向速度 | 0.472 | 15.36 | 4.230785 |
df.describe()
| 发现时间 | 发现数量 | 行星质量 | 距地距离 | 轨道周期 | |
|---|---|---|---|---|---|
| count | 1035.000000 | 1035.000000 | 513.000000 | 808.000000 | 992.000000 |
| mean | 2009.070531 | 1.785507 | 2.638161 | 264.069282 | 2002.917596 |
| std | 3.972567 | 1.240976 | 3.818617 | 733.116493 | 26014.728304 |
| min | 1989.000000 | 1.000000 | 0.003600 | 1.350000 | 0.090706 |
| 25% | 2007.000000 | 1.000000 | 0.229000 | 32.560000 | 5.442540 |
| 50% | 2010.000000 | 1.000000 | 1.260000 | 55.250000 | 39.979500 |
| 75% | 2012.000000 | 2.000000 | 3.040000 | 178.500000 | 526.005000 |
| max | 2014.000000 | 7.000000 | 25.000000 | 8500.000000 | 730000.000000 |
数据透视
两个特征内的数据透视
数据透视,对数据分析来讲十分重要。
现以泰坦尼克号的生还数据为例,以“是否生还”特征为考察的核心(或者说是神经网络的输出),研究其它特征(输入)与之的关系,如示例所示。
import pandas as pd
# 导入 Pandas 对象
df = pd.read_csv('/kaggle/working/test1.csv', index_col=0)
df.head()
| 性别 | 年龄 | 船舱等级 | 费用 | 是否生还 | |
|---|---|---|---|---|---|
| Unnamed: 0 | |||||
| 0 | 男 | 22.0 | 三等 | 7.2500 | 0 |
| 1 | 女 | 38.0 | 一等 | 71.2833 | 1 |
| 2 | 女 | 26.0 | 三等 | 7.9250 | 1 |
| 3 | 女 | 35.0 | 一等 | 53.1000 | 1 |
| 4 | 男 | 35.0 | 三等 | 8.0500 | 0 |
# 一个特征:性别
df.pivot_table('是否生还', index='性别')
| 是否生还 | |
|---|---|
| 性别 | |
| 女 | 0.742038 |
| 男 | 0.188908 |
# 两个特征:性别、船舱等级
df.pivot_table('是否生还', index='性别', columns='船舱等级')
| 船舱等级 | 一等 | 三等 | 二等 |
|---|---|---|---|
| 性别 | |||
| 女 | 0.968085 | 0.500000 | 0.921053 |
| 男 | 0.368852 | 0.135447 | 0.157407 |
在上述示例中,数据透视表中的数值默认是输出特征“是否生还”的均值(mean),行标签和列标签变成了其它的输入特征。可以看出,女性整体的生还概率是 74%,男性整体的生还概率为 18%。
按照船舱等级的下降,生还率逐步下降。 值得注意的是,pivot_table() 方法有一个很重要的参数:aggfunc,其默认值是'mean',除此以外,所有的聚合函数'max'、'min'、'sum'、'count' 均可使用。
显然,对于这里的“是否生还”来说,'mean'就是最好的选择,其刚好为概率。
多个特征的数据透视
前面的示例只涉及到两个特征,有时需要考察更多特征与输出特征的关系。
这里,将年龄和费用都加进去。但是,这两个特征的数值很分散,之前的性别和船舱等级都可以按照类别分,现在已经不能再按类别分了。因此,需要涉及****到数据透视表配套的两个重要函数:pd.cut()与 pd.qcut()。
# 导入 Pandas 对象
df = pd.read_csv('/kaggle/working/test1.csv', index_col=0)
df.head()
| 性别 | 年龄 | 船舱等级 | 费用 | 是否生还 | |
|---|---|---|---|---|---|
| Unnamed: 0 | |||||
| 0 | 男 | 22.0 | 三等 | 7.2500 | 0 |
| 1 | 女 | 38.0 | 一等 | 71.2833 | 1 |
| 2 | 女 | 26.0 | 三等 | 7.9250 | 1 |
| 3 | 女 | 35.0 | 一等 | 53.1000 | 1 |
| 4 | 男 | 35.0 | 三等 | 8.0500 | 0 |
# 三个特征:性别、船舱等级、年龄
age = pd.cut( df['年龄'], [0,18,120] ) # 以 18 岁为分水岭
df.pivot_table('是否生还', index= ['性别', age], columns='船舱等级')
/tmp/ipykernel_55/1361481379.py:3: FutureWarning: The default value of observed=False is deprecated and will change to observed=True in a future version of pandas. Specify observed=False to silence this warning and retain the current behavior
df.pivot_table('是否生还', index= ['性别', age], columns='船舱等级')
| 船舱等级 | 一等 | 三等 | 二等 | |
|---|---|---|---|---|
| 性别 | 年龄 | |||
| 女 | (0, 18] | 0.909091 | 0.511628 | 1.000000 |
| (18, 120] | 0.972973 | 0.423729 | 0.900000 | |
| 男 | (0, 18] | 0.800000 | 0.215686 | 0.600000 |
| (18, 120] | 0.375000 | 0.133663 | 0.071429 |
# 四个特征:性别、船舱等级、年龄、费用
fare = pd.qcut( df['费用'], 2 ) # 将费用自动分为两部分
df.pivot_table('是否生还', index= ['船舱等级',fare], columns=['性别', age])
/tmp/ipykernel_55/2785335320.py:3: FutureWarning: The default value of observed=False is deprecated and will change to observed=True in a future version of pandas. Specify observed=False to silence this warning and retain the current behavior
df.pivot_table('是否生还', index= ['船舱等级',fare], columns=['性别', age])
| 性别 | 女 | 男 | |||
|---|---|---|---|---|---|
| 年龄 | (0, 18] | (18, 120] | (0, 18] | (18, 120] | |
| 船舱等级 | 费用 | ||||
| 一等 | (-0.001, 14.454] | NaN | NaN | NaN | 0.000000 |
| (14.454, 512.329] | 0.909091 | 0.972973 | 0.800000 | 0.391304 | |
| 三等 | (-0.001, 14.454] | 0.714286 | 0.444444 | 0.260870 | 0.125000 |
| (14.454, 512.329] | 0.318182 | 0.391304 | 0.178571 | 0.192308 | |
| 二等 | (-0.001, 14.454] | 1.000000 | 0.880000 | 0.000000 | 0.098039 |
| (14.454, 512.329] | 1.000000 | 0.914286 | 0.818182 | 0.030303 | |
- pd.cut()函数需要手动设置分割点,也可以设置为
[0,18,60,120]。 - pd.qcut()函数可自动分割,如果需要分割成 3 部分,可以设置为 3。