admin 管理员组文章数量: 887021
pandas基础
- 一.pandas介绍
- 1.什么是pandas
- 2.pandas用途
- 3.课程内容
- 二.Ipython开发环境搭建
- 1.安装
- 2.新建运行环境
- 3.Ipython技巧
- 4.Ipython notebook
- 三.numpy简介
- 四.pandas入门
- 1.官方网址:
- 2.数据表创建、访问、更改
- 2.1创建pandas对象
- 2.2查看数据
- 2.3选择数据
- 3.DataFrame的操作
- 3.1处理缺失数据missing data
- 3.2数据运算
- 3.3数据合并
- 3.4数据分组
- 4.其他操作
- 4.1数据整形
- 4.2数据透视
- 4.3时间序列
- 4.4数据可视化
- 4.5 数据读写,即载入与保存
- 五.实例Movielens电影数据分析
- 1. 数据准备
- 2.操作
- 2.1用pandas将数据导入进来
- 2.2操作数据
- 六.Pandas核心数据结构
- 1.Series
- 1.1定义及创建
- 1.2操作
- 1.2.1Series 类似numpy多维数组
- 1.2.2Series 类似字典
- 1.2.3矢量操作与对齐Series标签
- 1.2.4名称属性
- 2.DataFrame
- 2.1定义及创建
- 2.1.1用 Series 字典或字典生成 DataFrame
- 2.1.2用列表构成的字典生成DataFrame
- 2.1.3用元组构成的列表生成DataFrame
- 2.1.4用字典构成的列表生成DataFrame
- 2.1.5用元组构成的字典生成DataFrame
- 2.1.6用Series生成DataFrame
- 2.2特性及操作
- 2.2.1提取、添加、删除列
- 2.2.2用方法链分配新列
- 2.2.3索引 / 选择
- 2.2.4 数据对齐和运算
- 2.2.5 控制台显示
- 3.Panel
- 3.1定义
- 3.2创建
- 3.3操作
- 七.Pandas基础运算
- 1.重置索引
- 1.1reindex()
- 1.2重置索引,并与其它对象对齐reindex_like() 方法
- 1.4重置索引填充
- 1.5重置索引填充的限制
- 1.6用 align 对齐多个对象
- 2.更换标签
- 2.1去掉轴上的标签/丢弃部分数据
- 2.2重命名或映射标签
- 3.函数
- 3.1表级函数应用pipe() 方法
- 3.2行列级函数应用apply()
- 3.2.1apply() 沿着 DataFrame 的轴应用函数
- 3.2.2apply() 支持通过函数名字符串调用函数
- 3.2.3 用好 apply() 可以了解数据集的很多信息。
- 3.2.4 向 apply() 方法传递额外的参数与关键字参数
- 3.2.5 为每行或每列执行 Series 方法的功能
- 3.3 聚合 API
- 3.3.1应用单个函数
- 3.3.2多函数聚合
- 3.3.3用字典实现聚合
- 3.3.4多种数据类型(Dtype)
- 3.4自定义 Describe
- 3.5Transform API
- 3.5.1 单函数
- 3.5.2 多函数 Transform
- 3.5.3用字典执行 transform 操作
- 3.6元素级函数应用:映射DataFrame 的 applymap() 及 Series 的 map()
- 4.排序和排名
- 4.1按索引排序
- 4.2按值排序
- 4.3按按索引与值排序
- 4.4搜索排序
- 4.5最大值与最小值
- 4.5.1Series 支持 nsmallest() 与 nlargest() 方法
- 4.5.2 DataFrame 也支持 nlargest 与 nsmallest 方法
- 4.6用多层索引的列排序
- 4.7 排名rank()
- 4.7.1 Series排名
- 4.7.2 DataFrame排名
- 5.数据的唯一性
一.pandas介绍
1.什么是pandas
- Pandas是Python里分析结构化数据的工具集
- pandas依赖于两个东西
基础是numpy:提供高性能矩阵运算,包含基础的数据模型
图形库matplotlib:python中提供数据可视化的库,
2.pandas用途
主要是结构化数据分析
不论是大数据还是人工智能,最重要的是数据
因而,从数据中挖掘出价值,就很重要
如何进行数据挖掘?
用pandas进行数据分析,先去探索下数据,是否有价值,
pandas可以处理海量数据,
提供了数据清洗功能,方便处理Nonedata,
3.课程内容
- Ipython
数据分析领域用Ipython解析器,而不用默认的python解析器,因为Ipython解析器有更方便的功能。 - pandas快速入门
- pandas核心数据结构和基础运算
两个核心数据结构,DataFrame(表格)和Series(表格中的列/行) - pandas高级运算内容
索引和数据选择
分组统计
时间序列
数据IO:数据从磁盘读出来再保存到磁盘 - 数据可视化
- 用pandas进行数据分析的实例
二.Ipython开发环境搭建
1.安装
-
安装python,python官网
-
安装jupyter,pip install jupyter
-
pip install numpy
-
pip install matplotlib
-
如果是windows用户,还需pip install pyreadline,
因为Ipython中有一个命令行自动完成的功能,入伙没有pyreadline,这个命令行自动完成的功能没法实现。
但是linux/mac用户不需要。 -
安装Ananconda,所有的包都有,不必再另行安装,可以直接拿来用
2.新建运行环境
以我的电脑系统为例:windows10版本
我的系统中安装了Anaconda,因而使用了Anaconda的python解释器,版本为python3.7。Anaconda集成了这里要用到的数据科学包,无需再次安装。
进入windows cmd
激活Anaconda的conda环境
# 进入windows cmd
conda activate #激活conda环境,进入bas。,conda的运行环境,其中集成了大量的包/库,可以直接调用
pip list #查看base中安装了什么包
#已经安装了jupyter,numpy,pandas,matplotlib,Ipython,pyreadline,没有安装Virtualenv
# Virtualenv 用于新建项目运行的虚拟环境,可以隔离不同项目
pip install virtualenv #在base中安装virtualenv
pip list #检查是否安装成功
# 新建运行虚拟环境
#进入windows cmd,用命令行新建一个.venvs文件夹(创建到自己定义的目录下),在里面安装虚拟环境。
#或者直接就在自定义的目录下在windows interfac环境下新建一个.venvs目录
cd F:\BaiShiEducation\pandas_practice
mkdir .venvs #创建.venvs文件夹,用来存储不同的虚拟环境
virtualenv --system-site-packages .venvs/ipthw #在.venvs目录下新建了一个虚拟环境,叫ipthw。这条命令将base中已经装好的包都继承过来了,即在虚拟环境中建立了api接口。
# 虚拟环境就是一个用来安装不同包/库的地方,这样可以针对不同项目使用不同版本的软件包了。
#在ipthw虚拟环境中查看可用的包
pip list #base中的包都继承了
.\.venvs\ipthw\Scripts\activate #激活虚拟环境
3.Ipython技巧
进入Ipython
- 这里显示出的数据会比标准python解释器格式化更好,特别是字典这类型数据
举例说明
对比python格式下的数据格式
- Ipython提供命令行自动补全的功能,
np.ran #摁tab键,会出现所有ran开头的函数
np.random #摁tab键,会出现所有random开头的函数
np.random.ran
- 可以快速查看文档
np.random.randn? #函数后面加问号
#而在python中用help
help(np.random.randn)
- Ipython中可以直接运行shell命令
魔术命令,magic
IPython 的「魔术」是 IPython 基于 Python 标准语法的一系列提升。魔术命令包括两种方法:(line magics):以 % 为前缀,在单个输入行上运行;(cell magics):以 %% 为前缀,在多个输入行上运行。
摁tab键可以自动把目录名称补全
!echo "print('hello pandas')" #命令行中打印"print('hello pandas')"
!echo "print('hello pandas')" > hello.py # echo前面加上感叹号或%表示执行shell命令,在shell中执行echo命令。加上>hello.py,意思是将内容打印到后面的文件中。
ls #查看当前目录中的内容
%run hello.py #运行hello.py 文件
!more hell.py #查看hello.py内容
# 统计代码的执行效率——timeit函数
a = np.random.randn(100,100)
%timeit a.dot(a)
# 表明,在Ipython中,shell命令和python命令可以一起使用
#查看Ipython标准说明文档
%quickref
# 查看Ipython的魔术命令大全,魔术命令关键字以%开头
%magic #查看Ipython的所有魔术命令,
4.Ipython notebook
这一部分可以参照https://wwwblogs/rangger/p/9520123.html
-
启动
注意要退出Ipython/python Interactive command prompt,然后在cmd下(此处是base下的虚拟环境)中输入命令:Ipython notebook/Jupyter notebook
Ipython notebook就是Ipython工具的可视化界面,跟命令行中操作在本质上是一样的,但是功能更强大。就跟python既可以在python Interactive command prompt中操作,同时在IDE中操作更方便一个道理。 -
Ipython magic命令
使用魔法函数可以简单的实现一些单纯python要很麻烦才能实现的功能
在notebook中可以使用shell命令,即Ipython magic命令。 -
notebook快捷键
help—keyboard shortcuts
运行命令的快捷键—ctrl+enter
运行当前cell命令且自动在下面新建cell—shift+enter -
insert cell插入操作框
-
查询函数的帮助文档
函数后加?
docstring,文档字符串, -
定义函数,同一个方框内调用或在下一个方框内调用
-
显示图片
用magic 命令设置内容的格式
%matplotlib inline #magic函数
举例说明
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2*np.pi, num=100) #取0到2pai的数,中间取100个,即0到2pai分成100份
y = np.sin(x)
plt.plot(x,y)
三.numpy简介
- 特性
高性能,科学计算和数据分析的基础包,是所有高级数据分析工具的构建基础
面向数组的思维模式
pandas处理的数据都是表格数据,实际上就是数组
举例说明:
一维数组
二维数组
直接写入内容
np.arange()函数创建数组
python中range创建list,numpy中arange创建维度数组
reshape()改变数组维度,
numpy提供函数创建特殊数组
可以创建多维数组
科学技术算领域为什么有三维数组?
举例说明:有一个图片,长为100个像素,宽为200个像素,这就是一个100200数组,每个像素中有一个RGB(31数组)。所以一个100200图片,一个像素的颜色是用RGB三个字节来表示的,那么用数组来表示,就是100200*3的一个三维数组。
np.eyes(),对角数组,对角线是1,其他元素是0
reshape()转换已有数组的维度
数组索引
二维数组的索引
data[1:3] 行索引
data[:,2:4]列索引
data[1:3,2:4] 行和列索引
用数组去索引
data[[1,3],[2,3]] 返回两个元素,第一个是行1列2,第二个是行3列3
比较数组中的元素和另外一个元素,返回结果是元素为布尔型的array。
用比较的结果,布尔型array作为索引,array中结果为true的元素列出来。这是分解写法
常用写法为data[data>10],选择data中大于10的所有元素,构成一个新数组
选择出数组中的偶数元素
数组运算
加法,数组中每个元素之间的计算,结果构成一个新数组
可用add函数
数组的乘法和矩阵的内积不同
矩阵的内积:x.dot(y)
数组的除法,默认是int型,除法结果不够1,就结果为0
需要转换为float型,结果为小数
内置计算函数
比如sqrt,平方根
转置数组
np.linespace(),指定范围和等分多少份
四.pandas入门
1.官方网址:
https://www.pypandas/docs/getting_started/10min.html
质量最高
2.数据表创建、访问、更改
2.1创建pandas对象
- series,带索引的一维数据结构
import pandas as pd
import numpy as np
# 创建关键数据结构
#数据结构series,代表一行/一列,最简单的创建方式就是传递一个列表。其中包含索引和值,索引是自动创建的
s = pd.Series([1,3,5,np.NaN,8,4]) #NaN,not a number,不是数值,
- DataFrame ,二维数组
# 二维数组,dataframe
dates = pd.date_range( #创建日期序列,pd.date_range函数。创建日期序列作为索引
dates = pd.date_range('20160301',periods=6) #前面是起始日期,periods表示创建几个日期。
data = pd.DataFrame(np.random.randn(6,4),index=dates,columns=list('ABCD'))
#np.random.randn(6,4),创建6行4列的随机数,作为索引内容。行索引是index,列索引是columns。
data.shape #数据类型是6行4列
data.values #数组的值
- 字典dict来创建DateFrame二维数组
d = {'A':1,'B':pd.Timestamp('20130301'),'C':range(4),'D':np.arange(4)} #pd.Timestamp,时间戳。ABCD为列标签的表,这个表中有4行,C和D元素个数要一样,不一样会报错。
转化为DateFrame
df = pd.DataFrame(d)
df.dtypes #可看到每一列的数据类型
df.A #这些列可通过属性来访问,A列的数据
type(df.B) #df中B列类型
在pandas中series表示一个行/列数据
2.2查看数据
- 查看DataFrame
data.head() #表格很大,只查看前几行,默认是前五行
data.head(2) #前两行数据
data.tail() #查看尾部数据
data.index #index行标签,
data.columns #columns列标签
data.values #值,numpy中的array
data.describe() #查看data的整体情况,是统计数据,按照列统计
data.T #转置,行变为列
data.T.shape #转置后的形状
2.3选择数据
- DataFrame排序
data.sort_index(axis=1) #用列标签排序,axis=1,升序排序
data.sort_index(axis=1,ascending=False) #ascending=False,降序排序
data.sort_index(axis=0,ascending=False)#axis=0,按照行排序
data.sort_values(by='A') #用值排序,用某一列的值排序.默认从小到大。A列的值
- DataFrame用python格式访问数据
data['A'] #选择A列,选择某一列的值
data.A
data[2:4] #访问2到4行
data['20160302','20160305'] #用行标签访问数据
# python格式的访问数据,效率低
- 用data.loc()函数访问数据
# 用data.loc()函数直接通过行/列标签访问数据
# 用data.iloc[]函数访问内置标签来访问数据
data.loc[:,['B','C']] #访问B和C两列数据
data.loc['20160302':'20160305',['B','C']] #访问行20160302:20160305和列B:C的数据
data.loc['20160302','B'] #访问特定值,20160302行B列
#访问某个值更高效的方法,data.at[]函数,访问效率更高,但是要传原生数据结构,而不是直接使用日期。
data.at[pd.Timestamp('20160302'),'B')
- 内置访问。data.iloc[]
访问某行某列的某个元素更高效方法,data.iat[]
用%timeit magic函数来测试.iloc[]访问数据是否比.iat[]访问数据效率高
- 布尔索引访问
data[data,A>0] #data中A列的所有大于0的数据
data[data>0] #data中所有大于0的元素。结果中NaN表示所有大于0的数据都被过滤掉了
# isin函数
data2 = data.copy() #先拷贝一份数据出来
data2
tag = ['a']*2 + ['b']*2 + ['c']*2 #生成tag序列
data2['TAG'] = tag #在data2中增加TAG列
data2
data2[data2.TAG.isin(['a','c']) #按照data2中的TAG列,过滤出TAG列中的a、c元素将data2列表过滤出来
- 修改表格数据
# 修改元素
# 修改一列或一行
#生成一个新的range来修改某一列。用列表修改,元素个数要匹配。
#用一个标量给整个列/行赋值,也可以给多喝行/列赋值,不用管匹配个数
# 可以创建一个行列和原来的表相等的表,就直接覆盖掉原来的表
3.DataFrame的操作
3.1处理缺失数据missing data
- 建表
%matplotlib inline #表示图片直接画在网页上
# 导进来所有需要的库/环境
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
dates = pd.date_range('20160301',periods=6) #创建一个日期序列
df = pd.DataFrame(np.random.randn(6,4),index=dates,columns=list('ABCD')) #np.random.randn(6,4),创建6行4列的数组,index=dates行标签为6个日期序列,columns=list('ABCD')列标签为ABCD。创建这个表。
- 更改表
# 制造一些数据缺失项
# 更改原有的表,reindex重新索引
df1 = df.reindex(index=dates[0:4], columns=list(df.columns)+['E']) #.reindex重新进行索引.index=dates[0:4],重新索引的行标签。列标签,columns=list(df.columns)+['E'],在原来的列上再加一个列E.新加上的列标签E没有给定值,默认是NaN,空值missing data。
# 给表赋值
df1.loc[dates[1:3],'E'] = 2# loc[dates[1:3],'E']定位到表的index标签,和columns标签,可直接通过标签名访问。
df1
- 处理missing data缺失数据
# 丢掉missing data
df1.dropna()
# 用默认值替换掉空值
df1.fillna(value=5)
dropna()和fillna()返回的都是复制后的
3.2数据运算
- 判断一个表中是否包含空数据
空数据地方返回true,其他返回false
表格很大的话,没法目视判断出哪个是空数据,
底下会打出有空值大的列
但是如果有很多列,一样目视难以扎到,
返回值表示表中有空数据
- 空数据不参与计算
按列求平均值
按行求平均值
- 累加值
空值不参与计算
dates = pd.date_range('20160301',periods=6)
s = pd.Series([1,3,5,np.nan,6,8],index=dates).shift(2) # pd.Series([1,3,5,np.nan,6,8],index=dates),c创建Series一维表,index为dates。shift()函数,对数据进行向下移动,默认向下移动1位。
#df-s 二维表减去一维序列,是表的每一列减s,
df.sub(s,axis='index') #axis='index',用行标签作为关键字索引
s中的NaN值,不参与运算,在减法之后的新表中,不参与运算的部分为NaN.
实际应用中,先把空值NaN作预处理,然后再进行计算
df.apply()函数,接收另一个函数作为参数。先计算表的累加值,按照列计算,下一行是上面行的和,然后将这些累加值赋值给表中,按照列赋值
** df.apply()函数,括号中接收函数作为参数,把df表中的列传给()中的函数去处理**
举例如下
- counts函数和mode函数
先创建一个series,
counts()函数查看表中的值有几个,mode()函数查看表中的值出现最大次数的数是哪个
3.3数据合并
- 数据合并
先创建一个DataFrame
取出几行数据
将以上3个表合并起来
df1 = pd.concat([df.iloc[:3],df.iloc[3:7],df.iloc[7:]]) #concat,意为合并多个数组;合并多个字符串,
df1和df是相等的,比较df1和df
第二个合并方法:
新建两个表
left = pd.DataFrame({'key':['foo','foo'],'lval':[1,2]})
right = pd.DataFrame({'key':['foo','foo'],'rval':[4,5]}) #用dict创建DataFrame
将他们当作两个表,最左边的0,1是identity,唯一标识符,key是两个表连接的外键,
用pd.merge(left,right,on=‘key’)来关联两个表
pd.merge(left,right,on='key')
# SELECT * FROM left INNER JOIN right ON left,key = right.key
**第三个合并方法:**直接插入一行
df.append(s,ignore_index=True) #ignore_index=True,忽略index。按照ABCD插入,插入到了最后一行
#新建一个5列的series,再去append
s = pd.Series(np.random.randint(1,5,size=5),index=list('ABCDE')
df.append(s,ignore_index=True)
新插入的第五列都是缺失值,只有底下最后一行有值
但是df还是没变,在append时,操作的是df的copy
3.4数据分组
- 分类统计
# groupby()函数来分组
df.groupby('A').sum() #用A列给df表分组,并求和
这里分组分为两个步骤:1.对数据按照一定规则进行分组,2.把分出来的组按照一定规则进行计算,bar分为一个组,求和,foo分为一个组,求和,再把这些组分为C和D两个列
df.groupby(['A','B']).sum() #先按照A列和B列一起分组,根据A县分为两个大组,再根据B分为6个小组,最后返回双索引结构的表。
df.groupby(['B','A']).sum() #先按照B分组,再按照A分组
4.其他操作
4.1数据整形
把行索引和列索引互换
先导入环境
- 创建一个复杂的表
创建一个元组列表作为表格的行索引
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表,也可将一个二维array解压为两个一维array。在 Python 3.x 中为了减少内存,zip() 返回的是一个对象。如需展示列表,需手动 list() 转换。
将元组列表作为表格的行索引
#这个索引是双层索引,双层索引可以给这个索引命名
#创建索引
index = pd.MultiIndex.from_tuples(tuples,names=['first','second'])
# MultiIndex表示多级索引,它是从Index继承过来的,其中多级标签用元组对象来表示。names=['first','second']是给两级标签命名。
df = pd.DataFrame(np.random.randn(0,2),index=index,column=['A','B']) #index是行标签,columns是列标签
- 列索引变为行索引
stacked = df.stack() #stack函数
stacked.unstack() #转化回来
stacked.unstack().unstack() #再转化一次,将第二层行索引转化为列索引
将原本的列索引变为了行索引,现在有三层行索引了
查看索引值,三层索引
将索引转化回来
再转化一次
4.2数据透视
只看表中的一部分数据
新建一个dataframe
以A、B两列为行索引,以C为列索引,针对D列的数据
df.pivot_table(values=['D'],index=['A','B'],columns=['C']) #以A、B两列为行索引,以C为列索引,针对D列的数据。这样定位出的数据在原表中不存在的话,新表中该位置就为NaN.
pivot,枢轴;中心点;中心;旋转运动
df.pivot_table(values=['E'],index=['A'],columns=['C'])
上面表里的值是这样来的
这就是说,数据透视表的数据有多个时,会求平均值,数据透视表中对应的没有数据时,就用NaN表示。
4.3时间序列
pandas提供了功能强大的时间处理函数
- pd.date_range()函数
rng = pd.date_range('20160301',periods=600,freg='s') #起始时间是20160301,产生600个时间,单位为秒。
# 创建一个值和上面的时间序列对应起来
a = pd.Series(np.random.randint(0,500,len(rng)),index=rng) #len(rng),长度就是rng的长度,行索引也是rng
这就跟股票的交易数据一样,每秒都有一个交易量
这么多数据,不利于分析,对其重采样
s.resample('2Min',how='sum') #重采样范围是2分钟,用求和的方式
求平均值的重采样方法
- .period_range()方法
#.period_range()方法建立时间序列
rng = pd.period_range('2000Q1','2016Q1',freg='Q') #以季度为单位,从2000Q1到2016Q1
转换为时间日期格式
rng.to_timestamp() #转换为时间日期格式
- 时间运算
- category,类别数据
新建dataframe
添加一个列,添加类别数据。
添加的这个列的数据等于raw_grade列的数据,astype,数据类型为category
重新赋值
排序,根据grade来排序,不是以名来排序,而是根据值来排序,值从raw_grade过来
4.4数据可视化
新建一个series
对其求和,求累加值
把数据可视化
4.5 数据读写,即载入与保存
创建一个dataframe
将创建的dataframe写入磁盘.to_csv()函数
%ls 查看当前目录下的文件
查看文件内容,%more data.csv
读取文件中的数据,pd.read_csv(‘data.csv’)
读出来的数据有个异常,多了一行索引值。
指定索引列,
pandas支持多种数据读写,包括excel,hdf,
五.实例Movielens电影数据分析
Movielens是电影的投票数据
1. 数据准备
下载地址:
https://grouplens/datasets/movielens/
README.txt是这个Dataset的介绍
下载下数据,放到当前操作目录下
ls目录查看当前目录下的内容
更改操作目录
查看README文档
README中介绍了文件中其他三个.dat文件的信息,
ratings.dat rating,等级,等级评定,
users.dat
movies.dat
直接查看三个数据文wenjian件,打开.dat文件
users.dat
movies.dat
rating.dat
这些数据是清洗过的,这些数据会保证每个用户至少对20个电影进行了评分。所以这些数据比较有代表性
2.操作
2.1用pandas将数据导入进来
- 读取三个.dat文件
import pandas as pd
# 将用户读出来。读user.dat时要注意,要把列的名称显示出来.因为user.dat文件中只有数据,没有列名称。
# user.dat中,列标签有UserID::Gender::Age::Occupation::Zip-code。用户ID,性别,年龄,职业,邮编
#
unames = ['user_id','gender','Age','Occupation','Zip-code']
# 读文件
users = pd.read_csv('users.dat',sep='::',header=None,names=unames) #第一个参数是要读的文件名,文件名不在当前操作目录环境下,文件名前要加上目录。.dat文件中每列之间用:分割,所以设置下分割符,sep='::'..dat文件中的表没有表头,hearder=None。设置列的名称,names=unames.
# 查看
print (len(users)) #查看读取出来的表的长度
users.head(5) #查看前5条
结果出现警告
C语言引擎不支持某些特性,要用python引擎来实现。这是因为read_csv()函数中的解析器是有两个版本,一个是python实现的,一个是C语言实现的,C语言实现的效率更高,但是特性支持有限,python支持的效率低,但是功能强大。
共有6040条记录
这些列标签在README中有说明
用相同方法将movies.dat,ratings.dat导入进来
rating_names = ['User_id','Movie_id','Rating','Timestamp']
ratings = pd.read_csv('ratings.dat',sep='::',header=None,names=rating_names)
movie_names = ['Movie_id','Title','Genres']
movies = pd.read_csv('movies.dat',sep='::',header=None,names=movie_names)
上面的三张表就类似于数据库中的三张表,在pandas中,要把数据合并起来才有利于分析
- 将三个表合并起来
data = pd.merge(pd.merge(users,ratings,on='User_id'),movies,on='Movie_id') #先将users表和ratings表合并,再跟movies合并,调用了两次pd.merge函数.users表和ratings表合并根据共同的User_id列名,之后根据共同的Movie_id列明合并。
# pandas中的merge()函数类似于SQL中join的用法,可以将不同数据集依照某些字段(属性)进行合并操作,得到一个新的数据集。就是根据外键来合并。
print(len(data))
2.2操作数据
- 查看数据
# 查看user_id为1的用户,他的所有电影评分数据
data[data.User_id == 1]
- 计算不同性别的平均得分,即每一部电影,所有男性的平均评分是多少,所有女性的平均评分是多少?
rating_by_gender = data.pivot_table(values='rating',index='title',columns='gender',aggfunc='mean')
#按性别评分,变量取名为rating_by_gender。用数据透视表,data.pivot_table。统计值选择rating列标签。统计条件,行条件为index='title',列条件为columns='gender',统计出来用函数aggfunc='mean'来进一步计算每部电影不同性别评分的平均值。
从这里可以看到哪些电影男女之间的评分分歧很大,算出哪个电影的男女评分差异最大。再加上一列,
rating_by_gender['diff']=rating_by_gender.F-rating_by_gender.M
#添加一列,命名为diff,rating_by_gender('diff'),这一列的值等于男性评分减去女性评分,rating_by_gender.F-rating_by_gender.M 。注意dataframe的赋值方法
rating_by_gender.head(10) #显示前10列
#算出男女分歧最大的电影,用diff列去排序
rating_by_gender.sort_values(by='diff',ascending=True).head(10)
# 给rating_by_gender表排序,排序值为sort_values,by='diff',按照正序排列,从小到大,ascending=True。显示结果的前十个数据。
# 按照降序排列
rating_by_gender.sort_values(by='diff',ascending=False).head(10)
- 哪些电影评分的人数最多?就意味着看的人数最多
按照电影名title分组,分组出来的电影就是每个电影被评分的次数,然后求size,就是电影总共获取了多少评分?
rating_by_title=data.groupby('Title').size()
rating_by_title.head(10)
# 对比,后面不加size(),结果就是相同的电影名聚集在一起
rating_by_title=data.groupby('Title')
rating_by_title.head(10)
rating_by_title=data.groupby(‘Title’).size(),其实就是按Title分组后,再去按Title把个数统计出来。
# 对统计结果排序
rating_by_title.sort_values().head(10)
# rating_by_title表是一个series,键值对应,因而对值排序,sort_values()。默认升序
#降序排列
rating_by_title.sort_values(ascending=False).head(10)
以上就是最热门的电影
- 查看评分最高的电影
mean_rating=data.pivot_table(values='Rating',index='Title',aggfunc='mean')
#data.pivot_table()数据透视表分析,分析对象(分析的数据核心)是values='Rating'。分析标准是按照电影名,index='Title',行为Title。按照mean计算。
mean_rating.head(10)
#对比下面
mean_rating=data.pivot_table(values='Rating',index='Title')
#排序找出前二十大高评分电影
mean_rating.sort_values(by='Rating',ascending=False).head(20)
- 找出很多人看,同时评分也很高的电影
找出看的人最多的前十大热门电影,获得找出平均得分的电影的表,然后找出前10大热门电影的评分
# 电影出现数大于1000,即评价人数超过1000的热门电影
hot_movies = rating_by_title[rating_by_title>1000]
#前10大热门电影
top_10_movies = hot_movies.sort_values(ascending=False).head(10)
top_10_movies
type(top_10_movies)
# 获得每个电影的平均评分,并且消除了重复出现的电影(由于评价人不同导致),表完全变为电影名和评分组合成的
mean_rating=data.pivot_table(values='Rating',index='Title',aggfunc='mean')
top_20_mean_ratings = mean_rating.sort_values(by='Rating',ascending=False).head(20)
top_20_mean_ratings
#前十大热门电影的评分
top_10_movies_rating=mean_rating[mean_rating.index.isin(top_10_movies.index)] #注意一个表使用另一个表的index的方法mean_rating.index.isin(top_10_movies.index)两个表的index的交集
top_10_movies_rating
#反之,找出评分前二十的电影的热门程度(即观看人数的多少)
top_20_mean_rating_movies=rating_by_title[rating_by_title.index.isin(top_20_mean_ratings.index)]
top_20_mean_rating_movies
#真正的好电影是由足够多人看,并且评分高
用pivot_table()解决这个问题
# 找出评价人数超过1000的热门电影,hot_movies
# 找出hot_movies的评分
hot_movies_rating=mean_rating[mean_rating.index.isin(hot_movies.index)]
# 对热门电影的评分排序,排在前面的就是真正的好电影
top_10_good_movies=hot_movies_rating.sort_values(ascending=False).haed(10)
六.Pandas核心数据结构
参照pandas官网资料:数据结构简介https://www.pypandas/docs/getting_started/dsintro.html#series
1.Series
来源于pandas—Series官方文档https://www.pypandas/docs/getting_started/dsintro.html#series
1.1定义及创建
Series 是带标签的一维数组,可存储整数、浮点数、字符串、Python 对象等类型的数据。轴标签统称为索引。调用 pd.Series 函数即可创建 Series:
s = pd.Series(data, index=index)
上述代码中,data 支持以下数据类型:
Python 字典
多维数组
标量值(如,5)
index 是轴标签列表。不同数据可分为以下几种情况:
- 多维数组
data 是多维数组时,index 长度必须与 data 长度一致。没有指定 index 参数时,创建数值型索引,即 [0, …, len(data) - 1]。
In [3]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
s
Out[4]:
a 0.469112
b -0.282863
c -1.509059
d -1.135632
e 1.212112
dtype: float64
In [5]: s.index
Out[5]: Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
In [6]: pd.Series(np.random.randn(5))
Out[6]:
0 -0.173215
1 0.119209
2 -1.044236
3 -0.861849
4 -2.104569
dtype: float64
注意
Pandas 的索引值可以重复。不支持重复索引值的操作会触发异常。其原因主要与性能有关,有很多计算实例,比如 GroupBy 操作就不用索引。
- 字典
Series 可以用字典实例化:
In [7]: d = {'b': 1, 'a': 0, 'c': 2}
In [8]: pd.Series(d)
Out[8]:
b 1
a 0
c 2
dtype: int64
注意
data 为字典,且未设置 index 参数时,如果 Python 版本 >= 3.6 且 Pandas 版本 >= 0.23,Series 按字典的插入顺序排序索引。
Python < 3.6 或 Pandas < 0.23,且未设置 index 参数时,Series 按字母顺序排序字典的键(key)列表。
上例中,如果 Python < 3.6 或 Pandas < 0.23,Series 按字母排序字典的键。输出结果不是 [‘b’, ‘a’, ‘c’],而是 [‘a’, ‘b’, ‘c’]。
如果设置了 index 参数,则按索引标签提取 data 里对应的值。
In [9]: d = {'a': 0., 'b': 1., 'c': 2.}
In [10]: pd.Series(d)
Out[10]:
a 0.0
b 1.0
c 2.0
dtype: float64
In [11]: pd.Series(d, index=['b', 'c', 'd', 'a'])
Out[11]:
b 1.0
c 2.0
d NaN
a 0.0
dtype: float64
注意
Pandas 用 NaN(Not a Number)表示缺失数据。
- 标量值
data 是标量值时,必须提供索引。Series 按索引长度重复该标量值。
In [12]: pd.Series(5., index=['a', 'b', 'c', 'd', 'e'])
Out[12]:
a 5.0
b 5.0
c 5.0
d 5.0
e 5.0
dtype: float64
1.2操作
1.2.1Series 类似numpy多维数组
Series 操作与 ndarray 类似,支持大多数 NumPy 函数,还支持索引切片。
In [3]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [4]: s
Out[4]:
a 0.469112
b -0.282863
c -1.509059
d -1.135632
e 1.212112
dtype: float64
# 单个元素取出来是数值
In [13]: s[0]
Out[13]: 0.4691122999071863
# 一组元素取出来是Series
In [14]: s[:3]
Out[14]:
a 0.469112
b -0.282863
c -1.509059
dtype: float64
In [15]: s[s > s.median()] #先取出单个元素为属猪,再让Series与数值比较,取出Series
Out[15]:
a 0.469112
e 1.212112
dtype: float64
In [16]: s[[4, 3, 1]] #用列表作为索引,索引切片
Out[16]:
e 1.212112
d -1.135632
b -0.282863
dtype: float64
In [17]: np.exp(s) #以自然常数e为底的指数函数,将s中的数作为e的次幂
Out[17]:
a 1.598575
b 0.753623
c 0.221118
d 0.321219
e 3.360575
dtype: float64
- 和 NumPy 数组一样,Series 也支持 dtype。
In [18]: s.dtype
Out[18]: dtype('float64')
Series 的数据类型一般是 NumPy 数据类型。不过,Pandas 和第三方库在一些方面扩展了 NumPy 类型系统,即扩展数据类型。比如,Pandas 的类别型数据与可空整数数据类型。更多信息,请参阅数据类型 。
- Series.array 用于提取 Series 数组。
In [19]: s.array
Out[19]:
<PandasArray>
[ 0.4691122999071863, -0.2828633443286633, -1.5090585031735124,
-1.1356323710171934, 1.2121120250208506]
Length: 5, dtype: float64
Series.array 一般是扩展数组。简单说,扩展数组是把 N 个 numpy.ndarray 包在一起的打包器
Series 只是类似于多维数组,提取真正的多维数组,要用 Series.to_numpy()
In [20]: s.to_numpy()
Out[20]: array([ 0.4691, -0.2829, -1.5091, -1.1356, 1.2121])
Series 是扩展数组 ,Series.to_numpy() 返回的是 NumPy 多维数组。
1.2.2Series 类似字典
Series 类似固定大小的字典,可以用索引标签提取值或设置值:
In [3]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [4]: s
Out[4]:
a 0.469112
b -0.282863
c -1.509059
d -1.135632
e 1.212112
dtype: float64
In [21]: s['a'] #用键访问
Out[21]: 0.4691122999071863
In [22]: s['e'] = 12 #字典方式赋值
In [23]: s
Out[23]:
a 0.469112
b -0.282863
c -1.509059
d -1.135632
e 12.000000
dtype: float64
# 可用字典方式增加元素
In [24]: 'e' in s
Out[24]: True
In [25]: 'f' in s
Out[25]: False
引用 Series 里没有的标签会触发异常:
s['f']
KeyError: 'f'
get 方法可以提取 Series 里没有的标签,返回 None 或指定默认值:
In [26]: s.get('f')
In [27]: s.get('f', np.nan)
Out[27]: nan
1.2.3矢量操作与对齐Series标签
In [3]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [4]: s
Out[4]:
a 0.469112
b -0.282863
c -1.509059
d -1.135632
e 1.212112
dtype: float64
In [28]: s + s
Out[28]:
a 0.938225
b -0.565727
c -3.018117
d -2.271265
e 24.000000
dtype: float64
In [29]: s * 2
Out[29]:
a 0.938225
b -0.565727
c -3.018117
d -2.271265
e 24.000000
dtype: float64
In [30]: np.exp(s)
Out[30]:
a 1.598575
b 0.753623
c 0.221118
d 0.321219
e 162754.791419
dtype: float64
Series 和多维数组的主要区别在于, Series 之间的操作会自动基于标签对齐数据。因此,不用顾及执行计算操作的 Series 是否有相同的标签。
In [31]: s[1:] + s[:-1]
Out[31]:
a NaN
b -0.565727
c -3.018117
d -2.271265
e NaN
dtype: float64
操作未对齐索引的 Series, 其计算结果是所有涉及索引的并集。如果在 Series 里找不到标签,运算结果标记为 NaN,即缺失值。编写无需显式对齐数据的代码,给交互数据分析和研究提供了巨大的自由度和灵活性。Pandas 数据结构集成的数据对齐功能,是 Pandas 区别于大多数标签型数据处理工具的重要特性。
注意
总之,让不同索引对象操作的默认结果生成索引并集,是为了避免信息丢失。就算缺失了数据,索引标签依然包含计算的重要信息。当然,也可以用dropna 函数清除含有缺失值的标签。
1.2.4名称属性
Series 支持 name 属性:
In [32]: s = pd.Series(np.random.randn(5), name='something')
In [33]: s
Out[33]:
0 -0.494929
1 1.071804
2 0.721555
3 -0.706771
4 -1.039575
Name: something, dtype: float64
In [34]: s.name
Out[34]: 'something'
一般情况下,Series 自动分配 name,特别是提取一维 DataFrame 切片时,详见下文。
0.18.0 版新增。
pandas.Series.rename() 方法用于重命名 Series 。
In [35]: s2 = s.rename("different")
In [36]: s2.name
Out[36]: 'different'
注意:s 与 s2 指向不同的对象。
2.DataFrame
2.1定义及创建
DataFrame 是由多种类型的列构成的二维标签数据结构,类似于 Excel 、SQL 表,或 Series 对象构成的字典。DataFrame 是最常用的 Pandas 对象,与 Series 一样,DataFrame 支持多种类型的输入数据:
一维 ndarray、列表、字典、Series 字典
二维 numpy.ndarray
结构多维数组或记录多维数组
Series
DataFrame
除了数据,还可以有选择地传递 index(行标签)和 columns(列标签)参数。传递了索引或列,就可以确保生成的 DataFrame 里包含索引或列。Series 字典加上指定索引时,会丢弃与传递的索引不匹配的所有数据。
没有传递轴标签时,按常规依据输入数据进行构建。
注意
Python > = 3.6,且 Pandas > = 0.23,数据是字典,且未指定 columns 参数时,DataFrame 的列按字典的插入顺序排序。
Python < 3.6 或 Pandas < 0.23,且未指定 columns 参数时,DataFrame 的列按字典键的字母排序。
2.1.1用 Series 字典或字典生成 DataFrame
生成的索引是每个 Series 索引的并集。先把嵌套字典转换为 Series。如果没有指定列,DataFrame 的列就是字典键的有序列表。
In [37]: d = {'one': pd.Series([1., 2., 3.], index=['a', 'b', 'c']),
....: 'two': pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
....:
In [38]: df = pd.DataFrame(d)
In [39]: df
Out[39]:
one two
a 1.0 1.0
b 2.0 2.0
c 3.0 3.0
d NaN 4.0
In [40]: pd.DataFrame(d, index=['d', 'b', 'a'])
Out[40]:
one two
d NaN 4.0
b 2.0 2.0
a 1.0 1.0
In [41]: pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
Out[41]:
two three
d 4.0 NaN
b 2.0 NaN
a 1.0 NaN
index 和 columns 属性分别用于访问行、列标签:
注意
指定列与数据字典一起传递时,传递的列会覆盖字典的键。
In [42]: df.index
Out[42]: Index(['a', 'b', 'c', 'd'], dtype='object')
In [43]: df.columns
Out[43]: Index(['one', 'two'], dtype='object')
2.1.2用列表构成的字典生成DataFrame
列表长度必须相同。如果传递了索引参数,index 的长度必须与列表一致。如果没有传递索引参数,生成的结果是 range(n),n 为数组长度。
In [44]: d = {'one': [1., 2., 3., 4.],
....: 'two': [4., 3., 2., 1.]}
....:
In [45]: pd.DataFrame(d)
Out[45]:
one two
0 1.0 4.0
1 2.0 3.0
2 3.0 2.0
3 4.0 1.0
In [46]: pd.DataFrame(d, index=['a', 'b', 'c', 'd'])
Out[46]:
one two
a 1.0 4.0
b 2.0 3.0
c 3.0 2.0
d 4.0 1.0
2.1.3用元组构成的列表生成DataFrame
In [47]: data = np.zeros((2, ), dtype=[('A', 'i4'), ('B', 'f4'), ('C', 'a10')])
In [48]: data[:] = [(1, 2., 'Hello'), (2, 3., "World")]
In [49]: pd.DataFrame(data)
Out[49]:
A B C
0 1 2.0 b'Hello'
1 2 3.0 b'World'
In [50]: pd.DataFrame(data, index=['first', 'second'])
Out[50]:
A B C
first 1 2.0 b'Hello'
second 2 3.0 b'World'
In [51]: pd.DataFrame(data, columns=['C', 'A', 'B'])
Out[51]:
C A B
0 b'Hello' 1 2.0
1 b'World' 2 3.0
2.1.4用字典构成的列表生成DataFrame
In [52]: data2 = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]
In [53]: pd.DataFrame(data2)
Out[53]:
a b c
0 1 2 NaN
1 5 10 20.0
In [54]: pd.DataFrame(data2, index=['first', 'second'])
Out[54]:
a b c
first 1 2 NaN
second 5 10 20.0
In [55]: pd.DataFrame(data2, columns=['a', 'b'])
Out[55]:
a b
0 1 2
1 5 10
2.1.5用元组构成的字典生成DataFrame
元组字典可以自动创建多层索引 DataFrame。
n [56]: pd.DataFrame({('a', 'b'): {('A', 'B'): 1, ('A', 'C'): 2},
....: ('a', 'a'): {('A', 'C'): 3, ('A', 'B'): 4},
....: ('a', 'c'): {('A', 'B'): 5, ('A', 'C'): 6},
....: ('b', 'a'): {('A', 'C'): 7, ('A', 'B'): 8},
....: ('b', 'b'): {('A', 'D'): 9, ('A', 'B'): 10}})
....:
Out[56]:
a b
b a c a b
A B 1.0 4.0 5.0 8.0 10.0
C 2.0 3.0 6.0 7.0 NaN
D NaN NaN NaN NaN 9.0
# 字典的key是元组,包含两个元素。字典的value是字典,这个字典中以元组为key,以常数为值。
2.1.6用Series生成DataFrame
生成的 DataFrame 继承了输入的 Series 的索引,如果没有指定列名,默认列名是输入 Series 的名称
DataFrame的索引方式,本质上都会试图从数据里面找出这个索引,索引找不到时就会自动分配,从0开始分配数字索引,这个索引可以去指定,对已有的索引会作索引对其的操作。
2.2特性及操作
2.2.1提取、添加、删除列
DataFrame 就像带索引的 Series 字典,提取、设置、删除列的操作与字典类似:
In [61]: df['one']
Out[61]:
a 1.0
b 2.0
c 3.0
d NaN
Name: one, dtype: float64
In [62]: df['three'] = df['one'] * df['two']
In [63]: df['flag'] = df['one'] > 2
In [64]: df
Out[64]:
one two three flag
a 1.0 1.0 1.0 False
b 2.0 2.0 4.0 False
c 3.0 3.0 9.0 True
d NaN 4.0 NaN False
删除(del、pop)列的方式也与字典类似:
In [65]: del df['two']
In [66]: three = df.pop('three')
In [67]: df
Out[67]:
one flag
a 1.0 False
b 2.0 False
c 3.0 True
d NaN False
标量值以广播的方式填充列:
In [68]: df['foo'] = 'bar'
In [69]: df
Out[69]:
one flag foo
a 1.0 False bar
b 2.0 False bar
c 3.0 True bar
d NaN False bar
插入与 DataFrame 索引不同的 Series 时,以 DataFrame 的索引为准:
In [70]: df['one_trunc'] = df['one'][:2]
In [71]: df
Out[71]:
one flag foo one_trunc
a 1.0 False bar 1.0
b 2.0 False bar 2.0
c 3.0 True bar NaN
d NaN False bar NaN
可以插入原生多维数组,但长度必须与 DataFrame 索引长度一致。
默认在 DataFrame 尾部插入列。insert 函数可以指定插入列的位置:
In [72]: df.insert(1, 'bar', df['one'])
In [73]: df
Out[73]:
one bar flag foo one_trunc
a 1.0 1.0 False bar 1.0
b 2.0 2.0 False bar 2.0
c 3.0 3.0 True bar NaN
d NaN NaN False bar NaN
2.2.2用方法链分配新列
DataFrame 提供了 assign() 方法,可以利用现有的列创建新列。
In [74]: iris = pd.read_csv('data/iris.data')
In [75]: iris.head()
Out[75]:
SepalLength SepalWidth PetalLength PetalWidth Name
0 5.1 3.5 1.4 0.2 Iris-setosa
1 4.9 3.0 1.4 0.2 Iris-setosa
2 4.7 3.2 1.3 0.2 Iris-setosa
3 4.6 3.1 1.5 0.2 Iris-setosa
4 5.0 3.6 1.4 0.2 Iris-setosa
In [76]: (iris.assign(sepal_ratio=iris['SepalWidth'] / iris['SepalLength'])
....: .head())
....:
Out[76]:
SepalLength SepalWidth PetalLength PetalWidth Name sepal_ratio
0 5.1 3.5 1.4 0.2 Iris-setosa 0.686275
1 4.9 3.0 1.4 0.2 Iris-setosa 0.612245
2 4.7 3.2 1.3 0.2 Iris-setosa 0.680851
3 4.6 3.1 1.5 0.2 Iris-setosa 0.673913
4 5.0 3.6 1.4 0.2 Iris-setosa 0.720000
上例中,插入了一个预计算的值。还可以传递带参数的函数,在 assign 的 DataFrame 上求值。
In [77]: iris.assign(sepal_ratio=lambda x: (x['SepalWidth'] / x['SepalLength'])).head()
Out[77]:
SepalLength SepalWidth PetalLength PetalWidth Name sepal_ratio
0 5.1 3.5 1.4 0.2 Iris-setosa 0.686275
1 4.9 3.0 1.4 0.2 Iris-setosa 0.612245
2 4.7 3.2 1.3 0.2 Iris-setosa 0.680851
3 4.6 3.1 1.5 0.2 Iris-setosa 0.673913
4 5.0 3.6 1.4 0.2 Iris-setosa 0.720000
assign 返回的都是数据副本,原 DataFrame 不变。
未引用 DataFrame 时,传递可调用的,不是实际要插入的值。这种方式常见于在操作链中调用 assign 的操作。例如,将 DataFrame 限制为花萼长度大于 5 的观察值,计算比例,再制图:
In [78]: (iris.query('SepalLength > 5')
....: .assign(SepalRatio=lambda x: x.SepalWidth / x.SepalLength,
....: PetalRatio=lambda x: x.PetalWidth / x.PetalLength)
....: .plot(kind='scatter', x='SepalRatio', y='PetalRatio'))
....:
Out[78]: <matplotlib.axes._subplots.AxesSubplot at 0x7f66075a7978>
上例用 assign 把函数传递给 DataFrame, 并执行函数运算。这是要注意的是,该 DataFrame 是筛选了花萼长度大于 5 以后的数据。首先执行的是筛选操作,再计算比例。这个例子就是对没有事先筛选 DataFrame 进行的引用。
允许依赖赋值,可以引用同一个 assign() 函数里之前创建的列 。
In [79]: dfa = pd.DataFrame({"A": [1, 2, 3],
....: "B": [4, 5, 6]})
....:
In [80]: dfa.assign(C=lambda x: x['A'] + x['B'],
....: D=lambda x: x['A'] + x['C'])
....:
Out[80]:
A B C D
0 1 4 5 6
1 2 5 7 9
2 3 6 9 12
第二个表达式里,x[‘C’] 引用刚创建的列,与 dfa[‘A’] + dfa[‘B’] 等效。
警告
依赖赋值改变了 Python 3.6 及之后版本与 Python 3.6 之前版本的代码操作方式。
要想编写支持 3.6 之前或之后版本的 Python 代码,传递 assign 表达式时,要注意以下两点:
更新现有的列
在同一个 assign 引用刚建立的更新列
示例如下,更新列 “A”,然后,在创建 “B” 列时引用该列。
>>> dependent = pd.DataFrame({"A": [1, 1, 1]})
>>> dependent.assign(A=lambda x: x["A"] + 1, B=lambda x: x["A"] + 2)
Python 3.5 或更早版本的表达式在创建 B 列时引用的是 A 列的“旧”值 [1, 1, 1]。输出是:
A B
0 2 3
1 2 3
2 2 3
Python >= 3.6 的表达式创建 A 列时,引用的是 A 列的“”新”值,[2, 2, 2],输出是:
A B
0 2 4
1 2 4
2 2 4
2.2.3索引 / 选择
选择行返回 Series,索引是 DataFrame 的列:
In [83]: df.loc['b']
Out[83]:
one 2
bar 2
flag False
foo bar
one_trunc 2
Name: b, dtype: object
In [84]: df.iloc[2]
Out[84]:
one 3
bar 3
flag True
foo bar
one_trunc NaN
Name: c, dtype: object
2.2.4 数据对齐和运算
dateframe与numpy.array是完全兼容的,可以直接调用numpy中的函数。 dateframe内部数据结构就是用的nparray
- DataFrame 对象可以自动对齐**列与索引(行标签)**的数据。与上文一样,生成的结果是列和行标签的并集。
In [85]: df = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])
In [86]: df2 = pd.DataFrame(np.random.randn(7, 3), columns=['A', 'B', 'C'])
In [87]: df + df2
Out[87]:
A B C D
0 0.045691 -0.014138 1.380871 NaN
1 -0.955398 -1.501007 0.037181 NaN
2 -0.662690 1.534833 -0.859691 NaN
3 -2.452949 1.237274 -0.133712 NaN
4 1.414490 1.951676 -2.320422 NaN
5 -0.494922 -1.649727 -1.084601 NaN
6 -1.047551 -0.748572 -0.805479 NaN
7 NaN NaN NaN NaN
8 NaN NaN NaN NaN
9 NaN NaN NaN NaN
- DataFrame 和 Series 之间执行操作时,默认操作是在 DataFrame 的列上对齐 Series 的索引,按行执行广播操作。例如:
In [85]: df = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])
In [88]: df - df.iloc[0]
Out[88]:
A B C D
0 0.000000 0.000000 0.000000 0.000000
1 -1.359261 -0.248717 -0.453372 -1.754659
2 0.253128 0.829678 0.010026 -1.991234
3 -1.311128 0.054325 -1.724913 -1.620544
4 0.573025 1.500742 -0.676070 1.367331
5 -1.741248 0.781993 -1.241620 -2.053136
6 -1.240774 -0.869551 -0.153282 0.000430
7 -0.743894 0.411013 -0.929563 -0.282386
8 -1.194921 1.320690 0.238224 -1.482644
9 2.293786 1.856228 0.773289 -1.446531
时间序列是特例,DataFrame 索引包含日期时,按列广播:
In [89]: index = pd.date_range('1/1/2000', periods=8)
In [90]: df = pd.DataFrame(np.random.randn(8, 3), index=index, columns=list('ABC'))
In [91]: df
Out[91]:
A B C
2000-01-01 -1.226825 0.769804 -1.281247
2000-01-02 -0.727707 -0.121306 -0.097883
2000-01-03 0.695775 0.341734 0.959726
2000-01-04 -1.110336 -0.619976 0.149748
2000-01-05 -0.732339 0.687738 0.176444
2000-01-06 0.403310 -0.154951 0.301624
2000-01-07 -2.179861 -1.369849 -0.954208
2000-01-08 1.462696 -1.743161 -0.826591
In [92]: type(df['A'])
Out[92]: Pandas.core.series.Series
In [93]: df - df['A']
Out[93]:
2000-01-01 00:00:00 2000-01-02 00:00:00 2000-01-03 00:00:00 2000-01-04 00:00:00 ... 2000-01-08 00:00:00 A B C
2000-01-01 NaN NaN NaN NaN ... NaN NaN NaN NaN
2000-01-02 NaN NaN NaN NaN ... NaN NaN NaN NaN
2000-01-03 NaN NaN NaN NaN ... NaN NaN NaN NaN
2000-01-04 NaN NaN NaN NaN ... NaN NaN NaN NaN
2000-01-05 NaN NaN NaN NaN ... NaN NaN NaN NaN
2000-01-06 NaN NaN NaN NaN ... NaN NaN NaN NaN
2000-01-07 NaN NaN NaN NaN ... NaN NaN NaN NaN
2000-01-08 NaN NaN NaN NaN ... NaN NaN NaN NaN
[8 rows x 11 columns]
警告
df - df['A']
已弃用,后期版本中会删除。实现此操作的首选方法是:
df.sub(df['A'], axis=0)
- 标量操作与其它数据结构一样:
In [94]: df * 5 + 2
Out[94]:
A B C
2000-01-01 -4.134126 5.849018 -4.406237
2000-01-02 -1.638535 1.393469 1.510587
2000-01-03 5.478873 3.708672 6.798628
2000-01-04 -3.551681 -1.099880 2.748742
2000-01-05 -1.661697 5.438692 2.882222
2000-01-06 4.016548 1.225246 3.508122
2000-01-07 -8.899303 -4.849247 -2.771039
2000-01-08 9.313480 -6.715805 -2.132955
- 支持布尔运算符:
In [97]: df1 = pd.DataFrame({'a': [1, 0, 1], 'b': [0, 1, 1]}, dtype=bool)
In [98]: df2 = pd.DataFrame({'a': [0, 1, 1], 'b': [1, 1, 0]}, dtype=bool)
In [99]: df1 & df2
Out[99]:
a b
0 False False
1 False True
2 True False
In [100]: df1 | df2
Out[100]:
a b
0 True True
1 True True
2 True True
In [101]: df1 ^ df2
Out[101]:
a b
0 True True
1 True False
2 False True
In [102]: -df1
Out[102]:
a b
0 False True
1 True False
2 False False
- 转置
类似于多维数组,T 属性(即 transpose 函数)可以转置 DataFrame:
# only show the first 5 rows
In [103]: df[:5].T
Out[103]:
2000-01-01 2000-01-02 2000-01-03 2000-01-04 2000-01-05
A -1.226825 -0.727707 0.695775 -1.110336 -0.732339
B 0.769804 -0.121306 0.341734 -0.619976 0.687738
C -1.281247 -0.097883 0.959726 0.149748 0.176444
- DataFrame 应用 NumPy 函数
Series 与 DataFrame 可使用 log、exp、sqrt 等多种元素级 NumPy 通用函数(ufunc) ,假设 DataFrame 的数据都是数字:
In [104]: np.exp(df)
Out[104]:
A B C
2000-01-01 0.293222 2.159342 0.277691
2000-01-02 0.483015 0.885763 0.906755
2000-01-03 2.005262 1.407386 2.610980
2000-01-04 0.329448 0.537957 1.161542
2000-01-05 0.480783 1.989212 1.192968
2000-01-06 1.496770 0.856457 1.352053
2000-01-07 0.113057 0.254145 0.385117
2000-01-08 4.317584 0.174966 0.437538
# dateframe与numpy.array是完全兼容的,可以直接调用numpy中的函数。dateframe内部数据结构就是用的nparray
In [105]: np.asarray(df) #dataframe可以直接转换为nparray
Out[105]:
array([[-1.2268, 0.7698, -1.2812],
[-0.7277, -0.1213, -0.0979],
[ 0.6958, 0.3417, 0.9597],
[-1.1103, -0.62 , 0.1497],
[-0.7323, 0.6877, 0.1764],
[ 0.4033, -0.155 , 0.3016],
[-2.1799, -1.3698, -0.9542],
[ 1.4627, -1.7432, -0.8266]])
np.array(df) == df.value #True
- 通用函数应用于 Series 的底层数组。
In [106]: ser = pd.Series([1, 2, 3, 4])
In [107]: np.exp(ser)
Out[107]:
0 2.718282
1 7.389056
2 20.085537
3 54.598150
dtype: float64
多个 Series 传递给 ufunc 时,会先进行对齐。
Pandas 可以自动对齐 ufunc 里的多个带标签输入数据。例如,两个标签排序不同的 Series 运算前,会先对齐标签。
In [108]: ser1 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
In [109]: ser2 = pd.Series([1, 3, 5], index=['b', 'a', 'c'])
In [110]: ser1
Out[110]:
a 1
b 2
c 3
dtype: int64
In [111]: ser2
Out[111]:
b 1
a 3
c 5
dtype: int64
In [112]: np.remainder(ser1, ser2)
Out[112]:
a 1
b 0
c 3
dtype: int64
一般来说,Pandas 提取两个索引的并集,不重叠的值用缺失值填充。
In [113]: ser3 = pd.Series([2, 4, 6], index=['b', 'c', 'd'])
In [114]: ser3
Out[114]:
b 2
c 4
d 6
dtype: int64
In [115]: np.remainder(ser1, ser3)
Out[115]:
a NaN
b 0.0
c 3.0
d NaN
dtype: float64
对 Series 和 Index 应用二进制 ufunc 时,优先执行 Series,并返回的结果也是 Series 。
In [116]: ser = pd.Series([1, 2, 3])
In [117]: idx = pd.Index([4, 5, 6])
In [118]: np.maximum(ser, idx)
Out[118]:
0 4
1 5
2 6
dtype: int64
2.2.5 控制台显示
控制台显示大型 DataFrame 时,会根据空间调整显示大小。info()函数可以查看 DataFrame 的信息摘要。下列代码读取 R 语言 plyr 包里的棒球数据集 CSV 文件):
In [119]: baseball = pd.read_csv('data/baseball.csv')
In [120]: print(baseball)
id player year stint team lg g ab r h X2b X3b hr rbi sb cs bb so ibb hbp sh sf gidp
0 88641 womacto01 2006 2 CHN NL 19 50 6 14 1 0 1 2.0 1.0 1.0 4 4.0 0.0 0.0 3.0 0.0 0.0
1 88643 schilcu01 2006 1 BOS AL 31 2 0 1 0 0 0 0.0 0.0 0.0 0 1.0 0.0 0.0 0.0 0.0 0.0
.. ... ... ... ... ... .. .. ... .. ... ... ... .. ... ... ... .. ... ... ... ... ... ...
98 89533 aloumo01 2007 1 NYN NL 87 328 51 112 19 1 13 49.0 3.0 0.0 27 30.0 5.0 2.0 0.0 3.0 13.0
99 89534 alomasa02 2007 1 NYN NL 8 22 1 3 1 0 0 0.0 0.0 0.0 0 3.0 0.0 0.0 0.0 0.0 0.0
[100 rows x 23 columns]
In [121]: baseball.info()
<class 'Pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 23 columns):
id 100 non-null int64
player 100 non-null object
year 100 non-null int64
stint 100 non-null int64
team 100 non-null object
lg 100 non-null object
g 100 non-null int64
ab 100 non-null int64
r 100 non-null int64
h 100 non-null int64
X2b 100 non-null int64
X3b 100 non-null int64
hr 100 non-null int64
rbi 100 non-null float64
sb 100 non-null float64
cs 100 non-null float64
bb 100 non-null int64
so 100 non-null float64
ibb 100 non-null float64
hbp 100 non-null float64
sh 100 non-null float64
sf 100 non-null float64
gidp 100 non-null float64
dtypes: float64(9), int64(11), object(3)
memory usage: 18.1+ KB
可以用 to_string 以表格形式返回 DataFrame 的字符串表示形式:
In [122]: print(baseball.iloc[-20:, :12].to_string())
id player year stint team lg g ab r h X2b X3b
80 89474 finlest01 2007 1 COL NL 43 94 9 17 3 0
81 89480 embreal01 2007 1 OAK AL 4 0 0 0 0 0
82 89481 edmonji01 2007 1 SLN NL 117 365 39 92 15 2
83 89482 easleda01 2007 1 NYN NL 76 193 24 54 6 0
84 89489 delgaca01 2007 1 NYN NL 139 538 71 139 30 0
85 89493 cormirh01 2007 1 CIN NL 6 0 0 0 0 0
86 89494 coninje01 2007 2 NYN NL 21 41 2 8 2 0
87 89495 coninje01 2007 1 CIN NL 80 215 23 57 11 1
88 89497 clemero02 2007 1 NYA AL 2 2 0 1 0 0
89 89498 claytro01 2007 2 BOS AL 8 6 1 0 0 0
90 89499 claytro01 2007 1 TOR AL 69 189 23 48 14 0
91 89501 cirilje01 2007 2 ARI NL 28 40 6 8 4 0
92 89502 cirilje01 2007 1 MIN AL 50 153 18 40 9 2
93 89521 bondsba01 2007 1 SFN NL 126 340 75 94 14 0
94 89523 biggicr01 2007 1 HOU NL 141 517 68 130 31 3
95 89525 benitar01 2007 2 FLO NL 34 0 0 0 0 0
96 89526 benitar01 2007 1 SFN NL 19 0 0 0 0 0
97 89530 ausmubr01 2007 1 HOU NL 117 349 38 82 16 3
98 89533 aloumo01 2007 1 NYN NL 87 328 51 112 19 1
99 89534 alomasa02 2007 1 NYN NL 8 22 1 3 1 0
过宽的 DataFrame 会跨多行输出:
display.width 选项可以更改单行输出的宽度:
display.max_colwidth 调整最大列宽。
3.Panel
3.1定义
-
Panel是三维的带标签的数组。实际上,Pandas的名称由来就是由Panel演进的,即pan(el)—da(ta)—s。pannel仪表板,仪表板数据,金融领域数据。pandas最早开发就是为了应对金融领域,金融领域数据就是三维数据。
Panel比较少用,但依然是最重要的基础数据结构之一。 -
三个维度:
items:坐标轴0,索引对应的元素是一个dataframe。
major_axis:坐标轴1,dataframe里的行标签
minor_axis:坐标轴2,dataframe里的列标签
上图可当成panel,即Series为一维,dataframe为二维,panel为三维。
3.2创建
pandas.Panel(data, items, major_axis, minor_axis, dtype, copy)
其中,data为数据。可通过多种方式构造。
items相当于上图中的分类标签。在item确定之后,就可以将其看作dataframe
Major_axis即为dataframe中的index。
Minor_axis为dataframe中的columns。
- 创建一个空面板,此处不多说
- 通过字典dataframe创建面板:
一开始试了字典系列,发现会报错,所以又采用了字典dataframe的方式。字典键即为item,里面的index和columns分别为主轴和次轴。
import pandas as pd
d = {"one": pd.DataFrame([1, 2, 3],index=["a","b","c"], columns=["hh"])}
df = pd.Panel(d)
print (df)
<class 'pandas.core.panel.Panel'>
Dimensions: 1 (items) x 3 (major_axis) x 1 (minor_axis)
Items axis: one to one
Major_axis axis: a to c
Minor_axis axis: hh to hh
- 通过3维数组创建面板:
import pandas as pd
import numpy as np
df = pd.Panel(np.random.rand(2,3,4))
print (df)
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 3 (major_axis) x 4 (minor_axis)
Items axis: 0 to 1
Major_axis axis: 0 to 2
Minor_axis axis: 0 to 3
创建的三维数组,分别对应相应的item,主轴和次轴。
3.3操作
import pandas as pd
import numpy as np
df = pd.Panel(np.random.rand(2,3,4),
items=["aa","bb"],major_axis=["a","b","c"],minor_axis=["q","w","e","f"])
print (df)
print("选择项目",df["aa"])
print("选择主轴",df.major_xs("b"))
print("选择次轴",df.minor_xs("q"))
print("选择某元素",df["aa","b","q"])
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 3 (major_axis) x 4 (minor_axis)
Items axis: aa to bb
Major_axis axis: a to c
Minor_axis axis: q to f
选择项目 q w e f
a 0.488587 0.855737 0.032916 0.106395
b 0.950385 0.251045 0.051626 0.427011
c 0.271140 0.774883 0.066487 0.129807
选择主轴 aa bb
q 0.950385 0.235801
w 0.251045 0.353422
e 0.051626 0.595372
f 0.427011 0.314126
选择次轴 aa bb
a 0.488587 0.695660
b 0.950385 0.235801
c 0.271140 0.757256
选择某元素 0.9503852814428109
选择项目时,直接用标签选择即可。
选择主轴和次轴时,则需调用相应的方法。
选择某一元素时,直接选标签即可。
将panel转换为DataFrame
不论多少维数据,最终都可以转换维一个多维标签表示的2维dataframe数据。
七.Pandas基础运算
参考了官网:https://www.pypandas/docs/getting_started/basics.html#%E9%87%8D%E7%BD%AE%E7%B4%A2%E5%BC%95%E4%B8%8E%E6%9B%B4%E6%8D%A2%E6%A0%87%E7%AD%BE
1.重置索引
1.1reindex()
- reindex()指的是沿着指定轴,让数据与给定的一组标签进行匹配。该功能完成以下几项操作:
1.让现有数据匹配一组新标签,并重新排序;
2.在无数据但有标签的位置插入缺失值(NA)标记;
3.如果指定,则按逻辑填充无标签的数据,该操作多见于时间序列数据。
In [196]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [197]: s
Out[197]:
a 1.695148
b 1.328614
c 1.234686
d -0.385845
e -1.326508
dtype: float64
In [198]: s.reindex(['e', 'b', 'f', 'd'])
Out[198]:
e -1.326508
b 1.328614
f NaN
d -0.385845
dtype: float64
本例中,原 Series 里没有标签 f ,因此,输出结果里 f 对应的值为 NaN。
- DataFrame 支持同时 reindex 索引与列:
In [199]: df
Out[199]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [200]: df.reindex(index=['c', 'f', 'b'], columns=['three', 'two', 'one'])
Out[200]:
three two one
c 1.227435 1.478369 0.695246
f NaN NaN NaN
b -0.050390 1.912123 0.343054
- reindex 还支持 axis 关键字:
In [202]: rs = s.reindex(df.index)
In [203]: rs
Out[203]:
a 1.695148
b 1.328614
c 1.234686
d -0.385845
dtype: float64
In [204]: rs.index is df.index
Out[204]: True
重置后,Series 的索引与 DataFrame 的索引是同一个 Python 对象。
- DataFrame.reindex()还支持 “轴样式”调用习语,可以指定单个 labels 参数,并指定应用于哪个 axis。
In [205]: df.reindex(['c', 'f', 'b'], axis='index')
Out[205]:
one two three
c 0.695246 1.478369 1.227435
f NaN NaN NaN
b 0.343054 1.912123 -0.050390
In [206]: df.reindex(['three', 'two', 'one'], axis='columns')
Out[206]:
three two one
a NaN 1.772517 1.394981
b -0.050390 1.912123 0.343054
c 1.227435 1.478369 0.695246
d -0.613172 0.279344 NaN
注意
编写注重性能的代码时,最好花些时间深入理解 reindex:预对齐数据后,操作会更快。两个未对齐的 DataFrame 相加,后台操作会执行 reindex。探索性分析时很难注意到这点有什么不同,这是因为 reindex 已经进行了高度优化,但需要注重 CPU 周期时,显式调用 reindex 还是有一些影响的。
1.2重置索引,并与其它对象对齐reindex_like() 方法
In [199]: df
Out[199]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [207]: df2
Out[207]:
one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369
In [208]: df3
Out[208]:
one two
a 0.583888 0.051514
b -0.468040 0.191120
c -0.115848 -0.242634
In [209]: df.reindex_like(df2)
Out[209]:
one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369
1.4重置索引填充
ffill,forward fill向前填充。 nearest在这里可以用interpolate插入,fillna代替。
In [219]: rng = pd.date_range('1/3/2000', periods=8)
In [220]: ts = pd.Series(np.random.randn(8), index=rng)
In [221]: ts2 = ts[[0, 3, 6]]
In [222]: ts
Out[222]:
2000-01-03 0.183051
2000-01-04 0.400528
2000-01-05 -0.015083
2000-01-06 2.395489
2000-01-07 1.414806
2000-01-08 0.118428
2000-01-09 0.733639
2000-01-10 -0.936077
Freq: D, dtype: float64
In [223]: ts2
Out[223]:
2000-01-03 0.183051
2000-01-06 2.395489
2000-01-09 0.733639
dtype: float64
In [224]: ts2.reindex(ts.index)
Out[224]:
2000-01-03 0.183051
2000-01-04 NaN
2000-01-05 NaN
2000-01-06 2.395489
2000-01-07 NaN
2000-01-08 NaN
2000-01-09 0.733639
2000-01-10 NaN
Freq: D, dtype: float64
In [225]: ts2.reindex(ts.index, method='ffill')
Out[225]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 0.183051
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 2.395489
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
In [226]: ts2.reindex(ts.index, method='bfill')
Out[226]:
2000-01-03 0.183051
2000-01-04 2.395489
2000-01-05 2.395489
2000-01-06 2.395489
2000-01-07 0.733639
2000-01-08 0.733639
2000-01-09 0.733639
2000-01-10 NaN
Freq: D, dtype: float64
In [227]: ts2.reindex(ts.index, method='nearest')
Out[227]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 2.395489
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 0.733639
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
#method='nearest',用 fillna 或 interpolate 也能实现同样的效果:
In [228]: ts2.reindex(ts.index).fillna(method='ffill')
Out[228]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 0.183051
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 2.395489
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
上述操作要求索引按递增或递减排序。
如果索引不是按递增或递减排序,reindex() 会触发 ValueError 错误。fillna() 与 interpolate() 则不检查索引的排序。
1.5重置索引填充的限制
limit 与 tolerance 参数可以控制 reindex 的填充操作。limit 限定了连续匹配的最大数量:
In [229]: ts2.reindex(ts.index, method='ffill', limit=1)
Out[229]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 NaN
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 NaN
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
反之,tolerance 限定了索引与索引器值之间的最大距离:
In [230]: ts2.reindex(ts.index, method='ffill', tolerance='1 day')
Out[230]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 NaN
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 NaN
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
注意:索引为 DatetimeIndex、TimedeltaIndex 或 PeriodIndex 时,tolerance 会尽可能将这些索引强制转换为 Timedelta,这里要求用户用恰当的字符串设定 tolerance 参数。
1.6用 align 对齐多个对象
align() 方法是对齐两个对象最快的方式,该方法支持 join 参数(请参阅 joining 与 merging):
1.join=‘outer’:使用两个对象索引的合集,默认值
2.join=‘left’:使用左侧调用对象的索引
3.join=‘right’:使用右侧传递对象的索引
4.join=‘inner’:使用两个对象索引的交集
- 该方法返回重置索引后的两个 Series 元组:
In [210]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [211]: s1 = s[:4]
In [212]: s2 = s[1:]
In [213]: s1.align(s2)
Out[213]:
(a -0.186646
b -1.692424
c -0.303893
d -1.425662
e NaN
dtype: float64, a NaN
b -1.692424
c -0.303893
d -1.425662
e 1.114285
dtype: float64)
In [214]: s1.align(s2, join='inner')
Out[214]:
(b -1.692424
c -0.303893
d -1.425662
dtype: float64, b -1.692424
c -0.303893
d -1.425662
dtype: float64)
In [215]: s1.align(s2, join='left')
Out[215]:
(a -0.186646
b -1.692424
c -0.303893
d -1.425662
dtype: float64, a NaN
b -1.692424
c -0.303893
d -1.425662
dtype: float64)
- 默认条件下, join 方法既应用于索引,也应用于列:
In [216]: df.align(df2, join='inner')
Out[216]:
( one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369, one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369)
- align 方法还支持 axis 选项,用来指定要对齐的轴:
In [217]: df.align(df2, join='inner', axis=0)
Out[217]:
( one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435, one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369)
- align 方法还支持 axis 选项,用来指定要对齐的轴:
In [217]: df.align(df2, join='inner', axis=0)
Out[217]:
( one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435, one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369)
- 如果把 Series 传递给 DataFrame.align(),可以用 axis 参数选择是在 DataFrame 的索引,还是列上对齐两个对象:
In [218]: df.align(df2.iloc[0], axis=1)
Out[218]:
( one three two
a 1.394981 NaN 1.772517
b 0.343054 -0.050390 1.912123
c 0.695246 1.227435 1.478369
d NaN -0.613172 0.279344, one 1.394981
three NaN
two 1.772517
Name: a, dtype: float64)
2.更换标签
2.1去掉轴上的标签/丢弃部分数据
drop() 函数与 reindex 经常配合使用,该函数用于删除轴上的一组标签:
In [231]: df
Out[231]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [232]: df.drop(['a', 'd'], axis=0)
Out[232]:
one two three
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
In [233]: df.drop(['one'], axis=1)
Out[233]:
two three
a 1.772517 NaN
b 1.912123 -0.050390
c 1.478369 1.227435
d 0.279344 -0.613172
注意:下面的代码可以运行,但不够清晰:
In [234]: df.reindex(df.index.difference(['a', 'd']))
Out[234]:
one two three
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
2.2重命名或映射标签
- rename() 方法支持按不同的轴基于映射(字典或 Series)调整标签。
In [235]: s
Out[235]:
a -0.186646
b -1.692424
c -0.303893
d -1.425662
e 1.114285
dtype: float64
In [236]: s.rename(str.upper)
Out[236]:
A -0.186646
B -1.692424
C -0.303893
D -1.425662
E 1.114285
dtype: float64
- 如果调用的是函数,该函数在处理标签时,必须返回一个值,而且生成的必须是一组唯一值。此外,rename() 还可以调用字典或 Series。
In [237]: df.rename(columns={'one': 'foo', 'two': 'bar'},
.....: index={'a': 'apple', 'b': 'banana', 'd': 'durian'})
.....:
Out[237]:
foo bar three
apple 1.394981 1.772517 NaN
banana 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
durian NaN 0.279344 -0.613172
Pandas 不会重命名标签未包含在映射里的列或索引。注意,映射里多出的标签不会触发错误。
- DataFrame.rename() 还支持“轴式”习语,用这种方式可以指定单个 mapper,及执行映射的 axis。
In [238]: df.rename({'one': 'foo', 'two': 'bar'}, axis='columns')
Out[238]:
foo bar three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [239]: df.rename({'a': 'apple', 'b': 'banana', 'd': 'durian'}, axis='index')
Out[239]:
one two three
apple 1.394981 1.772517 NaN
banana 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
durian NaN 0.279344 -0.613172
rename() 方法还提供了 inplace 命名参数,默认为 False,并会复制底层数据。inplace=True 时,会直接在原数据上重命名。
- rename() 还支持用标量或列表更改 Series.name 属性。
In [240]: s.rename("scalar-name")
Out[240]:
a -0.186646
b -1.692424
c -0.303893
d -1.425662
e 1.114285
Name: scalar-name, dtype: float64
- rename_axis() 方法支持指定 多层索引 名称,与标签相对应。
In [241]: df = pd.DataFrame({'x': [1, 2, 3, 4, 5, 6],
.....: 'y': [10, 20, 30, 40, 50, 60]},
.....: index=pd.MultiIndex.from_product([['a', 'b', 'c'], [1, 2]],
.....: names=['let', 'num']))
.....:
In [242]: df
Out[242]:
x y
let num
a 1 1 10
2 2 20
b 1 3 30
2 4 40
c 1 5 50
2 6 60
In [243]: df.rename_axis(index={'let': 'abc'})
Out[243]:
x y
abc num
a 1 1 10
2 2 20
b 1 3 30
2 4 40
c 1 5 50
2 6 60
In [244]: df.rename_axis(index=str.upper)
Out[244]:
x y
LET NUM
a 1 1 10
2 2 20
b 1 3 30
2 4 40
c 1 5 50
2 6 60
3.函数
查看函数帮助文档
不管是为 Pandas 对象应用自定义函数,还是应用第三方函数,都离不开以下三种方法。用哪种方法取决于操作的对象是 DataFrame,还是 Series ;是行、列,还是元素。
1.表级函数应用:pipe()
2.行列级函数应用: apply()
3.聚合 API: agg() 与 transform()
4.元素级函数应用:applymap()
3.1表级函数应用pipe() 方法
虽然可以把 DataFrame 与 Series 传递给函数,不过链式调用函数时,最好使用 pipe() 方法。
- 在链式方法中调用自定义函数或第三方支持库函数时,用 pipe 更容易,与用 Pandas 自身方法一样。
>>> (df.pipe(h)
... .pipe(g, arg1=1)
... .pipe(f, arg2=2, arg3=3))
pipe 为元组 (callable,data_keyword)形式。.pipe 把 DataFrame 作为元组里指定的参数。
- 下例用 statsmodels 拟合回归。该 API 先接收一个公式,DataFrame 是第二个参数,data。要传递函数,则要用pipe 接收关键词对 (sm.ols,‘data’)。
In [138]: import statsmodels.formula.api as sm
In [139]: bb = pd.read_csv('data/baseball.csv', index_col='id')
In [140]: (bb.query('h > 0')
.....: .assign(ln_h=lambda df: np.log(df.h))
.....: .pipe((sm.ols, 'data'), 'hr ~ ln_h + year + g + C(lg)')
.....: .fit()
.....: .summary()
.....: )
.....:
Out[140]:
<class 'statsmodels.iolib.summary.Summary'>
"""
OLS Regression Results
==============================================================================
Dep. Variable: hr R-squared: 0.685
Model: OLS Adj. R-squared: 0.665
Method: Least Squares F-statistic: 34.28
Date: Thu, 22 Aug 2019 Prob (F-statistic): 3.48e-15
Time: 15:48:59 Log-Likelihood: -205.92
No. Observations: 68 AIC: 421.8
Df Residuals: 63 BIC: 432.9
Df Model: 4
Covariance Type: nonrobust
===============================================================================
coef std err t P>|t| [0.025 0.975]
-------------------------------------------------------------------------------
Intercept -8484.7720 4664.146 -1.819 0.074 -1.78e+04 835.780
C(lg)[T.NL] -2.2736 1.325 -1.716 0.091 -4.922 0.375
ln_h -1.3542 0.875 -1.547 0.127 -3.103 0.395
year 4.2277 2.324 1.819 0.074 -0.417 8.872
g 0.1841 0.029 6.258 0.000 0.125 0.243
==============================================================================
Omnibus: 10.875 Durbin-Watson: 1.999
Prob(Omnibus): 0.004 Jarque-Bera (JB): 17.298
Skew: 0.537 Prob(JB): 0.000175
Kurtosis: 5.225 Cond. No. 1.49e+07
==============================================================================
Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.49e+07. This might indicate that there are
strong multicollinearity or other numerical problems.
pipe方法引入了 R 语言里用于读取 pipe 的操作符 (%>%)。pipe 的实现思路非常清晰,仿佛 Python 源生的一样。
3.2行列级函数应用apply()
3.2.1apply() 沿着 DataFrame 的轴应用函数
apply() 方法沿着 DataFrame 的轴应用函数,比如,描述性统计方法,该方法支持 axis 参数。
In [77]: df
Out[77]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [141]: df.apply(np.mean)
Out[141]:
one 0.811094
two 1.360588
three 0.187958
dtype: float64
In [142]: df.apply(np.mean, axis=1)
Out[142]:
a 1.583749
b 0.734929
c 1.133683
d -0.166914
dtype: float64
In [143]: df.apply(lambda x: x.max() - x.min())
Out[143]:
one 1.051928
two 1.632779
three 1.840607
dtype: float64
In [144]: df.apply(np.cumsum)
Out[144]:
one two three
a 1.394981 1.772517 NaN
b 1.738035 3.684640 -0.050390
c 2.433281 5.163008 1.177045
d NaN 5.442353 0.563873
In [145]: df.apply(np.exp)
Out[145]:
one two three
a 4.034899 5.885648 NaN
b 1.409244 6.767440 0.950858
c 2.004201 4.385785 3.412466
d NaN 1.322262 0.541630
3.2.2apply() 支持通过函数名字符串调用函数
In [146]: df.apply('mean')
Out[146]:
one 0.811094
two 1.360588
three 0.187958
dtype: float64
In [147]: df.apply('mean', axis=1)
Out[147]:
a 1.583749
b 0.734929
c 1.133683
d -0.166914
dtype: float64
默认情况下,apply() 调用的函数返回的类型会影响 DataFrame.apply 输出结果的类型。
1.函数返回的是 Series 时,最终输出结果是 DataFrame。输出的列与函数返回的 Series 索引相匹配。
2.函数返回其它任意类型时,输出结果是 Series。
result_type 会覆盖默认行为,该参数有三个选项:reduce、broadcast、expand。这些选项决定了列表型返回值是否扩展为 DataFrame
3.2.3 用好 apply() 可以了解数据集的很多信息。
- 比如可以提取每列的最大值对应的日期:
In [148]: tsdf = pd.DataFrame(np.random.randn(1000, 3), columns=['A', 'B', 'C'],
.....: index=pd.date_range('1/1/2000', periods=1000))
.....:
In [149]: tsdf.apply(lambda x: x.idxmax())
Out[149]:
A 2000-08-06
B 2001-01-18
C 2001-07-18
dtype: datetime64[ns]
3.2.4 向 apply() 方法传递额外的参数与关键字参数
比如下例中要应用的这个函数:
def subtract_and_divide(x, sub, divide=1):
return (x - sub) / divide
可以用下列方式应用该函数:
df.apply(subtract_and_divide, args=(5,), divide=3)
3.2.5 为每行或每列执行 Series 方法的功能
In [150]: tsdf
Out[150]:
A B C
2000-01-01 -0.158131 -0.232466 0.321604
2000-01-02 -1.810340 -3.105758 0.433834
2000-01-03 -1.209847 -1.156793 -0.136794
2000-01-04 NaN NaN NaN
2000-01-05 NaN NaN NaN
2000-01-06 NaN NaN NaN
2000-01-07 NaN NaN NaN
2000-01-08 -0.653602 0.178875 1.008298
2000-01-09 1.007996 0.462824 0.254472
2000-01-10 0.307473 0.600337 1.643950
In [151]: tsdf.apply(pd.Series.interpolate)
Out[151]:
A B C
2000-01-01 -0.158131 -0.232466 0.321604
2000-01-02 -1.810340 -3.105758 0.433834
2000-01-03 -1.209847 -1.156793 -0.136794
2000-01-04 -1.098598 -0.889659 0.092225
2000-01-05 -0.987349 -0.622526 0.321243
2000-01-06 -0.876100 -0.355392 0.550262
2000-01-07 -0.764851 -0.088259 0.779280
2000-01-08 -0.653602 0.178875 1.008298
2000-01-09 1.007996 0.462824 0.254472
2000-01-10 0.307473 0.600337 1.643950
apply() 有一个参数 raw,默认值为 False,在应用函数前,使用该参数可以将每行或列转换为 Series。该参数为 True 时,传递的函数接收 ndarray 对象,若不需要索引功能,这种操作能显著提高性能。
3.3 聚合 API
aggregate,n,合计;集合体;总计,v,集合;聚集;合计
聚合函数为DataFrame.aggregate(),它的别名是 DataFrame.agg()。
In [152]: tsdf = pd.DataFrame(np.random.randn(10, 3), columns=['A', 'B', 'C'],
.....: index=pd.date_range('1/1/2000', periods=10))
.....:
In [153]: tsdf.iloc[3:7] = np.nan
In [154]: tsdf
Out[154]:
A B C
2000-01-01 1.257606 1.004194 0.167574
2000-01-02 -0.749892 0.288112 -0.757304
2000-01-03 -0.207550 -0.298599 0.116018
2000-01-04 NaN NaN NaN
2000-01-05 NaN NaN NaN
2000-01-06 NaN NaN NaN
2000-01-07 NaN NaN NaN
2000-01-08 0.814347 -0.257623 0.869226
2000-01-09 -0.250663 -1.206601 0.896839
2000-01-10 2.169758 -1.333363 0.283157
3.3.1应用单个函数
应用单个函数时,该操作与 apply() 等效,这里也可以用字符串表示聚合函数名。下面的聚合函数输出的结果为 Series:
In [155]: tsdf.agg(np.sum)
Out[155]:
A 3.033606
B -1.803879
C 1.575510
dtype: float64
In [156]: tsdf.agg('sum')
Out[156]:
A 3.033606
B -1.803879
C 1.575510
dtype: float64
# 因为应用的是单个函数,该操作与`.sum()` 是等效的
In [157]: tsdf.sum()
Out[157]:
A 3.033606
B -1.803879
C 1.575510
dtype: float64
#Series 单个聚合操作返回标量值:
In [158]: tsdf.A.agg('sum')
Out[158]: 3.033606102414146
3.3.2多函数聚合
用列表形式传递多个聚合函数。每个函数在输出结果 DataFrame 里以行的形式显示,行名是每个聚合函数的函数名。
In [159]: tsdf.agg(['sum'])
Out[159]:
A B C
sum 3.033606 -1.803879 1.57551
- 多个函数输出多行:
In [160]: tsdf.agg(['sum', 'mean'])
Out[160]:
A B C
sum 3.033606 -1.803879 1.575510
mean 0.505601 -0.300647 0.262585
- Series 聚合多函数返回结果还是 Series,索引为函数名:
In [161]: tsdf.A.agg(['sum', 'mean'])
Out[161]:
sum 3.033606
mean 0.505601
Name: A, dtype: float64
- 传递 lambda 函数时,输出名为 的行:
In [163]: def mymean(x):
.....: return x.mean()
.....:
In [164]: tsdf.A.agg(['sum', mymean])
Out[164]:
sum 3.033606
mymean 0.505601
Name: A, dtype: float64
3.3.3用字典实现聚合
指定为哪些列应用哪些聚合函数时,需要把包含列名与标量(或标量列表)的字典传递给 DataFrame.agg。
注意:这里输出结果的顺序不是固定的,要想让输出顺序与输入顺序一致,请使用 OrderedDict。
In [165]: tsdf.agg({'A': 'mean', 'B': 'sum'})
Out[165]:
A 0.505601
B -1.803879
dtype: float64
输入的参数是列表时,输出结果为 DataFrame,并以矩阵形式显示所有聚合函数的计算结果,且输出结果由所有唯一函数组成。未执行聚合操作的列输出结果为 NaN 值:
In [166]: tsdf.agg({'A': ['mean', 'min'], 'B': 'sum'})
Out[166]:
A B
mean 0.505601 NaN
min -0.749892 NaN
sum NaN -1.803879
3.3.4多种数据类型(Dtype)
与 groupby 的 .agg 操作类似,DataFrame 含不能执行聚合的数据类型时,.agg 只计算可聚合的列:
In [167]: mdf = pd.DataFrame({'A': [1, 2, 3],
.....: 'B': [1., 2., 3.],
.....: 'C': ['foo', 'bar', 'baz'],
.....: 'D': pd.date_range('20130101', periods=3)})
.....:
In [168]: mdf.dtypes
Out[168]:
A int64
B float64
C object
D datetime64[ns]
dtype: object
In [169]: mdf.agg(['min', 'sum'])
Out[169]:
A B C D
min 1 1.0 bar 2013-01-01
sum 6 6.0 foobarbaz NaT
3.4自定义 Describe
.agg() 可以创建类似于内置 describe 函数 的自定义 describe 函数。
In [170]: from functools import partial
In [171]: q_25 = partial(pd.Series.quantile, q=0.25)
In [172]: q_25.__name__ = '25%'
In [173]: q_75 = partial(pd.Series.quantile, q=0.75)
In [174]: q_75.__name__ = '75%'
In [175]: tsdf.agg(['count', 'mean', 'std', 'min', q_25, 'median', q_75, 'max'])
Out[175]:
A B C
count 6.000000 6.000000 6.000000
mean 0.505601 -0.300647 0.262585
std 1.103362 0.887508 0.606860
min -0.749892 -1.333363 -0.757304
25% -0.239885 -0.979600 0.128907
median 0.303398 -0.278111 0.225365
75% 1.146791 0.151678 0.722709
max 2.169758 1.004194 0.896839
partial,局部的。quantile,分位数;分位点
3.5Transform API
3.5.1 单函数
transform() 方法的返回结果与原始数据的索引相同,大小相同。与 .agg API 类似,该 API 支持同时处理多种操作,不用一个一个操作
In [176]: tsdf = pd.DataFrame(np.random.randn(10, 3), columns=['A', 'B', 'C'],
.....: index=pd.date_range('1/1/2000', periods=10))
.....:
In [177]: tsdf.iloc[3:7] = np.nan
In [178]: tsdf
Out[178]:
A B C
2000-01-01 -0.428759 -0.864890 -0.675341
2000-01-02 -0.168731 1.338144 -1.279321
2000-01-03 -1.621034 0.438107 0.903794
2000-01-04 NaN NaN NaN
2000-01-05 NaN NaN NaN
2000-01-06 NaN NaN NaN
2000-01-07 NaN NaN NaN
2000-01-08 0.254374 -1.240447 -0.201052
2000-01-09 -0.157795 0.791197 -1.144209
2000-01-10 -0.030876 0.371900 0.061932
- 这里转换的是整个 DataFrame。.transform() 支持 NumPy 函数、字符串函数及自定义函数。
In [179]: tsdf.transform(np.abs)
Out[179]:
A B C
2000-01-01 0.428759 0.864890 0.675341
2000-01-02 0.168731 1.338144 1.279321
2000-01-03 1.621034 0.438107 0.903794
2000-01-04 NaN NaN NaN
2000-01-05 NaN NaN NaN
2000-01-06 NaN NaN NaN
2000-01-07 NaN NaN NaN
2000-01-08 0.254374 1.240447 0.201052
2000-01-09 0.157795 0.791197 1.144209
2000-01-10 0.030876 0.371900 0.061932
In [180]: tsdf.transform('abs')
Out[180]:
A B C
2000-01-01 0.428759 0.864890 0.675341
2000-01-02 0.168731 1.338144 1.279321
2000-01-03 1.621034 0.438107 0.903794
2000-01-04 NaN NaN NaN
2000-01-05 NaN NaN NaN
2000-01-06 NaN NaN NaN
2000-01-07 NaN NaN NaN
2000-01-08 0.254374 1.240447 0.201052
2000-01-09 0.157795 0.791197 1.144209
2000-01-10 0.030876 0.371900 0.061932
In [181]: tsdf.transform(lambda x: x.abs())
Out[181]:
A B C
2000-01-01 0.428759 0.864890 0.675341
2000-01-02 0.168731 1.338144 1.279321
2000-01-03 1.621034 0.438107 0.903794
2000-01-04 NaN NaN NaN
2000-01-05 NaN NaN NaN
2000-01-06 NaN NaN NaN
2000-01-07 NaN NaN NaN
2000-01-08 0.254374 1.240447 0.201052
2000-01-09 0.157795 0.791197 1.144209
2000-01-10 0.030876 0.371900 0.061932
- 这里的 transform() 接受单个函数;与 ufunc 等效。
In [182]: np.abs(tsdf)
Out[182]:
A B C
2000-01-01 0.428759 0.864890 0.675341
2000-01-02 0.168731 1.338144 1.279321
2000-01-03 1.621034 0.438107 0.903794
2000-01-04 NaN NaN NaN
2000-01-05 NaN NaN NaN
2000-01-06 NaN NaN NaN
2000-01-07 NaN NaN NaN
2000-01-08 0.254374 1.240447 0.201052
2000-01-09 0.157795 0.791197 1.144209
2000-01-10 0.030876 0.371900 0.061932
.transform() 向 Series 传递单个函数时,返回的结果也是单个 Series。
In [183]: tsdf.A.transform(np.abs)
Out[183]:
2000-01-01 0.428759
2000-01-02 0.168731
2000-01-03 1.621034
2000-01-04 NaN
2000-01-05 NaN
2000-01-06 NaN
2000-01-07 NaN
2000-01-08 0.254374
2000-01-09 0.157795
2000-01-10 0.030876
Freq: D, Name: A, dtype: float64
3.5.2 多函数 Transform
- transform() 调用多个函数时,生成多层索引 DataFrame。第一层是原始数据集的列名;第二层是 transform() 调用的函数名。
In [184]: tsdf.transform([np.abs, lambda x: x + 1])
Out[184]:
A B C
absolute <lambda> absolute <lambda> absolute <lambda>
2000-01-01 0.428759 0.571241 0.864890 0.135110 0.675341 0.324659
2000-01-02 0.168731 0.831269 1.338144 2.338144 1.279321 -0.279321
2000-01-03 1.621034 -0.621034 0.438107 1.438107 0.903794 1.903794
2000-01-04 NaN NaN NaN NaN NaN NaN
2000-01-05 NaN NaN NaN NaN NaN NaN
2000-01-06 NaN NaN NaN NaN NaN NaN
2000-01-07 NaN NaN NaN NaN NaN NaN
2000-01-08 0.254374 1.254374 1.240447 -0.240447 0.201052 0.798948
2000-01-09 0.157795 0.842205 0.791197 1.791197 1.144209 -0.144209
2000-01-10 0.030876 0.969124 0.371900 1.371900 0.061932 1.061932
- 为 Series 应用多个函数时,输出结果是 DataFrame,列名是 transform() 调用的函数名。
In [185]: tsdf.A.transform([np.abs, lambda x: x + 1])
Out[185]:
absolute <lambda>
2000-01-01 0.428759 0.571241
2000-01-02 0.168731 0.831269
2000-01-03 1.621034 -0.621034
2000-01-04 NaN NaN
2000-01-05 NaN NaN
2000-01-06 NaN NaN
2000-01-07 NaN NaN
2000-01-08 0.254374 1.254374
2000-01-09 0.157795 0.842205
2000-01-10 0.030876 0.969124
3.5.3用字典执行 transform 操作
- 函数字典可以为每列执行指定 transform() 操作。
In [186]: tsdf.transform({'A': np.abs, 'B': lambda x: x + 1})
Out[186]:
A B
2000-01-01 0.428759 0.135110
2000-01-02 0.168731 2.338144
2000-01-03 1.621034 1.438107
2000-01-04 NaN NaN
2000-01-05 NaN NaN
2000-01-06 NaN NaN
2000-01-07 NaN NaN
2000-01-08 0.254374 -0.240447
2000-01-09 0.157795 1.791197
2000-01-10 0.030876 1.371900
- transform() 的参数是列表字典时,生成的是以 transform() 调用的函数为名的多层索引 DataFrame。
In [187]: tsdf.transform({'A': np.abs, 'B': [lambda x: x + 1, 'sqrt']})
Out[187]:
A B
absolute <lambda> sqrt
2000-01-01 0.428759 0.135110 NaN
2000-01-02 0.168731 2.338144 1.156782
2000-01-03 1.621034 1.438107 0.661897
2000-01-04 NaN NaN NaN
2000-01-05 NaN NaN NaN
2000-01-06 NaN NaN NaN
2000-01-07 NaN NaN NaN
2000-01-08 0.254374 -0.240447 NaN
2000-01-09 0.157795 1.791197 0.889493
2000-01-10 0.030876 1.371900 0.609836
3.6元素级函数应用:映射DataFrame 的 applymap() 及 Series 的 map()
- 并非所有函数都能矢量化,即接受 NumPy 数组,返回另一个数组或值,DataFrame 的 applymap() 及 Series 的 map() ,支持任何接收单个值并返回单个值的 Python 函数。
In [188]: df4
Out[188]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [189]: def f(x):
.....: return len(str(x))
.....:
In [190]: df4['one'].map(f)
Out[190]:
a 18
b 19
c 18
d 3
Name: one, dtype: int64
In [191]: df4.applymap(f)
Out[191]:
one two three
a 18 17 3
b 19 18 20
c 18 18 16
d 3 19 19
- Series.map() 还有个功能,可以“连接”或“映射”第二个 Series 定义的值。这与 merging / joining 功能联系非常紧密:
In [192]: s = pd.Series(['six', 'seven', 'six', 'seven', 'six'],
.....: index=['a', 'b', 'c', 'd', 'e'])
.....:
In [193]: t = pd.Series({'six': 6., 'seven': 7.})
In [194]: s
Out[194]:
a six
b seven
c six
d seven
e six
dtype: object
In [195]: s.map(t)
Out[195]:
a 6.0
b 7.0
c 6.0
d 7.0
e 6.0
dtype: float64
4.排序和排名
Pandas 支持三种排序方式,按索引标签排序,按列里的值排序,按两种方式混合排序。
4.1按索引排序
Series.sort_index() 与 DataFrame.sort_index() 方法用于按索引层级对 Pandas 对象排序。
In [291]: df = pd.DataFrame({
.....: 'one': pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
.....: 'two': pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
.....: 'three': pd.Series(np.random.randn(3), index=['b', 'c', 'd'])})
.....:
In [292]: unsorted_df = df.reindex(index=['a', 'd', 'c', 'b'],
.....: columns=['three', 'two', 'one'])
.....:
In [293]: unsorted_df
Out[293]:
three two one
a NaN -1.152244 0.562973
d -0.252916 -0.109597 NaN
c 1.273388 -0.167123 0.640382
b -0.098217 0.009797 -1.299504
# DataFrame
In [294]: unsorted_df.sort_index()
Out[294]:
three two one
a NaN -1.152244 0.562973
b -0.098217 0.009797 -1.299504
c 1.273388 -0.167123 0.640382
d -0.252916 -0.109597 NaN
In [295]: unsorted_df.sort_index(ascending=False)
Out[295]:
three two one
d -0.252916 -0.109597 NaN
c 1.273388 -0.167123 0.640382
b -0.098217 0.009797 -1.299504
a NaN -1.152244 0.562973
In [296]: unsorted_df.sort_index(axis=1)
Out[296]:
one three two
a 0.562973 NaN -1.152244
d NaN -0.252916 -0.109597
c 0.640382 1.273388 -0.167123
b -1.299504 -0.098217 0.009797
# Series
In [297]: unsorted_df['three'].sort_index()
Out[297]:
a NaN
b -0.098217
c 1.273388
d -0.252916
Name: three, dtype: float64
4.2按值排序
Series.sort_values() 方法用于按值对 Series 排序。DataFrame.sort_values() 方法用于按行列的值对 DataFrame 排序。DataFrame.sort_values() 的可选参数 by 用于指定按哪列排序,该参数的值可以是一列或多列数据。
In [298]: df1 = pd.DataFrame({'one': [2, 1, 1, 1],
.....: 'two': [1, 3, 2, 4],
.....: 'three': [5, 4, 3, 2]})
.....:
In [299]: df1.sort_values(by='two')
Out[299]:
one two three
0 2 1 5
2 1 2 3
1 1 3 4
3 1 4 2
参数 by 支持列名列表,示例如下:
In [300]: df1[['one', 'two', 'three']].sort_values(by=['one', 'two'])
Out[300]:
one two three
2 1 2 3
1 1 3 4
3 1 4 2
0 2 1 5
这些方法支持用 na_position 参数处理空值。
In [301]: s[2] = np.nan
In [302]: s.sort_values()
Out[302]:
0 A
3 Aaba
1 B
4 Baca
6 CABA
8 cat
7 dog
2 NaN
5 NaN
dtype: object
In [303]: s.sort_values(na_position='first')
Out[303]:
2 NaN
5 NaN
0 A
3 Aaba
1 B
4 Baca
6 CABA
8 cat
7 dog
dtype: object
4.3按按索引与值排序
通过参数 by 传递给 DataFrame.sort_values() 的字符串可以引用列或索引层名。
# 创建 MultiIndex
In [304]: idx = pd.MultiIndex.from_tuples([('a', 1), ('a', 2), ('a', 2),
.....: ('b', 2), ('b', 1), ('b', 1)])
.....:
In [305]: idx.names = ['first', 'second']
# 创建 DataFrame
In [306]: df_multi = pd.DataFrame({'A': np.arange(6, 0, -1)},
.....: index=idx)
.....:
In [307]: df_multi
Out[307]:
A
first second
a 1 6
2 5
2 4
b 2 3
1 2
1 1
按 second(索引)与 A(列)排序。
In [308]: df_multi.sort_values(by=['second', 'A'])
Out[308]:
A
first second
b 1 1
1 2
a 1 6
b 2 3
a 2 4
2 5
注意
字符串、列名、索引层名重名时,会触发警告提示,并以列名为准。后期版本中,这种情况将会触发模糊错误。
4.4搜索排序
Series 支持 searchsorted() 方法,这与numpy.ndarray.searchsorted() 的操作方式类似。
In [309]: ser = pd.Series([1, 2, 3])
In [310]: ser.searchsorted([0, 3])
Out[310]: array([0, 2])
In [311]: ser.searchsorted([0, 4])
Out[311]: array([0, 3])
In [312]: ser.searchsorted([1, 3], side='right')
Out[312]: array([1, 3])
In [313]: ser.searchsorted([1, 3], side='left')
Out[313]: array([0, 2])
In [314]: ser = pd.Series([3, 1, 2])
In [315]: ser.searchsorted([0, 3], sorter=np.argsort(ser))
Out[315]: array([0, 2])
4.5最大值与最小值
4.5.1Series 支持 nsmallest() 与 nlargest() 方法
Series 支持 nsmallest() 与 nlargest() 方法,本方法返回 N 个最大或最小的值。对于数据量大的 Series 来说,该方法比先为整个 Series 排序,再调用 head(n) 这种方式的速度要快得多。
In [316]: s = pd.Series(np.random.permutation(10))
In [317]: s
Out[317]:
0 2
1 0
2 3
3 7
4 1
5 5
6 9
7 6
8 8
9 4
dtype: int64
In [318]: s.sort_values()
Out[318]:
1 0
4 1
0 2
2 3
9 4
5 5
7 6
3 7
8 8
6 9
dtype: int64
In [319]: s.nsmallest(3)
Out[319]:
1 0
4 1
0 2
dtype: int64
In [320]: s.nlargest(3)
Out[320]:
6 9
8 8
3 7
dtype: int64
permutation,. [数] 排列;[数] 置换
4.5.2 DataFrame 也支持 nlargest 与 nsmallest 方法
In [321]: df = pd.DataFrame({'a': [-2, -1, 1, 10, 8, 11, -1],
.....: 'b': list('abdceff'),
.....: 'c': [1.0, 2.0, 4.0, 3.2, np.nan, 3.0, 4.0]})
.....:
In [322]: df.nlargest(3, 'a')
Out[322]:
a b c
5 11 f 3.0
3 10 c 3.2
4 8 e NaN
In [323]: df.nlargest(5, ['a', 'c'])
Out[323]:
a b c
5 11 f 3.0
3 10 c 3.2
4 8 e NaN
2 1 d 4.0
6 -1 f 4.0
In [324]: df.nsmallest(3, 'a')
Out[324]:
a b c
0 -2 a 1.0
1 -1 b 2.0
6 -1 f 4.0
In [325]: df.nsmallest(5, ['a', 'c'])
Out[325]:
a b c
0 -2 a 1.0
1 -1 b 2.0
6 -1 f 4.0
2 1 d 4.0
4 8 e NaN
4.6用多层索引的列排序
列为多层索引时,可以显式排序,用 by 指定所有层级。
In [326]: df1.columns = pd.MultiIndex.from_tuples([('a', 'one'),
.....: ('a', 'two'),
.....: ('b', 'three')])
.....:
In [327]: df1.sort_values(by=('a', 'two'))
Out[327]:
a b
one two three
0 2 1 5
2 1 2 3
1 1 3 4
3 1 4 2
4.7 排名rank()
4.7.1 Series排名
这个元素在这一系列中排第几名
s.rank()方法生成一个包含排名信息的新的series
上面的6有两个,是并列排名,默认情况下将排名取中间值,为4.5名
可以给定参数,让两个相同的值有先后。first让先出现的值排在前面
4.7.2 DataFrame排名
5.数据的唯一性
import numpy as np
import pandas as pd
#创建一个Series
a = pd.Series(list('abbcdabacad'))
a
#统计Series的value出现了几次
a.value_counts()
# 获取value的为一值
a.unique()
# isin()判断a中的值是否在后面列表中
a.isin(['a','c','d'])
版权声明:本文标题:3.机器学习—数据科学包3.2pandas基础 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1729033210h1309412.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论