2012-10-25 39 views
7

我的問題是:我有一個數據框與一些因子變量。我現在想要爲這個數據框分配一個新的向量,爲這些因子變量的每個子集創建一個索引。如何將計數器分配給由因子組合定義的data.frame的特定子集?

data <-data.frame(fac1=factor(rep(1:2,5)), fac2=sample(letters[1:3],10,rep=T)) 

給了我這樣的:

 fac1 fac2 
    1  1 a 
    2  2 c 
    3  1 b 
    4  2 a 
    5  1 c 
    6  2 b 
    7  1 a 
    8  2 a 
    9  1 b 
    10 2 c 

而我想的是,其對各因素的組合發生的組合計數器。像這樣

 fac1 fac2 counter 
    1  1 a  1 
    2  2 c  1 
    3  1 b  1 
    4  2 a  1 
    5  1 c  1 
    6  2 b  1 
    7  1 a  2 
    8  2 a  2 
    9  1 b  2 
    10 1 a  3 

到目前爲止,我想過使用tapply拿到過所有因素組合的計數器,它工作正常

counter <-tapply(data$fac1, list(data$fac1,data$fac2), function(x) 1:length(x)) 

但我不知道我怎麼可以指定櫃檯列表(例如未列出)到數據幀中的組合,而不使用低效的循環:)

+0

是否需要在訂單或你只是想淨計數?如果你只是想計數,表格(粘貼(數據$ fac1,數據$ fac2,sep =「 - 」))可能會有所幫助。 – screechOwl

+0

嗨!在每個fac1×fac2組合中,順序很重要。 (人們可以把它看作一個人「fac1」看到字母「fac2」的次數) – JBJ

+0

你可以使用相同的基本策略,但是從** plyr **開始從'tapply'切換到'ddply',或者如果你的數據是巨大的,性能是一個問題,'data.table'。 – joran

回答

6

這是ave()功能的工作:

# Use set.seed for reproducible examples 
# when random number generation is involved 
set.seed(1) 
myDF <- data.frame(fac1 = factor(rep(1:2, 7)), 
        fac2 = sample(letters[1:3], 14, replace = TRUE), 
        stringsAsFactors=FALSE) 
myDF$counter <- ave(myDF$fac2, myDF$fac1, myDF$fac2, FUN = seq_along) 
myDF 
# fac1 fac2 counter 
# 1  1 a  1 
# 2  2 b  1 
# 3  1 b  1 
# 4  2 c  1 
# 5  1 a  2 
# 6  2 c  2 
# 7  1 c  1 
# 8  2 b  2 
# 9  1 b  2 
# 10 2 a  1 
# 11 1 a  3 
# 12 2 a  2 
# 13 1 c  2 
# 14 2 b  3 

注意在data.frame()步驟中使用的stringsAsFactors=FALSE。如果你沒有這個,你仍然可以得到輸出:myDF$counter <- ave(as.character(myDF$fac2), myDF$fac1, myDF$fac2, FUN = seq_along)

+0

它當然是+ 1 –

+0

很好的回答! +1 –

+0

根據效率比較mrdwab和我的解決方案(不能讓@mplourde工作),而mrdwab速度提高一倍。對於1000000行,它是1.693與3.382秒 – vaettchen

0

這是避免(顯式)循環的基本R方式。

data$counter <- with(data, { 
    inter <- as.character(interaction(fac1, fac2)) 
    names(inter) <- seq_along(inter) 
    inter.ordered <- inter[order(inter)] 
    counter <- with(rle(inter.ordered), unlist(sapply(lengths, sequence))) 
    counter[match(names(inter), names(inter.ordered))] 
}) 
0

這裏有一個小循環變體(因爲「數據」我已重新命名變量「X」是被以其它方式使用):

x <-data.frame(fac1=rep(1:2,5), fac2=sample(letters[1:3],10,rep=T)) 
x$fac3 <- paste(x$fac1, x$fac2, sep="") 
x$ctr <- 1 
y <- table(x$fac3) 
for(i in 1 : length(rownames(y))) 
    x$ctr[x$fac3 == rownames(y)[i]] <- 1:length(x$ctr[x$fac3 == rownames(y)[i]]) 
x <- x[-3] 

不知道這是否是在大data.frame高效但它的作品!

4

一個data.table解決

library(data.table) 
DT <- data.table(data) 
DT[, counter := seq_len(.N), by = list(fac1, fac2)] 
相關問題