左手用R右手Python系列之——数据框与apply向量运算
R语言与Python中的apply函数都有着丰富的应用场景,恰到好处的使用apply函数,可以避免在很多场景下书写冗余的代码,这不仅能提高代码可读性,而且提高代码执行的效率。
apply(X, MARGIN, FUN, ...)
X #一个数组(包括矩阵)
MARGIN #一个给定下标的向量,将被指定函数执行计算1代表行,2代表列,c(1,2)代表行列。
FUN #执行计算的函数(如果是+、%*%这种符号函数需要使用反引号包括【英文输入法状态下的“~”键】)
... #函数的参数
apply函数内部执行的数组运算,我们通常传入的data.frame会被强制转换为二维数组参与最终的计算。
FUN参数支持R语言中常用的基础统计函数(meanmaxminmedianmodestdvar等),或者是一些符号函数【`+`、`%*%`等,】以及通过代码创建的自定义函数。
为了加深理解,我使用一个三维数组进行演示:
x <- array(1:48,c(4,3,4))
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
, , 3
[,1] [,2] [,3]
[1,] 25 29 33
[2,] 26 30 34
[3,] 27 31 35
[4,] 28 32 36
, , 4
[,1] [,2] [,3]
[1,] 37 41 45
[2,] 38 42 46
[3,] 39 43 47
[4,] 40 44 48
使用apply函数对x这个三维数组进行各剖面的统计计算:
apply(x,3,mean)
#计算第三维度(四个子矩阵块儿)矩阵均值(也可以是最大值、最小值等统计量)
[1] 6.5 18.5 30.5 42.5
因为每一个子矩阵块儿均值是单值,所有第三维度一共四个子块,返回一个单向量,依次为第三维度四个矩阵的均值量。
apply(x,c(1,3),mean)
#第三维与行切块交叉均值
[,1] [,2] [,3] [,4]
[1,] 5 17 29 41
[2,] 6 18 30 42
[3,] 7 19 31 43
[4,] 8 20 32 44
这是一个二维切块交叉均值统计量的输出,结果是一个矩阵,如何解读这个矩阵,其实很简单。c(1,3)实现了按照行与第三维度交叉切块,将原始三维数据组切成了4*4=16个子块【每个矩阵有四行,第三维一共有四个矩阵】。16个子块计算出mean之后,按照行列(第三维度)顺序输出矩阵。
所以以上结果的[1,1]=5是第一个矩阵第一行的均值,相当于
mean(x[1,,1]) [1] 5
依次类推,行上分别是mean(x[1,,2])mean(x[1,,3])mean(x[1,,4])的均值,列上分别是mean(x[1,,1])、mean(x[2,,1])、mean(x[3,,1])、mean(x[4,,1])
,其他每一行或者列都可以类比推导。输出的行严格按照原始数组行顺序,输出的列严格按照原始高维数据第三维顺序。
apply(x,c(3,1),mean)
再来看一下当将MARGIN参数的向量顺序反转之后出现的情况:
[,1] [,2] [,3] [,4]
[1,] 5 6 7 8
[2,] 17 18 19 20
[3,] 29 30 31 32
[4,] 41 42 43 44
仍然时一个向量,不过这些的输出次序变了,相当于把上一个输出转置了,实际是因为输出结果排布,第三维度变成了结果矩阵的行,行维度变成了输出结果矩阵的列。
而一共16个行的矩阵及其计算结果并没有改变。
也许这么说很快能把你绕晕了,那就来个图吧~
apply(x,c(2,3),mean)
[,1] [,2] [,3] [,4]
[1,] 2.5 14.5 26.5 38.5
[2,] 6.5 18.5 30.5 42.5
[3,] 10.5 22.5 34.5 46.5
apply(x,c(3,2),mean)
[,1] [,2] [,3]
[1,] 2.5 6.5 10.5
[2,] 14.5 18.5 22.5
[3,] 26.5 30.5 34.5
[4,] 38.5 42.5 46.5
列与第三维交叉均值,同样可以类比理解。
apply(x,c(1,2),mean)
[,1] [,2] [,3]
[1,] 19 23 27
[2,] 20 24 28
[3,] 21 25 29
[4,] 22 26 30
apply(x,c(2,1),mean)
[,1] [,2] [,3] [,4]
[1,] 19 20 21 22
[2,] 23 24 25 26
[3,] 27 28 29 30
以上是行列交叉均值,这个不太好理解,其实就是每一个第三维度行列交叉指组成的向量的均值,因为原始高维数据的每一个矩阵都是四行三列,所以最终的输出也是四行三列。
输出结果的解读可以这么来看:
mean(x[1,1,])=19
mean(x[2,1,])=20
mean(x[3,1,])=21
mean(x[4,1,])=22
其他的以此类推,apply(x,c(2,1),mean)的输出结果相当于apply(x,c(1,2),mean)的转置,其实就是颠倒了行列,计算输出时按照列顺序排布。
apply(x,c(1,2,3),mean)
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
, , 2
[,1] [,2] [,3]
[1,] 13 17 21
[2,] 14 18 22
[3,] 15 19 23
[4,] 16 20 24
, , 3
[,1] [,2] [,3]
[1,] 25 29 33
[2,] 26 30 34
[3,] 27 31 35
[4,] 28 32 36
, , 4
[,1] [,2] [,3]
[1,] 37 41 45
[2,] 38 42 46
[3,] 39 43 47
[4,] 40 44 48
使用apply(x,c(1,2,3),mean)操作,结果输出与原始三维数组x一模一样,这个也不难理解,相当于对原始数组中的单个值进行了逐次遍历,每一个单值的mean必然等于它本身。 掌握apply函数的核心思想,必须首先掌握高维数组的dim概念,array的索引概念如果熟悉,那么apply仅仅是针对每一次索引运用了统计量而已。
以上是高维数组的apply参数详解,实际上我们平时很少使用超过二维(也就是矩阵)的运算,更多的时候是使用数据框参与计算,apply计算数据框的相关变量,仅需掌握MARGIN的参数含义即可,要牢记1代表计算行,2代表计算列。
mydf <- data.frame(matrix(rnorm(48,10,5),nrow=6,dimnames=list(NULL,LETTERS[1:8])))
A B C D E F G H
1 12.613699 5.471280 10.723466 3.7370156 2.845806 6.887259 4.680479 13.422446
2 14.588237 11.027817 12.484466 -0.9092612 9.835008 17.976195 17.649579 9.651938
3 2.939922 5.989195 4.310257 6.9660366 5.623445 12.950469 10.591221 8.729425
4 4.131217 13.610730 14.042249 9.0431193 9.941429 3.802639 10.037765 11.986332
5 10.155239 11.301701 3.349171 13.3299717 1.267965 13.767660 5.857686 7.801586
6 13.993980 7.249232 6.482925 8.7703328 5.489774 14.429364 9.675892 2.890610
apply(mydf,1,mean) #计算数据框的行均值
[1] 7.547681 11.537997 7.262496 9.574435 8.353872 8.622764
apply(mydf,2,mean) #计算数据框的列均值
A B C D E F G H
9.737049 9.108326 8.565422 6.822869 5.833905 11.635598 9.748770 9.080390
除此之外,还有几个计算行列统计量的快捷函数:colSums、colMeans
colSums(mydf)
A B C D E F G H
58.42229 54.64995 51.39253 40.93721 35.00343 69.81359 58.49262 54.48234
rowSums(mydf)
[1] 60.38145 92.30398 58.09997 76.59548 66.83098 68.98211
colMeans(mydf)
A B C D E F G H
9.737049 9.108326 8.565422 6.822869 5.833905 11.635598 9.748770 9.080390
rowMeans(mydf)
[1] 7.547681 11.537997 7.262496 9.574435 8.353872 8.622764
Python
python中涉及维度操作的函数有这么几个:applyapplymapmap
import pandas as pd
import numpy as np
df= pd.DataFrame(np.random.randn(8,6), columns=list('ABCDEF'))
?df.apply
Signature: df.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)
Docstring:
Applies function along input axis of DataFrame.
Parameters
----------
func : function
Function to apply to each column/row
axis : {0 or 'index', 1 or 'columns'}, default 0
* 0 or 'index': apply function to each column
* 1 or 'columns': apply function to each row
pd中的apply方法与R语言中的apply函数用法以及参数基本一致。其中较为重要的参数是funcaxisargs
func #参数指定需要执行的函数名称;
axis #指定针对对象的哪个轴执行运算
args #是func函数的可选参数
axis轴的选择规则是0或者index代表行(默认为0),1或者columns代表列。(因为Python中索引以0开始,总体顺序与R中1代表行,2代表列一致)。
df.apply(np.sum,axis=0)
Out[6]:
A 2.042850
B -0.018453
C -2.656881
D -0.621382
E -6.504787
F -4.363466
dtype: float64
df.apply(np.sum,axis=1)
Out[7]:
0 -2.6334631 -3.4064622 -4.2373143 0.0073824 -2.8301175 -2.7321456 0.3313507 3.378650
dtype: float64
func参数同样支持自定义函数以及匿名函数;
df.apply(lambda x: np.sqrt(np.abs(x)),axis=1)
A B C D E F
0 0.518005 1.315212 0.495409 1.584483 0.134769 1.265769
1 1.016121 0.506741 1.080625 0.239525 1.509077 1.092389
2 0.812656 0.563715 0.404424 0.792446 1.685342 0.213683
3 0.191120 0.855446 0.991484 0.869212 0.683357 0.754288
4 0.649375 0.857485 0.785169 1.158319 0.751475 1.210032
5 0.187696 0.535870 1.006190 0.843008 1.148970 1.196930
6 1.170808 0.605734 0.835844 0.984158 1.005559 0.815561
7 0.679565 1.055820 0.250509 1.217166 1.412106 0.828901
applymap函数针对所有元素执行函数,不区分行列:
Signature: df.applymap(func)
Docstring:
Apply a function to a DataFrame that is intended to operate
elementwise, i.e. like doing map(func, series) for each series in the
DataFrame
Parameters
----------
func : function
Python function, returns a single value from a single value
df.applymap(lambda x: '%.2f' % x)
A B C D E F
0 0.27 -1.73 -0.25 -2.51 -0.02 1.60
1 1.03 0.26 -1.17 -0.06 -2.28 -1.19
2 -0.66 -0.32 0.16 -0.63 -2.84 0.05
3 0.04 -0.73 0.98 0.76 -0.47 -0.57
4 0.42 0.74 -0.62 -1.34 -0.56 -1.46
5 0.04 0.29 -1.01 0.71 -1.32 -1.43
6 1.37 0.37 -0.70 0.97 -1.01 -0.67
7 -0.46 1.11 -0.06 1.48 1.99 -0.69
df.applymap(lambda x: x if x>0 else 0)
A B C D E F
0 0.268329 0.000000 0.000000 0.000000 0.000000 1.602172
1 1.032502 0.256786 0.000000 0.000000 0.000000 0.000000
2 0.000000 0.000000 0.163559 0.000000 0.000000 0.045660
3 0.036527 0.000000 0.983041 0.755529 0.000000 0.000000
4 0.421687 0.735280 0.000000 0.000000 0.000000 0.000000
5 0.035230 0.287157 0.000000 0.710662 0.000000 0.000000
6 1.370792 0.366914 0.000000 0.968567 0.000000 0.000000
7 0.000000 1.114756 0.000000 1.481492 1.994043 0.000000
map函数专门针对单个序列内的所有元素进行操作,有点儿类似于apply指定序列后的操作。
Init signature: map(self, /, *args, **kwargs)
Docstring:
map(func, *iterables) --> map object
Make an iterator that computes the function using arguments from
each of the iterables. Stops when the shortest iterable is exhausted.
Type: type
df['A'].map(lambda x: round(x))
Out[34]:
0 01 12 -13 04 05 06 17 0
Name: A, dtype: int64
df['B'].map(lambda x: np.abs(x))
Out[36]:
0 1.7297831 0.2567862 0.3177753 0.7317884 0.7352805 0.2871576 0.3669147 1.114756
Name: B, dtype: float64
df['C'].map(lambda x: '%.2f' % x)
Out[37]:
0 -0.251 -1.172 0.163 0.984 -0.625 -1.016 -0.707 -0.06
Name: C, dtype: object
df['D'].map(lambda x: x if x > 0 else 0)
Out[38]:
0 0.0000001 0.0000002 0.0000003 0.7555294 0.0000005 0.7106626 0.9685677 1.481492
Name: D, dtype: float64
本文小结:
R
apply
Python
apply
applymap
map
往期案例数据请移步本人GitHub: https://github.com/ljtyduyu/DataWarehouse/tree/master/File
- 【译】Spring 官方教程:创建批处理服务
- Oracle12c R2版本Application Containers特性(三)
- Shell系列-编写及执行脚本
- Spring Security 入门(五):在 Spring-Boot中的应用
- Go语言Goroutine与Channel内存模型
- Tarjan--LCA算法的个人理解即模板
- spark sql编程之实现合并Parquet格式的DataFrame的schema
- Oracle压缩黑科技(一)—基础表压缩
- 12 条用于 Linux 的 MySQL/MariaDB 安全最佳实践
- hdu----(4545)魔法串(LCS)
- Oracle压缩黑科技(二)—压缩数据的修改
- 在Pivotal Web Service上发布Spring Boot应用
- hdu---(1325)Is It A Tree?(并查集)
- spark2 sql编程样例:sql操作
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Mybatis系列第四讲 Mybatis使用详解(2)
- 大型项目技术栈第八讲 Redis
- 大型项目技术栈第七讲 Chosen的使用
- 大型项目技术栈第六讲 EasyExcel的使用
- JavaWeb第二讲 重定向与转发 & doGet()与doPost()
- JavaWeb第一讲 Servlet的工作原理及生命周期
- 多系列数据核密度图
- leetcode树之二叉树的层平均值
- 大型项目技术栈第二讲 ES6(ECMAScript 6.0)的使用
- 大型项目技术栈第三讲 ztree的使用
- JavaWeb新手训练经典项目 & 半小时高效开发 & 海量知识点涵盖 = 从这里开始
- Java反射_笔记分享
- Java注解详细总结
- 文档驱动 —— 表单组件(六):基于AntDV的Form表单的封装,目标还是不写代码
- 这就是你日日夜夜想要的docker!!!---------Docker资源控制--Cgroup