京公网安备 11010802034615号
经营许可证编号:京B2-20210330
r语言常用函数apply及subset函数
1、merge函数对数据框的操作,从两个数据框中选择出条件相等的行组合成一个新的数据框
df1=data.frame(name=c("aa","bb","cc"),age=c(20,29,30),sex=c("f","m","f"))
df2=data.frame(name=c("dd","bb","cc"),age=c(40,35,36),sex=c("f","m","f"))
mergedf=merge(df1,df2,by="name")
2、subset函数,从某一个数据框中选择出符合某条件的数据或是相关的列
(1)单条件查询
> selectresult=subset(df1,name=="aa")
> selectresult
name age sex
1 aa 20 f
> df1
name age sex
1 aa 20 f
2 bb 29 m
3 cc 30 f
(2)指定显示列
> selectresult=subset(df1,name=="aa",select=c(age,sex))
> selectresult
age sex
1 20 f
(3)多条件查询
> selectresult=subset(df1,name=="aa" & sex=="f",select=c(age,sex))
> selectresult
age sex
1 20 f
> df1
name age sex
1 aa 20 f
2 bb 29 m
3 cc 30 f
为什么用apply
因为我是一个程序员,所以在最初学习R的时候,当成“又一门编程语言”来学习,但是怎么学都觉得别扭。现在我的看法倾向于,R不是一种通用型的编程语言,而是一种统计领域的软件工具。因此,不能用通用型编程的思维来设计R代码。在Andrew Lim关于R和Python的对比回答中,R是一种面向数组(array-oriented)的语法,它更像数学,方便科学家将数学公式转化为R代码。而Python是一种通用编程语言,更工程化。在使用R时,要尽量用array的方式思考,避免for循环。不用循环怎么实现迭代呢?这就需要用到apply函数族。它不是一个函数,而是一族功能类似的函数。
概述
apply系列函数的基本作用是对数组(array,可以是多维)或者列表(list)按照元素或元素构成的子集合进行迭代,并将当前元素或子集合作为参数调用某个指定函数。vector是一维的array,dataframe可以看作特殊的list。
这些函数间的关系
作用目标 在每个元素上应用 在子集合上应用
array apply tapply
list lapply(...) by
其中lapply(...)包括一族函数
lapply
|
|-> 简化版: sapply
| | -> 可设置返回值模板: vapply
| |-> 多变量版: mapply
|
|-> 递归版: rapply
另外vector比较奇怪,vector是一维的array,但是却不全是和array使用相同的函数。在按元素迭代的情况下,使用和list一样的lapply函数;而在按子集合迭代的情况下,tapply和by都能用,只是返回值形式不同。
功能与语法描述
apply
apply(array, margin, FUN, ...)
在array上,沿margin方向,依次调用FUN。返回值为vector。margin表示数组引用的第几维下标(即array[index1, index2, ...]中的第几个index),1对应为1表示行,2表示列,c(1,2)表示行列。margin=1时,apply(a, 1, sum)等效于下面的操作
a <- array(c(1:24), dim=c(2,3,4))
result=c()
for (i in c(1:dim(a)[1])) {
result <- c(result, sum(a[i,,]))
}
经实测,只能用在二维及以上的array上,不能用在vector上(如果要应用于vector,请使用lapply或sapply)。以matrix为例,如下
> m <- matrix(c(1:10), nrow=2)
> m
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 5 7 9
[2,] 2 4 6 8 10
> apply(m, 1, sum)
[1] 25 30
> apply(m, 2, sum)
[1] 3 7 11 15 19
tapply
tapply(array, indices, margin, FUN=NULL, ...)
按indices中的值分组,把相同值对应下标的array中的元素形成一个集合,应用到FUN。类似于group by indices的操作。如果FUN返回的是一个值,tapply返回vector;若FUN返回多个值,tapply返回list。vector或list的长度和indices中不同值的个数相等。
当FUN为NULL的时候,返回一个长度和array中元素个数相等的vector,指示分组的结果,vector中相等的元素所对应的下标属于同一组。例如,返回c(1, 2, 1, 3, 2), 表示根据传入的indices,第1、3个元素作为一组,第2、5个元素作为一组,第4个元素作为一组。
一维array的例子(即vector)
> v <- c(1:5)
> ind <- c('a','a','a','b','b')
> tapply(v, ind)
[1] 1 1 1 2 2
> tapply(v, ind, sum)
a b
6 9
> tapply(v, ind, fivenum)
$a
[1] 1.0 1.5 2.0 2.5 3.0
$b
[1] 4.0 4.0 4.5 5.0 5.0
二维array的例子(即matrix)
> m <- matrix(c(1:10), nrow=2)
> m
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 5 7 9
[2,] 2 4 6 8 10
> ind <- matrix(c(rep(1,5), rep(2,5)), nrow=2)
> ind
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 2 2
[2,] 1 1 2 2 2
> tapply(m, ind)
[1] 1 1 1 1 1 2 2 2 2 2
> tapply(m, ind, mean)
1 2
3 8
> tapply(m, ind, fivenum)
$`1`
[1] 1 2 3 4 5
$`2`
[1] 6 7 8 9 10
by
by(dataframe, INDICES, FUN, ..., simplify=TRUE)
by可以当成dataframe上的tapply。indices应当和dataframe每列的长度相同。返回值是by类型的object。若simplify=FALSE,本质上是个list。
> df <- data.frame(a=c(1:5), b=c(6:10))
> ind <- c(1,1,1,2,2)
> res <- by(df, ind, colMeans)
> res
ind: 1
a b
2 7
------------------------------------------------------------
ind: 2
a b
4.5 9.5
> class(res)
[1] "by"
> names(res)
[1] "1" "2"
lapply
lapply(list, FUN, ...)
在list上逐个元素调用FUN。可以用于dataframe上,因为dataframe是一种特殊形式的list。例
> lst <- list(a=c(1:5), b=c(6:10))
> lapply(lst, mean)
$a
[1] 3
$b
[1] 8
> lapply(lst, fivenum)
$a
[1] 1 2 3 4 5
$b
[1] 6 7 8 9 10
sapply
sapply(list, FUN, ..., simplify, USE.NAME=TRUE)
比lapply多了一个simplify参数。如果simplify=FALSE,则等价于lapply。否则,在上一种情况的基础上,将lapply输出的list简化为vector或matrix。例
> lst <- list(a=c(1:5), b=c(6:10))
> sapply(lst, mean)
a b
3 8
> sapply(lst, fivenum)
a b
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
vapply
vapply(list, FUN, FUN.VALUE, ..., USE.NAME=TRUE)
vapply类似于sapply,但是提供了第三个参数FUN.VALUE用以指明返回值的形式,可以看作返回值的模板。例
> lst <- list(a=c(1:5), b=c(6:10))
> res <- vapply(lst, function(x) c(min(x), max(x)), c(min.=0, max.=0))
> res
a b
min. 1 6
max. 5 10
mapply
mapply(FUN, ..., MoreArgs=NULL, SIMPLIFY=TRUE, USE.NAMES=TRUE)
mapply是多变量版的sapply,参数(...)部分可以接收多个数据,mapply将FUN应用于这些数据的第一个元素组成的数组,然后是第二个元素组成的数组,以此类推。要求多个数据的长度相同,或者是整数倍关系。返回值是vector或matrix,取决于FUN返回值是一个还是多个。
> mapply(sum, list(a=1,b=2,c=3), list(a=10,b=20,d=30))
a b c
11 22 33
> mapply(function(x,y) x^y, c(1:5), c(1:5))
[1] 1 4 27 256 3125
> mapply(function(x,y) c(x+y, x^y), c(1:5), c(1:5))
[,1] [,2] [,3] [,4] [,5]
[1,] 2 4 6 8 10
[2,] 1 4 27 256 3125
rapply
rapply(list, FUN, classes="ANY", deflt=NULL, how=c("unlist", "replace", "list"), ...)
rapply是递归版的lappy。基本原理是对list作遍历,如果其中有的元素仍然是list,则继续遍历;对于每个非list类型的元素,如果其类型是classes参数指定的类型之一,则调用FUN。classes="ANY"表示匹配所有类型。
how参数用来指定操作方式,有三种:
"replace" 直接用调用FUN后的结果替换原list中原来的元素
"list" 新建一个list,元素类型在classes中的,调用FUN;不在classes中的类型,使用deflt。会保留原始list的结构。
"unlist" 相当于对"list"模式下的结果调用unlist(recursive=TRUE)
> lst <- list(a=list(aa=c(1:5), ab=c(6:10)), b=list(ba=c(1:10)))
> lst
$a
$a$aa
[1] 1 2 3 4 5
$a$ab
[1] 6 7 8 9 10
$b
$b$ba
[1] 1 2 3 4 5 6 7 8 9 10
> rapply(lst, sum, how='list')
$a
$a$aa
[1] 15
$a$ab
[1] 40
$b
$b$ba
[1] 55
> rapply(lst, sum, how='unlist')
a.aa a.ab b.ba
15 40 55
第二个是关于classes和deflt参数使用的例子
> lst2
$a
$a$aa
[1] 1 2 3 4 5
$a$ab
[1] 6 7 8 9 10
$b
$b$ba
[1] "I am a string"
> rapply(lst2, sum, how='unlist')
Error in .Primitive("sum")("I am a string", ...) :
invalid 'type' (character) of argument
> rapply(lst2, sum, classes=c('integer'), deflt=-1, how='unlist')a.aa a.ab b.ba
15 40 -1
> rapply(lst2, nchar, classes=c('character'), deflt=as.integer(NA), how='unlist')
a.aa a.ab b.ba
NA NA 13
eapply
environment上的的apply。从没用过environment,暂时不研究了。
应用
tapply实现crosstable功能
以一个例子演示。原始数据为按年份year、地区loc和商品类别type进行统计的销售量。我们要制作两个销售总量的crosstable,一个以年份为行、地区为列,一个以年份为行,类别为列。
> df <- data.frame(year=kronecker(2001:2003, rep(1,4)), loc=c('beijing','beijing','shanghai','shanghai'), type=rep(c('A','B'),6), sale=rep(1:12))
> df
year loc type sale
1 2001 beijing A 1
2 2001 beijing B 2
3 2001 shanghai A 3
4 2001 shanghai B 4
5 2002 beijing A 5
6 2002 beijing B 6
7 2002 shanghai A 7
8 2002 shanghai B 8
9 2003 beijing A 9
10 2003 beijing B 10
11 2003 shanghai A 11
12 2003 shanghai B 12
> tapply(df$sale, df[,c('year','loc')], sum)
loc
year beijing shanghai
2001 3 7
2002 11 15
2003 19 23
> tapply(df$sale, df[,c('year','type')], sum)
type
year A B
2001 4 6
2002 12 14
2003 20 22
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
在传统零售行业同质化竞争激烈、大众营销转化率持续走低的背景下,依托经验与直觉的粗放式营销逐渐失效。美国塔吉特百货(Target ...
2026-10-10随着智能客服、数字化服务、用户精细化运营的快速普及,传统零散、非标准化的客户服务数据与业务体系逐渐难以支撑高效服务治理。 ...
2026-10-10 很多数据分析师能熟练地写SQL、做透视表、算描述性统计,但当被问到“如何预测用户流失概率”“如何归因销量下滑的关键因素 ...
2026-10-10CDA数据分析师 出品 作者:李诗怡 定义区别 · 场景举例 · 指标分类 · 计算方法 知识体系总览 模块 包含内容 一、核 ...
2026-10-09在数据分析工作流中,业务数据大多存储在各类关系型数据库内,例如MySQL、PostgreSQL、SQLite等。Pandas是Python生态中主流的数 ...
2026-10-09在数字化精细化运营时代,海量用户存在需求差异、行为差异、价值差异与偏好差异。如果企业采用“一刀切”的统一营销、统一服务、 ...
2026-10-09 很多数据分析师拿到数据就开始清洗、建模,但当被问到“这批数据属于什么类型——结构化还是非结构化?分类变量还是数值变量 ...
2026-10-09指标体系是企业数字化分析、业务监控、经营决策的核心基础框架,是将零散数据转化为可衡量、可对比、可落地业务价值的关键体系。 ...
2026-10-08随着市场竞争日趋饱和,同质化低价竞争逐渐陷入内卷僵局,传统以价格、渠道、促销为核心的营销模式边际效益持续递减。在此背景下 ...
2026-10-08 很多数据分析师画过趋势图、做过业绩预测,但当被问到“这个月销售额增长20%,到底是长期趋势自然增长,还是促销活动的短期 ...
2026-10-08你有没有想过,手机里点外卖、刷社交软件、转一笔账,背后到底是谁在替你"记着账"? 答案其实很简单:数据库,以及跟它对话的那 ...
2026-10-07CDA数据分析师 出品 作者:李诗怡 一、数据分析四大思维 1. 对比思维:没有对比就没有分析 核心观点:单独一个数字没有意义,有 ...
2026-10-05Kimball 是方法,星型模型是它产出的形状。 很多人把"Kimball vs 星型模型"当成一道选择题——这本身就是个误会:Kimball 是动词 ...
2026-10-05写在开头 老板在微信上甩来一句: "帮我看下为什么销量跌了。" ” 你回工位,打开 SQL,开始写。查订单表、拉近三个月、按 ...
2026-10-03CDA数据分析师 出品 作者:李诗怡 1. 事实表 vs 维度表 对比维度 事实表 维度表 核心问题 记录“业务发生了什么事” 描述 ...
2026-10-02做数据聚合时,PySpark的groupBy()确实能完成统计,这也是它的本职工作。但它有一个根本性局限:每一组数据,最终只能返回一行 ...
2026-10-01热力地图是数据可视化中极具辨识度与实用性的空间分析图表,结合地理空间维度与数据密度特征,通过颜色深浅、色阶渐变直观展示数 ...
2026-09-30 很多数据分析师做过按月份的销售额趋势图,画过按天的流量折线图,但当被问到“时间序列和普通数据有什么本质区别”“季节性 ...
2026-09-30同样是“银行数据岗”,在国有大行总行数据中心、在一家城商行的零售部、在银行系金融科技子公司、在保险公司,工作内容、成长节 ...
2026-09-29在数据分析与统计学研究中,数据往往不是独立存在的,不同变量之间普遍存在相互关联、相互影响的关系。相关性统计分析是挖掘变量 ...
2026-09-29