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

  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://wwwblogs/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/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/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/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 是轴标签列表。不同数据可分为以下几种情况:

  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/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'])

本文标签: 机器 基础 科学 数据 pandas