我正在尝试识别纵向数据集中letter
内的最后ID
。
说我的数据看起来像这样,
dfL <- data.frame(ID = c(1L, 1L, 1L, 4L, 4L, 4L, 4L, 4L, 9L, 9L, 9L, 9L, 9L, 10L), week = c("BS", 4L, 6L, "BS", 6L, 9L, 9L, 12L, "BS", 4L, 6L, 9L, 12L, "BS"), outcome = c(14L, 28L, 42L, 14L, 46L, 64L, 71L, 85L, 14L, 28L, 51L, 66L, 84L, 0L), letter = c("a", "b", "a", "b", "a", "b", "a", "b", "a", "b", "a", "b", NA, NA)); dfL
每个ID
都有一串字母(a
和b
),我需要找到ID
中的最后一个字母,然后将其放入在基线上。
ID week outcome letter
1 1 BS 14 a
2 1 4 28 b
3 1 6 42 a
4 4 BS 14 b
5 4 6 46 a
6 4 9 64 b
7 4 9 71 a
8 4 12 85 b
9 9 BS 14 a
10 9 4 28 b
11 9 6 51 a
12 9 9 66 b
13 9 12 84 <NA>
14 10 BS 0 <NA>
我想最终结果看起来像这样,
ID week outcome letter last_letter
1 1 BS 14 a a
2 1 4 28 b <NA>
3 1 6 42 a <NA>
4 4 BS 14 b b
5 4 6 46 a <NA>
6 4 9 64 b <NA>
7 4 9 71 a <NA>
8 4 12 85 b <NA>
9 9 BS 14 a b
10 9 4 28 b <NA>
11 9 6 51 a <NA>
12 9 9 66 b <NA>
13 9 12 84 <NA> <NA>
14 10 BS 0 <NA> <NA>
我已经使用which.max
软件包中的data.table
和ave
进行了调整,但我仍然有点卡住了。
答案 0 :(得分:4)
使用基础R ave
我会使用这样的自定义函数来处理它:
FUN <- function(x) {
if (all(is.na(x))) return(NA)
tail(na.omit(x), 1)
}
dfL$lastL <- with(dfL, ave(letter, ID, FUN=FUN))
## ID week outcome letter lastL
## 1 1 BS 14 a a
## 2 1 4 28 b a
## 3 1 6 42 a a
## 4 4 BS 14 b b
## 5 4 6 46 a b
## 6 4 9 64 b b
## 7 4 9 71 a b
## 8 4 12 85 b b
## 9 9 BS 14 a b
## 10 9 4 28 b b
## 11 9 6 51 a b
## 12 9 9 66 b b
## 13 9 12 84 <NA> b
## 14 10 BS 0 <NA> <NA>
编辑:
如果您希望它与<NA>
一样,那么使用tapply
的方法就可以了。
FUN <- function(x) {
if (all(is.na(x))) {
first <- NA
} else {
first <- tail(na.omit(x), 1)
}
out <- as.character(rep(NA, length(x)))
out[1] <- as.character(first)
out
}
dfL$lastL <- factor(unlist(with(dfL, tapply(letter, ID, FUN=FUN))))
## ID week outcome letter lastL
## 1 1 BS 14 a a
## 2 1 4 28 b <NA>
## 3 1 6 42 a <NA>
## 4 4 BS 14 b b
## 5 4 6 46 a <NA>
## 6 4 9 64 b <NA>
## 7 4 9 71 a <NA>
## 8 4 12 85 b <NA>
## 9 9 BS 14 a b
## 10 9 4 28 b <NA>
## 11 9 6 51 a <NA>
## 12 9 9 66 b <NA>
## 13 9 12 84 <NA> <NA>
## 14 10 BS 0 <NA> <NA>
答案 1 :(得分:2)
我希望我的问题是对的(我真的不知道每个ID的最后一个字母是什么;我会认为它是结果最高的那个):
然后是data.table
解决方案:
library(data.table)
dfL <- as.data.table(dfL)
setkey(dfL, ID, outcome)
intDT <- dfL[!is.na(letter), list(lastL = tail(letter, 1)), by=ID]
setkey(intDT, ID)
intDT[dfL]
ID lastL week outcome letter
1: 1 a BS 14 a
2: 1 a 4 28 b
3: 1 a 6 42 a
4: 4 b BS 14 b
5: 4 b 6 46 a
6: 4 b 9 64 b
7: 4 b 9 71 a
8: 4 b 12 85 b
9: 9 b BS 14 a
10: 9 b 4 28 b
11: 9 b 6 51 a
12: 9 b 9 66 b
13: 9 b 12 84 NA
14: 10 NA BS 0 NA
只是对我在这里做的简短说明:我先排序dfL
,然后为每个ID(by=ID
)获取letter
的最后一个值(已完成使用函数tail
)。之后,我必须再次合并两个data.tables。
更容易(感谢Luciano的评论):
dfL[!is.na(letter), lastL := tail(as.character(letter), 1), by=ID]
ID week outcome letter lastL
1: 1 BS 14 a a
2: 1 4 28 b a
3: 1 6 42 a a
4: 4 BS 14 b b
5: 4 6 46 a b
6: 4 9 64 b b
7: 4 9 71 a b
8: 4 12 85 b b
9: 9 BS 14 a b
10: 9 4 28 b b
11: 9 6 51 a b
12: 9 9 66 b b
13: 9 12 84 NA NA
14: 10 BS 0 NA NA
这一切都是一步完成的。但是,只有将列letter
转换为字符时才能使用此功能。
答案 2 :(得分:2)
这是一种使用plyr的方法:首先省略NA,按id拆分并查看最后一个值。然后合并回来。
library(plyr)
last_letter <- ddply(na.omit(dfL), .(ID), function(x) tail(as.character(x$letter),1))
last_letter$week <- "BS"
names(last_letter)[2] <- "last_letter"
merge(dfL, last_letter, by = c("ID", "week"), all=TRUE)
ID week outcome letter last_letter
1 1 4 28 b <NA>
2 1 6 42 a <NA>
3 1 BS 14 a a
4 4 12 85 b <NA>
5 4 6 46 a <NA>
6 4 9 64 b <NA>
7 4 9 71 a <NA>
8 4 BS 14 b b
9 9 12 84 <NA> <NA>
10 9 4 28 b <NA>
11 9 6 51 a <NA>
12 9 9 66 b <NA>
13 9 BS 14 a b
14 10 BS 0 <NA> <NA>