在R中,如何在单独的变量中为每个重复创建连续的ID号?

时间:2013-03-07 19:53:05

标签: r dataframe

我对R和编程很新。我刚刚开始学习如何使用for循环,但我无法弄清楚如何获取我想要打印的变量作为我的数据帧的一部分。

我的数据看起来像这样:

Place  Sex  Length
A      M    32
A      M    33
A      F    35
A      F    35
A      F    35
A      F    39
B      M    30
B      F    25
B      F    28
B      F    28

我想在我的数据框中创建第四个变量,它为每行数据提供一个特定于其Place/Sex/Length组合的唯一标识符,以便我的数据看起来像这样,因此每个人都有一个唯一的{{ 1}}仅适用于该行数据的组合:

Place/Sex/Length/ID

提前感谢您的任何建议。我一直在寻找一些帮助,如何做到这一点,没有运气。

3 个答案:

答案 0 :(得分:4)

一种(多种)方法是在基础R中使用ave,如下所示(假设data.frame名为“temp”)

within(temp, {
  ID <- ave(as.character(interaction(temp)), 
            interaction(temp), FUN = seq_along)
})
#    Place Sex Length ID
# 1      A   M     32  1
# 2      A   M     33  1
# 3      A   F     35  1
# 4      A   F     35  2
# 5      A   F     35  3
# 6      A   F     39  1
# 7      B   M     30  1
# 8      B   F     25  1
# 9      B   F     28  1
# 10     B   F     28  2

尝试运行interaction(temp)以了解它正在做什么。

答案 1 :(得分:3)

另一种方式:

# assuming the data.frame is already sorted by 
# all three columns (unfortunately, this is a requirement)
> sequence(rle(do.call(paste, df))$lengths)
# [1] 1 1 1 2 3 1 1 1 1 2

分解:

do.call(paste, df) # pastes each row of df together with default separator "space"
#  [1] "A M 32" "A M 33" "A F 35" "A F 35" "A F 35" "A F 39" "B M 30" "B F 25" "B F 28"
# [10] "B F 28"

rle(.) # gets the run length vector 
# Run Length Encoding
#   lengths: int [1:7] 1 1 3 1 1 1 2
#   values : chr [1:7] "A M 32" "A M 33" "A F 35" "A F 39" "B M 30" "B F 25" "B F 28"

$lengths # get the run-lengths (as opposed to values)
# [1] 1 1 3 1 1 1 2

sequence(.) # get 1:n for each n 
# [1] 1 1 1 2 3 1 1 1 1 2

基准:

由于有很多解决方案,我认为我会在相对较大的data.frame上对此进行基准测试。所以,结果如下(我还添加了一个解决方案data.table)。

以下是数据:

require(data.table)
require(plyr)
set.seed(45)

length <- 1e3 # number of rows in `df`
df <- data.frame(Place = sample(letters[1:20], length, replace=T), 
                 Sex = sample(c("M", "F"), length, replace=T), 
                 Length = sample(1:75, length, replace=T))
df <- df[with(df, order(Place, Sex, Length)), ]

Ananda的ave解决方案:

AVE_FUN <- function(x) {
    i <- interaction(x)
    within(x, {
        ID <- ave(as.character(i), i, FUN = seq_along)
    })
}

Arun的rle解决方案:

RLE_FUN <- function(x) {
    x <- transform(x, ID = sequence(rle(do.call(paste, df))$lengths))
}

Ben的plyr解决方案:

PLYR_FUN <- function(x) {
    ddply(x, c("Place", "Sex", "Length"), transform, ID = seq_along(Length))
}

最后,data.table解决方案:

DT_FUN <- function(x) {
    dt <- data.table(x)
    dt[, ID := seq_along(.I), by=names(dt)]
}

基准代码:

require(rbenchmark)
benchmark(d1 <- AVE_FUN(df), 
          d2 <- RLE_FUN(df), 
          d3 <- PLYR_FUN(df), 
          d4 <- DT_FUN(df), 
 replications = 5, order = "elapsed")

结果:

使用length = 1e3(data.frame df中的行数)

#                 test replications elapsed relative user.self 
# 2  d2 <- RLE_FUN(df)            5   0.013    1.000     0.013 
# 4   d4 <- DT_FUN(df)            5   0.017    1.308     0.016 
# 1  d1 <- AVE_FUN(df)            5   0.052    4.000     0.052 
# 3 d3 <- PLYR_FUN(df)            5   4.629  356.077     4.452 

使用length = 1e4

#                test replications elapsed relative user.self
# 4   d4 <- DT_FUN(df)            5   0.033    1.000     0.031
# 2  d2 <- RLE_FUN(df)            5   0.089    2.697     0.088
# 1  d1 <- AVE_FUN(df)            5   0.102    3.091     0.100
# 3 d3 <- PLYR_FUN(df)            5  23.103  700.091    20.659

使用length = 1e5

#                test replications elapsed relative user.self
# 4   d4 <- DT_FUN(df)            5   0.179    1.000     0.130
# 1  d1 <- AVE_FUN(df)            5   1.001    5.592     0.940
# 2  d2 <- RLE_FUN(df)            5   1.098    6.134     1.011
# 3 d3 <- PLYR_FUN(df)            5 219.861 1228.274   147.545

观察:我注意到的趋势是,随着越来越大的数据,data.table(毫不奇怪)做得最好(尺度非常好),而averle非常接近第二名的竞争者(averle更好)。不幸的是,plyr在所有数据集上表现非常差。

注意:Ananda的解决方案提供character输出,我在基准测试中保留了它。

答案 2 :(得分:3)

不可避免的plyr解决方案。

获取数据:

temp <- read.table(text="
Place  Sex  Length
A      M    32
A      M    33
A      F    35
A      F    35
A      F    35
A      F    39
B      M    30
B      F    25
B      F    28
B      F    28",
header=TRUE)

加载包并执行:

library("plyr")
ddply(temp,c("Place","Sex","Length"),transform,ID=seq_along(Length))

订单已更改(如果需要,可以使用arrange()重新排序),但变量应该是正确的:

##        Place Sex Length ID
## 1      A   F     35  1
## 2      A   F     35  2
## 3      A   F     35  3
## 4      A   F     39  1
## 5      A   M     32  1
## 6      A   M     33  1
## 7      B   F     25  1
## 8      B   F     28  1
## 9      B   F     28  2
## 10     B   M     30  1