每当我想在R中做一些"map"py时,我通常会尝试使用一个函数 apply
家族中.
但是,我从来没有完全理解它们之间的区别 - 如何{ sapply
,lapply
等}将函数应用于输入/分组输入,输出将是什么样的,甚至输入可以是什么 - 所以我经常只要仔细检查它们,直到我得到我想要的东西.
有人可以解释如何使用哪一个?
我当前(可能不正确/不完整)的理解是......
sapply(vec, f)
:输入是一个向量.output是一个向量/矩阵,其中element i
是f(vec[i])
一个矩阵,如果f
有一个多元素输出
lapply(vec, f)
:相同sapply
,但输出是一个列表?
apply(matrix, 1/2, f)
:输入是一个矩阵.output是一个向量,其中element i
是f(矩阵的row/col i)tapply(vector, grouping, f)
:output是一个矩阵/数组,其中矩阵/数组中的元素是向量f
分组g
的值,和g
被推送到行/列名称by(dataframe, grouping, f)
:让我们g
成为一个分组.适用f
于组/数据框的每一列.漂亮打印分组和f
每列的值.aggregate(matrix, grouping, f)
:类似于by
,但不是将输出打印得很漂亮,而是将所有内容都粘贴到数据帧中.侧问题:我还没有学会plyr或重塑-将plyr
或reshape
更换所有这些完全?
有没有办法在我的lapply()函数中获取列表索引名称?
n = names(mylist)
lapply(mylist, function(list.elem) { cat("What is the name of this list element?\n" })
Run Code Online (Sandbox Code Playgroud)
我之前询问是否可以在lapply()返回列表中保留索引名称,但我仍然不知道是否有一种简单的方法来获取自定义函数中的每个元素名称.我想避免在名称本身上调用lapply,我宁愿在函数参数中获取名称.
(这一定是一个非常基本的问题,但到目前为止我没有在R手册中找到答案......)
当我使用lapply语法时lapply
- 这很容易理解,我可以像这样定义myfun:
myfun <- function(x) {
# doing something here with x
}
lapply(input, myfun);
Run Code Online (Sandbox Code Playgroud)
和元素R
作为lapply(input, myfun);
参数传递给input
.
但是,如果我需要传递更多参数x
呢?例如,它定义如下:
myfun <- function(x, arg1) {
# doing something here with x and arg1
}
Run Code Online (Sandbox Code Playgroud)
如何使用此函数传递两个myfun
元素(作为myfunc
参数)和其他一些参数?
我需要访问lapply函数中的列表名称.我在网上发现了一些线程,据说我应该遍历列表的名称,以便能够获取我的函数中的每个列表元素名称:
> n = names(mylist)
> mynewlist = lapply(n, function(nameindex, mylist) { return(mylist[[nameindex]]) }, mylist)
> names(mynewlist)
NULL
> names(mynewlist) = n
Run Code Online (Sandbox Code Playgroud)
问题是mynewlist丢失了原始的mylist索引,我必须添加last names()赋值来恢复它们.
有没有办法为lapply函数返回的每个元素提供显式索引名称?或者以不同的方式确保mynewlist元素具有正确的索引名称集?如果lapply没有以与mylist相同的顺序返回列表元素,我觉得mynewlist索引名称可能是错误的.
我使用大量固定宽度的文件(即没有分隔字符),我需要读入R.所以,通常有一个列宽度的定义来将字符串解析为变量.我可以read.fwf
用来读取数据没有问题.但是,对于大文件,这可能需要很长时间.对于最近的数据集,这需要800秒来读取具有~500,000行和143个变量的数据集.
seer9 <- read.fwf("~/data/rawdata.txt",
widths = cols,
header = FALSE,
buffersize = 250000,
colClasses = "character",
stringsAsFactors = FALSE))
Run Code Online (Sandbox Code Playgroud)
fread
在data.table
R 中的包中解决大多数数据读取问题非常棒,除了它不解析固定宽度的文件.但是,我可以将每一行读作单个字符串(~500,000行,1列).这需要3-5秒.(我喜欢data.table.)
seer9 <- fread("~/data/rawdata.txt", colClasses = "character",
sep = "\n", header = FALSE, verbose = TRUE)
Run Code Online (Sandbox Code Playgroud)
关于如何解析文本文件,有很多关于SO的好帖子.见JHoward的建议在这里,创建起始和终止列的矩阵,并substr
分析数据.请参阅此处使用的GSee建议strsplit
.我无法弄清楚如何使用这些数据.(另外,迈克尔史密斯对data.table邮件列表提出了一些建议,这些建议sed
超出了我的实施能力.)现在,使用fread
和substr()
我可以在大约25-30秒内完成整个事情.请注意,在结束时强制转换为data.table需要一段时间(5秒?).
end_col <- cumsum(cols)
start_col <- end_col - cols + 1
start_end <- cbind(start_col, end_col) # matrix of start …
Run Code Online (Sandbox Code Playgroud) 有没有办法在两个向量上使用mapply来构造命名列表?第一个向量是类型character
,包含用于列表的名称,而第二个包含值.
到目前为止,我唯一的解决方案是:
> dummyList = list()
> addToList <- function(name, value) {
+ dummyList[[name]] <- value
+ }
> mapply(addToList, c("foo", "bar"), as.list(c(1, 2))
$foo
`1`
$bar
`2`
Run Code Online (Sandbox Code Playgroud)
这似乎是一个相当人为的解决方案,但我无法弄清楚如何做到这一点.我遇到的问题是:
它需要创建dummyList
即使dummyList
永远不会改变,并且在调用之后是一个空列表mapply
.
如果数字向量,,, c(1, 2)
没有转换为列表,则调用的结果mapply
是双精度命名向量.
为了解决问题2,我总是可以调用mapply
两个向量然后调用as.list
结果,但似乎应该有一种方法可以直接创建一个值在向量中的列表.
假设我有一个data.frames列表
dflist <- list(data.frame(a=1:3), data.frame(b=10:12, a=4:6))
Run Code Online (Sandbox Code Playgroud)
如果我想从列表中的每个项目中提取第一列,我可以这样做
lapply(dflist, `[[`, 1)
# [[1]]
# [1] 1 2 3
#
# [[2]]
# [1] 10 11 12
Run Code Online (Sandbox Code Playgroud)
为什么我不能以同样的方式使用"$"函数
lapply(dflist, `$`, "a")
# [[1]]
# NULL
#
# [[2]]
# NULL
Run Code Online (Sandbox Code Playgroud)
但这些都有效:
lapply(dflist, function(x) x$a)
`$`(dflist[[1]], "a")
Run Code Online (Sandbox Code Playgroud)
我意识到在这种情况下可以使用
lapply(dflist, `[[`, "a")
Run Code Online (Sandbox Code Playgroud)
但我正在使用一个似乎不允许索引的S4对象[[
.例如
library(adegenet)
data(nancycats)
catpop <- genind2genpop(nancycats)
mylist <- list(catpop, catpop)
#works
catpop[[1]]$tab
#doesn't work
lapply(mylist, "$", "tab")
# Error in slot(x, name) :
# no slot of name "..." for …
Run Code Online (Sandbox Code Playgroud) 我在下面有一个示例函数,它将日期作为字符串读入并将其作为日期对象返回.如果它读取的字符串无法转换为日期,则会返回错误.
testFunction <- function (date_in) {
return(as.Date(date_in))
}
testFunction("2010-04-06") # this works fine
testFunction("foo") # this returns an error
Run Code Online (Sandbox Code Playgroud)
现在,我想使用lapply并在日期列表中应用此函数:
dates1 = c("2010-04-06", "2010-04-07", "2010-04-08")
lapply(dates1, testFunction) # this works fine
Run Code Online (Sandbox Code Playgroud)
但是,如果我想在两个好日期中间的一个字符串返回错误时将该函数应用于列表,那么处理此问题的最佳方法是什么?
dates2 = c("2010-04-06", "foo", "2010-04-08")
lapply(dates2, testFunction)
Run Code Online (Sandbox Code Playgroud)
我认为我想在那里试一试,但是有没有办法捕获"foo"字符串的错误,同时要求lapply继续阅读第三个日期?
这非常类似于将一个共同功能应用于一个data.table
完整.SDcols
答案的多个列的问题.
不同之处在于我想同时在不属于.SD
子集的另一列上应用不同的函数.我在下面发布一个简单的例子来展示我尝试解决问题:
dt = data.table(grp = sample(letters[1:3],100, replace = TRUE),
v1 = rnorm(100),
v2 = rnorm(100),
v3 = rnorm(100))
sd.cols = c("v2", "v3")
dt.out = dt[, list(v1 = sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]
Run Code Online (Sandbox Code Playgroud)
产生以下错误:
Error in `[.data.table`(dt, , list(v1 = sum(v1), lapply(.SD, mean)), by = grp,
: object 'v1' not found
Run Code Online (Sandbox Code Playgroud)
现在这是有道理的,因为v1
列不包含在必须首先计算的列子集中.所以我通过将其包含在我的列子集中进一步探索:
sd.cols = c("v1","v2", "v3")
dt.out = dt[, list(sum(v1), lapply(.SD,mean)), by = grp, .SDcols = …
Run Code Online (Sandbox Code Playgroud) 假设我们在目录C:\ R\Data中有文件file1.csv,file2.csv,...和file100.csv,我们希望将它们全部读入单独的数据框(例如file1,file2,...和file100).
这样做的原因是,尽管具有相似的名称,但它们具有不同的文件结构,因此将它们放在列表中并不是很有用.
我可以使用lapply
但返回包含100个数据帧的单个列表.相反,我想在全球环境中使用这些数据框.
如何直接将多个文件读入全局环境?或者,或者,如何将数据框列表的内容解压缩到其中?