将函数应用于按以下方式分组的数据框
Apply function to data frames grouped by
我想将一个函数应用于数据框的子集,这些数据框在按一些变量分组后源自初始数据框。因此,我正在寻找一个与 apply
或类似的包装器等效的包装器,将整个数据帧作为输入并输出一个向量。这是因为手头的函数需要来自不同位置的行和列的条目,不能简化为仅使用行和列,因此采用 lapply
或 apply(df, 1(2),...)
[=21 的形式=]
让我们考虑下面的例子:
iris <- data.table(iris)
my.function <- function(sub.data){
v <- c(NA)
for(j in 2:dim(sub.data)[1]){
if(sub.data[j,1, with = FALSE] > sub.data[j-1,2, with = FALSE]+2){
v[j] <- "ok"
} else {
v[j] <- "not ok"
}
}
return(v)
}
执行 my.function(iris)
工作正常,但假设我只想将该函数应用于具有相同物种的组。因此,在 data.table
语法中,这应该是这样的:
results <- iris[,
wrapper(.SD, my.function),
by = Species
]
其中 wrapper
是我正在寻找的环境,类型为 lapply
或类似。同样,也可以使用 dplyr
包,但我不知道相应的语法是什么:我试过
results <- iris %>%
group_by(Species) %>%
summarise(results = my.function(iris))
但这似乎并没有产生正确的结果,因为它仍然针对每个物种的整个数据集运行,而不是分成子集。
这里好像不需要wrapper
。只需 运行 您在 .SD 上的功能就可以满足您的需求。
library(data.table)
#your function works with a data.table
#by below will create smaller data tables on which you can directly
#run my.function on
iris[, my.function(.SD), by=Species]
输出:
Species V1
1: setosa NA
2: setosa not ok
3: setosa not ok
4: setosa not ok
5: setosa not ok
---
146: virginica ok
147: virginica ok
148: virginica ok
149: virginica ok
150: virginica ok
这里的objective是不使用包吗?
输出向量的长度是否与data.frame的行数相同?如果是这样,请尝试 ave
我们使用了测试 my.function
其中 returns 行数乘以其输入数据帧的列数:
my.function <- function(x) prod(dim(x)) # test function
ave(1:nrow(iris), iris$Species, FUN = function(ix) my.function(iris[ix, ]))
## [1] 250 250 250 250 250 250 250 250 ...
如果 my.function returns 一个长度与输入行数相同的向量,以上内容也适用。
如果在这种情况下您只需要长度为 3 的向量:
tapply(1:nrow(iris), iris$Species, function(ix) my.function(iris[ix, ]))
## setosa versicolor virginica
## 250 250 250
或by
:
c(by(iris, iris$Species, my.function))
## setosa versicolor virginica
## 250 250 250
或sapply/split
:
sapply(split(iris, iris$Species), my.function)
## setosa versicolor virginica
## 250 250 250
我想将一个函数应用于数据框的子集,这些数据框在按一些变量分组后源自初始数据框。因此,我正在寻找一个与 apply
或类似的包装器等效的包装器,将整个数据帧作为输入并输出一个向量。这是因为手头的函数需要来自不同位置的行和列的条目,不能简化为仅使用行和列,因此采用 lapply
或 apply(df, 1(2),...)
[=21 的形式=]
让我们考虑下面的例子:
iris <- data.table(iris)
my.function <- function(sub.data){
v <- c(NA)
for(j in 2:dim(sub.data)[1]){
if(sub.data[j,1, with = FALSE] > sub.data[j-1,2, with = FALSE]+2){
v[j] <- "ok"
} else {
v[j] <- "not ok"
}
}
return(v)
}
执行 my.function(iris)
工作正常,但假设我只想将该函数应用于具有相同物种的组。因此,在 data.table
语法中,这应该是这样的:
results <- iris[,
wrapper(.SD, my.function),
by = Species
]
其中 wrapper
是我正在寻找的环境,类型为 lapply
或类似。同样,也可以使用 dplyr
包,但我不知道相应的语法是什么:我试过
results <- iris %>%
group_by(Species) %>%
summarise(results = my.function(iris))
但这似乎并没有产生正确的结果,因为它仍然针对每个物种的整个数据集运行,而不是分成子集。
这里好像不需要wrapper
。只需 运行 您在 .SD 上的功能就可以满足您的需求。
library(data.table)
#your function works with a data.table
#by below will create smaller data tables on which you can directly
#run my.function on
iris[, my.function(.SD), by=Species]
输出:
Species V1
1: setosa NA
2: setosa not ok
3: setosa not ok
4: setosa not ok
5: setosa not ok
---
146: virginica ok
147: virginica ok
148: virginica ok
149: virginica ok
150: virginica ok
这里的objective是不使用包吗?
输出向量的长度是否与data.frame的行数相同?如果是这样,请尝试 ave
我们使用了测试 my.function
其中 returns 行数乘以其输入数据帧的列数:
my.function <- function(x) prod(dim(x)) # test function
ave(1:nrow(iris), iris$Species, FUN = function(ix) my.function(iris[ix, ]))
## [1] 250 250 250 250 250 250 250 250 ...
如果 my.function returns 一个长度与输入行数相同的向量,以上内容也适用。
如果在这种情况下您只需要长度为 3 的向量:
tapply(1:nrow(iris), iris$Species, function(ix) my.function(iris[ix, ]))
## setosa versicolor virginica
## 250 250 250
或by
:
c(by(iris, iris$Species, my.function))
## setosa versicolor virginica
## 250 250 250
或sapply/split
:
sapply(split(iris, iris$Species), my.function)
## setosa versicolor virginica
## 250 250 250