3.机器学习—数据科学包3.2pandas基础

pandas基础

一.pandas介绍

1.什么是pandas

  1. Pandas是Python里分析结构化数据的工具集
  2. pandas依赖于两个东西
    基础是numpy:提供高性能矩阵运算,包含基础的数据模型
    图形库matplotlib:python中提供数据可视化的库,

2.pandas用途

主要是结构化数据分析

不论是大数据还是人工智能,最重要的是数据
因而,从数据中挖掘出价值,就很重要

如何进行数据挖掘?
用pandas进行数据分析,先去探索下数据,是否有价值,

pandas可以处理海量数据,
提供了数据清洗功能,方便处理Nonedata,

3.课程内容

  1. Ipython
    数据分析领域用Ipython解析器,而不用默认的python解析器,因为Ipython解析器有更方便的功能。
  2. pandas快速入门
  3. pandas核心数据结构和基础运算
    两个核心数据结构,DataFrame(表格)和Series(表格中的列/行)
  4. pandas高级运算内容
    索引和数据选择
    分组统计
    时间序列
    数据IO:数据从磁盘读出来再保存到磁盘
  5. 数据可视化
  6. 用pandas进行数据分析的实例

二.Ipython开发环境搭建

1.安装

  1. 安装python,python官网

  2. 安装jupyter,pip install jupyter

  3. pip install numpy

  4. pip install matplotlib

  5. 如果是windows用户,还需pip install pyreadline,
    因为Ipython中有一个命令行自动完成的功能,入伙没有pyreadline,这个命令行自动完成的功能没法实现。
    但是linux/mac用户不需要。

  6. 安装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
在这里插入图片描述

  1. 这里显示出的数据会比标准python解释器格式化更好,特别是字典这类型数据
    举例说明
    在这里插入图片描述
    对比python格式下的数据格式
    在这里插入图片描述
  2. Ipython提供命令行自动补全的功能,
np.ran #摁tab键,会出现所有ran开头的函数
np.random #摁tab键,会出现所有random开头的函数
np.random.ran

在这里插入图片描述

  1. 可以快速查看文档
np.random.randn? #函数后面加问号
#而在python中用help
help(np.random.randn)

在这里插入图片描述

  1. 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://www.cnblogs.com/rangger/p/9520123.html

  1. 启动
    注意要退出Ipython/python Interactive command prompt,然后在cmd下(此处是base下的虚拟环境)中输入命令:Ipython notebook/Jupyter notebook
    在这里插入图片描述
    Ipython notebook就是Ipython工具的可视化界面,跟命令行中操作在本质上是一样的,但是功能更强大。就跟python既可以在python Interactive command prompt中操作,同时在IDE中操作更方便一个道理。

  2. Ipython magic命令
    使用魔法函数可以简单的实现一些单纯python要很麻烦才能实现的功能
    在notebook中可以使用shell命令,即Ipython magic命令。

  3. notebook快捷键
    help—keyboard shortcuts
    运行命令的快捷键—ctrl+enter
    运行当前cell命令且自动在下面新建cell—shift+enter

  4. insert cell插入操作框
    在这里插入图片描述

  5. 查询函数的帮助文档
    函数后加?
    在这里插入图片描述
    docstring,文档字符串,

  6. 定义函数,同一个方框内调用或在下一个方框内调用
    在这里插入图片描述

  7. 显示图片
    用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简介

  1. 特性
    高性能,科学计算和数据分析的基础包,是所有高级数据分析工具的构建基础
    面向数组的思维模式

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.cn/docs/getting_started/10min.html
质量最高

2.数据表创建、访问、更改

2.1创建pandas对象

  1. series,带索引的一维数据结构
import pandas as pd
import numpy as np 
# 创建关键数据结构
#数据结构series,代表一行/一列,最简单的创建方式就是传递一个列表。其中包含索引和值,索引是自动创建的
s = pd.Series([1,3,5,np.NaN,8,4]) #NaN,not a number,不是数值,

在这里插入图片描述

  1. 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 #数组的值 

在这里插入图片描述
在这里插入图片描述

  1. 字典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查看数据

  1. 查看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选择数据

  1. 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列的值
  1. DataFrame用python格式访问数据
data['A'] #选择A列,选择某一列的值
data.A
data[2:4] #访问2到4行
data['20160302','20160305'] #用行标签访问数据
# python格式的访问数据,效率低

  1. 用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')

在这里插入图片描述
在这里插入图片描述

  1. 内置访问。data.iloc[]
    在这里插入图片描述
    在这里插入图片描述
    访问某行某列的某个元素更高效方法,data.iat[]

用%timeit magic函数来测试.iloc[]访问数据是否比.iat[]访问数据效率高
在这里插入图片描述

  1. 布尔索引访问
    在这里插入图片描述
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列表过滤出来

在这里插入图片描述

  1. 修改表格数据
# 修改元素

在这里插入图片描述

# 修改一列或一行
#生成一个新的range来修改某一列。用列表修改,元素个数要匹配。
#用一个标量给整个列/行赋值,也可以给多喝行/列赋值,不用管匹配个数
# 可以创建一个行列和原来的表相等的表,就直接覆盖掉原来的表

在这里插入图片描述
在这里插入图片描述

3.DataFrame的操作

3.1处理缺失数据missing data

  1. 建表
%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。创建这个表。

在这里插入图片描述

  1. 更改表
# 制造一些数据缺失项
# 更改原有的表,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

在这里插入图片描述

  1. 处理missing data缺失数据
# 丢掉missing data
df1.dropna()

在这里插入图片描述

# 用默认值替换掉空值
df1.fillna(value=5)

在这里插入图片描述
dropna()和fillna()返回的都是复制后的
加粗样式

3.2数据运算

  1. 判断一个表中是否包含空数据
    空数据地方返回true,其他返回false
    在这里插入图片描述
    表格很大的话,没法目视判断出哪个是空数据,
    底下会打出有空值大的列
    在这里插入图片描述但是如果有很多列,一样目视难以扎到,
    返回值表示表中有空数据
    在这里插入图片描述
  2. 空数据不参与计算
    按列求平均值
    在这里插入图片描述
    按行求平均值
    在这里插入图片描述
  3. 累加值
    在这里插入图片描述
    空值不参与计算
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表中的列传给()中的函数去处理**
在这里插入图片描述
举例如下
在这里插入图片描述

  1. counts函数和mode函数
    先创建一个series,
    在这里插入图片描述
    counts()函数查看表中的值有几个,mode()函数查看表中的值出现最大次数的数是哪个
    在这里插入图片描述

3.3数据合并

  1. 数据合并
    先创建一个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数据分组

  1. 分类统计
    在这里插入图片描述
# 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数据整形

把行索引和列索引互换
先导入环境
在这里插入图片描述

  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是列标签

在这里插入图片描述
在这里插入图片描述

  1. 列索引变为行索引
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提供了功能强大的时间处理函数

  1. 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分钟,用求和的方式

在这里插入图片描述
求平均值的重采样方法
在这里插入图片描述

  1. .period_range()方法
#.period_range()方法建立时间序列
rng = pd.period_range('2000Q1','2016Q1',freg='Q') #以季度为单位,从2000Q1到2016Q1

在这里插入图片描述
转换为时间日期格式

rng.to_timestamp() #转换为时间日期格式

在这里插入图片描述

  1. 时间运算
    在这里插入图片描述
  2. 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.org/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将数据导入进来

  1. 读取三个.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中,要把数据合并起来才有利于分析

  1. 将三个表合并起来
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操作数据

  1. 查看数据
# 查看user_id为1的用户,他的所有电影评分数据
data[data.User_id == 1]

在这里插入图片描述

  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) 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 哪些电影评分的人数最多?就意味着看的人数最多
    按照电影名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)

在这里插入图片描述
在这里插入图片描述
以上就是最热门的电影

  1. 查看评分最高的电影
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)

在这里插入图片描述

  1. 找出很多人看,同时评分也很高的电影
    找出看的人最多的前十大热门电影,获得找出平均得分的电影的表,然后找出前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.cn/docs/getting_started/dsintro.html#series

1.Series

来源于pandas—Series官方文档https://www.pypandas.cn/docs/getting_started/dsintro.html#series

1.1定义及创建

Series 是带标签的一维数组,可存储整数、浮点数、字符串、Python 对象等类型的数据。轴标签统称为索引。调用 pd.Series 函数即可创建 Series:

 s = pd.Series(data, index=index)

上述代码中,data 支持以下数据类型:
Python 字典
多维数组
标量值(如,5)
index 是轴标签列表。不同数据可分为以下几种情况:

  1. 多维数组
    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 操作就不用索引。

  1. 字典
    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)表示缺失数据。

  1. 标量值
    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
  1. 和 NumPy 数组一样,Series 也支持 dtype。
In [18]: s.dtype
Out[18]: dtype('float64')

Series 的数据类型一般是 NumPy 数据类型。不过,Pandas 和第三方库在一些方面扩展了 NumPy 类型系统,即扩展数据类型。比如,Pandas 的类别型数据与可空整数数据类型。更多信息,请参阅数据类型 。

  1. 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
在这里插入图片描述
在这里插入图片描述

  1. 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
  1. 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)
  1. 标量操作与其它数据结构一样:
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
  1. 支持布尔运算符:
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
  1. 转置
    类似于多维数组,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
  1. 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
  1. 通用函数应用于 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定义

  1. Panel是三维的带标签的数组。实际上,Pandas的名称由来就是由Panel演进的,即pan(el)—da(ta)—s。pannel仪表板,仪表板数据,金融领域数据。pandas最早开发就是为了应对金融领域,金融领域数据就是三维数据。
    Panel比较少用,但依然是最重要的基础数据结构之一。

  2. 三个维度:
    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。

  1. 创建一个空面板,此处不多说
  2. 通过字典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
  1. 通过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.cn/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()

  1. 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。

  1. 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
  1. 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 对象。

  1. 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’:使用两个对象索引的交集

  1. 该方法返回重置索引后的两个 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)
  1. 默认条件下, 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)
  1. 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)
  1. 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)
  1. 如果把 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重命名或映射标签

  1. 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
  1. 如果调用的是函数,该函数在处理标签时,必须返回一个值,而且生成的必须是一组唯一值。此外,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 不会重命名标签未包含在映射里的列或索引。注意,映射里多出的标签不会触发错误。

  1. 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 时,会直接在原数据上重命名。

  1. 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
  1. 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() 方法。

  1. 在链式方法中调用自定义函数或第三方支持库函数时,用 pipe 更容易,与用 Pandas 自身方法一样。
>>> (df.pipe(h)
...    .pipe(g, arg1=1)
...    .pipe(f, arg2=2, arg3=3))

pipe 为元组 (callable,data_keyword)形式。.pipe 把 DataFrame 作为元组里指定的参数。

  1. 下例用 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() 可以了解数据集的很多信息。
  1. 比如可以提取每列的最大值对应的日期:
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
  1. 多个函数输出多行:
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
  1. Series 聚合多函数返回结果还是 Series,索引为函数名:
In [161]: tsdf.A.agg(['sum', 'mean'])
Out[161]: 
sum     3.033606
mean    0.505601
Name: A, dtype: float64
  1. 传递 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
  1. 这里转换的是整个 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
  1. 这里的 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
  1. 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
  1. 为 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 操作
  1. 函数字典可以为每列执行指定 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
  1. 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()

  1. 并非所有函数都能矢量化,即接受 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
  1. 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'])

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值