2013-03-07 42 views
1

我對R和編程一般都很陌生。我剛開始學習如何使用for循環,但我無法弄清楚如何獲取我想要作爲數據框一部分打印的變量。在R中,如何爲單獨變量中的每個重複創建連續的ID號?

我看起來像這樣的數據:

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

一(許多)方法是在基礎R使用ave,如下(假設data.frame名爲「臨時」)

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)來獲得它在做什麼的想法。

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) 
    }) 
} 

Arun的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(編號在數據行。幀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的輸出結果,我將它保留在基準測試中。

+1

不包括在函數中創建data.table。 'dt [,ID:= seq_len(.N),by = names(DT)]'也可能更快 – mnel 2013-03-07 22:48:40

+0

@mnel,我記得MatthewDowle提到類似於包含',key(。)' (http://stackoverflow.com/questions/15182888/complicated-reshaping)。我認爲它應該包括根據對裏卡多基準的評論創建data.table。 – Arun 2013-03-07 22:55:49

+0

如果你想利用排序和加速從設置密鑰的優勢,然後包括setkey(),但你不在這種情況下,所以我認爲這是不公平的開銷(而不是公平的開銷,如果你設置密鑰) – mnel 2013-03-07 22:59:18

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 
+0

只是基於相對較大的data.frames和'plyr'的基準測試表現得相當糟糕,請檢查我的帖子以獲得結果。 – Arun 2013-03-07 21:40:01

+2

基準測試很棒 - 但它也並不令人驚訝。 AIUI)爲​​概念上的簡單性和便利性,並不一定是原始速度,與許多SO用戶羣不同,我沒有生活在大數據世界 - 我可以用5秒鐘生存1000行數據幀......但'data.table'和base-R解決方案當然值得考慮,如果有人需要速度...... – 2013-03-07 22:22:22

相關問題