我有一个包含18个数据框的列表,每个数据框都有不同的行数和随机空白行,结构如下:
l = c("D1", "D1", "D1", "", "D1", "D1", "D1", "D2", "D2", "D2", "D2", "", "D3", "D3", "D3", "D3")
a = c("Al", "Al", "St", "", "St", "Un", "St", "Al", "Al", "St", "St", "", "Al", "Al", "St", "St")
b = c(6000, 4980, 123, "", 98, 87, 51, 10989, 8756, 457, 233, "", 989, 743, 67, 55)
mydf = data.frame("Location" = l, "Name" = a, "count" = b)
mydf
Location Name count
1 D1 Al 6000
2 D1 Al 4980
3 D1 St 123
4
5 D1 St 98
6 D1 Un 87
7 D1 St 51
8 D2 Al 10989
9 D2 Al 8756
10 D2 St 457
11 D2 St 233
12
13 D3 Al 989
14 D3 Al 743
15 D3 St 67
16 D3 St 55
我的数据包含18个数据框:
sapply(mydata, dim)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] [,17] [,18]
[1,] 171 146 132 147 149 148 138 143 114 111 115 101 112 218 122 96 156 128
[2,] 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
我想使用transform
向我的数据框添加一列,其中包含每个位置的Al计数总和。我打算用相同的值填充整个新列。我以为我可以找到那些包含字符串" Al"然后应用sum函数但这不起作用。这是我试图使用的代码:
add.al.sum = function(df){
als = df[grep("Al", df$Name),]
alsum = sum(als, na.rm = TRUE)
transform(df, Al.sum = c(alsum))
}
mydf = lapply(mydf, function(x) add.al.sum(x))
这不能做我想做的事。我希望我的转换数据表看起来像这样; 不需要保留空行。
Location Name count Al.sum
1 D1 Al 6000 10980
2 D1 Al 4980 10980
3 D1 St 123 10980
4 NA
5 D1 St 98 10980
6 D1 Un 87 10980
7 D1 St 51 10980
8 D2 Al 10989 19745
9 D2 Al 8756 19745
10 D2 St 457 19745
11 D2 St 233 19745
12 NA
13 D3 Al 989 1732
14 D3 Al 743 1732
15 D3 St 67 1732
16 D3 St 55 1732
它实际上告诉我Error in df$Name : $ operator is invalid for atomic vectors
。我的实际数据与示例数据之间的唯一区别是,我的实际数据中的count
列列为int
而不是num
。我需要这个来处理int
列中的count
值。
在我得到Al计数的总和之后,我将重复这个过程,以便在各自的列中得到St和Un计数的总和。
编辑:我扩展了示例数据,并添加了有关我正在使用的数据框列表的更多信息。
答案 0 :(得分:2)
我们可以使用dplyr
library(dplyr)
mydf %>%
group_by(Location) %>%
mutate(Al.sum = sum(count[Name == 'Al']))
#Source: local data frame [10 x 4]
#Groups: Location [2]
# Location Name count Al.sum
# <fctr> <fctr> <dbl> <dbl>
#1 D1 Al 6000 10980
#2 D1 Al 4980 10980
#3 D1 St 123 10980
#4 D1 St 98 10980
#5 D1 Un 87 10980
#6 D1 St 51 10980
#7 D2 Al 10989 19745
#8 D2 Al 8756 19745
#9 D2 St 457 19745
#10 D2 St 233 19745
或通过data.table
library(data.table)
setDT(mydf)[, Al.sum := sum(count[Name == 'Al']), by = Location]
答案 1 :(得分:1)
这不使用任何包,只有一行代码。对于那些(Name == 'Al') * count
等于count
的行,Name
等于'A1'
,对于那些不为ifelse(Name == 'A1', count, 0)
的行,等于0。 (或者我们可以用ave
替换该表达式。然后,我们使用Location
将它们加起来mydf0
。请注意,我们使用的是底部注释2中定义的transform(mydf0, Al.sum = ave((Name == 'Al') * count, Location, FUN = sum))
。
Location Name count Al.sum
1 D1 Al 6000 10980
2 D1 Al 4980 10980
3 D1 St 123 10980
4 D1 St 98 10980
5 D1 Un 87 10980
6 D1 St 51 10980
7 D2 Al 10989 19745
8 D2 Al 8756 19745
9 D2 St 457 19745
10 D2 St 233 19745
,并提供:
sum(..., na.rm = TRUE)
示例数据没有NA值,因此我们没有使用sum
,但是如果要将其扩展到要删除NA值的其他数据,则将function(x) sum(x, na.rm = TRUE)
替换为L
。
<强>列表强>
这个问题提到了多个数据框,但没有给出一个例子;所以我们假设我们有下面显示的数据框列表L <- list(mydf0, mydf0)
lapply(L, transform, Al.sum = ave((Name == 'Al') * count, Location, FUN = sum))
。然后:
grepl
注意:我们可以在这样的问题中修复解决方案。 by
导致逻辑向量在乘法时被视为0/1向量,因此非Al计数归零。然后Location
将rbind
应用于Location
,add.al.sum = function(df) {
transform(df, Al.sum = sum(grepl("Al", Name) * count, na.rm = TRUE))
}
do.call("rbind", by(mydf0, mydf$Location, add.al.sum))
将各个部分(每个mydf0 <- mydf # preserve mydf just in case
mydf0[] <- lapply(mydf0, as.character) # make all cols character
mydf0 <- transform(mydf0, count = as.numeric(count)) # make count numeric
mydf0 <- subset(mydf0, Location != "") # remove blank lines
一个)放在一起。
git-svn
注2:首先修复数据框:
git-svn
更简单的方法是确保在读取数据时忽略空行并使列成为字符,但这取决于它们的读取方式。