Tôi muốn tổng các cột riêng lẻ theo nhóm và suy nghĩ đầu tiên của tôi là sử dụng tapply
. Tuy nhiên, tôi không thể nhận được tapply
để hoạt động. Có thể sử dụng tapply
để tổng hợp nhiều cột không? Nếu không, tại sao không?tổng hợp nhiều cột theo nhóm với tapply
Tôi đã tìm kiếm trên Internet rộng rãi và tìm thấy nhiều câu hỏi tương tự được đăng từ năm 2008. Tuy nhiên, không có câu hỏi nào được trả lời trực tiếp. Thay vào đó, các câu trả lời luôn đề xuất sử dụng một hàm khác.
Dưới đây là tập hợp dữ liệu mẫu mà tôi muốn tổng hợp táo theo tiểu bang, quả anh đào theo tiểu bang và mận theo tiểu bang. Dưới đây tôi đã biên soạn nhiều lựa chọn thay thế cho tapply
rằng hoạt động.
Ở dưới cùng, tôi hiển thị sửa đổi đơn giản cho mã nguồn tapply
cho phép tapply
thực hiện thao tác mong muốn.
Tuy nhiên, có lẽ tôi đang xem một cách đơn giản để thực hiện thao tác mong muốn với tapply
. Tôi không tìm kiếm các chức năng thay thế, mặc dù các lựa chọn thay thế khác được hoan nghênh.
Do sự đơn giản của việc sửa đổi của tôi thành mã nguồn tapply
Tôi tự hỏi tại sao nó, hoặc một cái gì đó tương tự, chưa được triển khai.
Cảm ơn bạn đã được tư vấn. Nếu câu hỏi của tôi là bản sao, tôi sẽ sẵn lòng đăng câu hỏi của tôi dưới dạng câu trả lời cho câu hỏi khác đó.
Dưới đây là tập hợp dữ liệu ví dụ:
df.1 <- read.table(text = '
state county apples cherries plums
AA 1 1 2 3
AA 2 10 20 30
AA 3 100 200 300
BB 7 -1 -2 -3
BB 8 -10 -20 -30
BB 9 -100 -200 -300
', header = TRUE, stringsAsFactors = FALSE)
này không hoạt động:
tapply(df.1, df.1$state, function(x) {colSums(x[,3:5])})
Các trang trợ giúp nói:
tapply(X, INDEX, FUN = NULL, ..., simplify = TRUE)
X an atomic object, typically a vector.
tôi đã nhầm lẫn bởi những cụm từ typically a vector
mà làm cho tôi tự hỏi liệu có thể sử dụng khung dữ liệu không. Tôi chưa bao giờ rõ ràng về những gì có nghĩa là atomic object
.
Dưới đây là một số lựa chọn thay thế cho tapply
hoạt động. Giải pháp thay thế đầu tiên là công việc xung quanh kết hợp tapply
với apply
.
apply(df.1[,c(3:5)], 2, function(x) tapply(x, df.1$state, sum))
# apples cherries plums
# AA 111 222 333
# BB -111 -222 -333
with(df.1, aggregate(df.1[,3:5], data.frame(state), sum))
# state apples cherries plums
# 1 AA 111 222 333
# 2 BB -111 -222 -333
t(sapply(split(df.1[,3:5], df.1$state), colSums))
# apples cherries plums
# AA 111 222 333
# BB -111 -222 -333
t(sapply(split(df.1[,3:5], df.1$state), function(x) apply(x, 2, sum)))
# apples cherries plums
# AA 111 222 333
# BB -111 -222 -333
aggregate(df.1[,3:5], by=list(df.1$state), sum)
# Group.1 apples cherries plums
# 1 AA 111 222 333
# 2 BB -111 -222 -333
by(df.1[,3:5], df.1$state, colSums)
# df.1$state: AA
# apples cherries plums
# 111 222 333
# ------------------------------------------------------------
# df.1$state: BB
# apples cherries plums
# -111 -222 -333
with(df.1,
aggregate(x = list(apples = apples,
cherries = cherries,
plums = plums),
by = list(state = state),
FUN = function(x) sum(x)))
# state apples cherries plums
# 1 AA 111 222 333
# 2 BB -111 -222 -333
lapply(split(df.1, df.1$state), function(x) {colSums(x[,3:5])})
# $AA
# apples cherries plums
# 111 222 333
#
# $BB
# apples cherries plums
# -111 -222 -333
Đây là mã nguồn cho tapply
ngoại trừ việc tôi đã thay đổi dòng:
nx <- length(X)
tới:
nx <- ifelse(is.vector(X), length(X), dim(X)[1])
Phiên bản này được sửa đổi của tapply
thực hiện các hoạt động mong muốn:
my.tapply <- function (X, INDEX, FUN = NULL, ..., simplify = TRUE)
{
FUN <- if (!is.null(FUN)) match.fun(FUN)
if (!is.list(INDEX)) INDEX <- list(INDEX)
nI <- length(INDEX)
if (!nI) stop("'INDEX' is of length zero")
namelist <- vector("list", nI)
names(namelist) <- names(INDEX)
extent <- integer(nI)
nx <- ifelse(is.vector(X), length(X), dim(X)[1]) # replaces nx <- length(X)
one <- 1L
group <- rep.int(one, nx) #- to contain the splitting vector
ngroup <- one
for (i in seq_along(INDEX)) {
index <- as.factor(INDEX[[i]])
if (length(index) != nx)
stop("arguments must have same length")
namelist[[i]] <- levels(index)#- all of them, yes !
extent[i] <- nlevels(index)
group <- group + ngroup * (as.integer(index) - one)
ngroup <- ngroup * nlevels(index)
}
if (is.null(FUN)) return(group)
ans <- lapply(X = split(X, group), FUN = FUN, ...)
index <- as.integer(names(ans))
if (simplify && all(unlist(lapply(ans, length)) == 1L)) {
ansmat <- array(dim = extent, dimnames = namelist)
ans <- unlist(ans, recursive = FALSE)
} else {
ansmat <- array(vector("list", prod(extent)),
dim = extent, dimnames = namelist)
}
if(length(index)) {
names(ans) <- NULL
ansmat[index] <- ans
}
ansmat
}
my.tapply(df.1$apples, df.1$state, function(x) {sum(x)})
# AA BB
# 111 -111
my.tapply(df.1[,3:4] , df.1$state, function(x) {colSums(x)})
# $AA
# apples cherries
# 111 222
#
# $BB
# apples cherries
# -111 -222