1

我对 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组合的唯一标识符,以便我的数据看起来像这样,因此每个人都有一个Place/Sex/Length/ID特定于该数据行的唯一组合:

Place  Sex  Length Ind
A      M    32     1
A      M    33     1
A      F    35     1
A      F    35     2
A      F    35     3
A      F    39     1
B      M    30     1
B      F    25     1
B      F    28     1
B      F    28     2

提前感谢您的任何建议。我一直在寻找有关如何在没有运气的情况下执行此操作的帮助。

4

3 回答 3

4

一种(多种)方法是ave在基础 R 中使用,如下所示(假设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)以了解它在做什么。

于 2013-03-07T19:57:22.797 回答
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)), ]

阿难的ave解决方法:

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

阿伦的rle解决方案:

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

本的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第二名的竞争者非常接近(ave规模好于rle)。plyr不幸的是,在所有数据集上的表现都很糟糕。

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

于 2013-03-07T20:54:28.663 回答
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
于 2013-03-07T21:00:05.503 回答