识别纵向数据集中“ID”内的最后一个“字母”

时间:2013-03-27 18:30:22

标签: r

我正在尝试识别纵向数据集中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都有一串字母(ab),我需要找到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.tableave进行了调整,但我仍然有点卡住了。

3 个答案:

答案 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>