2013-01-23 111 views
4

我有一個150000行長格式的數據框,其中有多個相同的id變量。我正在使用reshape(來自stat,而不是package = reshape(2))將其轉換爲寬格式。我正在生成一個變量來計算每個id的給定級別的出現以用作索引。枚舉因子級別的實例

我已經有了一個使用plyr的小型數據框的工作,但對於我的完整df來說這太慢了。我可以更有效地編程嗎?

我一直在努力做到這一點與重塑包,因爲我有大約30個其他變量。對於每個單獨的分析,最好只重塑我正在查看的內容(而不是整個DF)。

> # u=id variable with three value variables 
> u<-c(rep("a",4), rep("b", 3),rep("c", 6), rep("d", 5)) 
> u<-factor(u) 
> v<-1:18 
> w<-20:37 
> x<-40:57 
> df<-data.frame(u,v,w,x) 
> df 
    u v w x 
1 a 1 20 40 
2 a 2 21 41 
3 a 3 22 42 
4 a 4 23 43 
5 b 5 24 44 
6 b 6 25 45 
7 b 7 26 46 
8 c 8 27 47 
9 c 9 28 48 
10 c 10 29 49 
11 c 11 30 50 
12 c 12 31 51 
13 c 13 32 52 
14 d 14 33 53 
15 d 15 34 54 
16 d 16 35 55 
17 d 17 36 56 
18 d 18 37 57 
> 
> library(plyr) 
> df2<-ddply(df, .(u), transform, count=rank(u, ties.method="first")) 
> df2 
    u v w x count 
1 a 1 20 40  1 
2 a 2 21 41  2 
3 a 3 22 42  3 
4 a 4 23 43  4 
5 b 5 24 44  1 
6 b 6 25 45  2 
7 b 7 26 46  3 
8 c 8 27 47  1 
9 c 9 28 48  2 
10 c 10 29 49  3 
11 c 11 30 50  4 
12 c 12 31 51  5 
13 c 13 32 52  6 
14 d 14 33 53  1 
15 d 15 34 54  2 
16 d 16 35 55  3 
17 d 17 36 56  4 
18 d 18 37 57  5 
> reshape(df2, idvar="u", timevar="count", direction="wide") 
    u v.1 w.1 x.1 v.2 w.2 x.2 v.3 w.3 x.3 v.4 w.4 x.4 v.5 w.5 x.5 v.6 w.6 x.6 
1 a 1 20 40 2 21 41 3 22 42 4 23 43 NA NA NA NA NA NA 
5 b 5 24 44 6 25 45 7 26 46 NA NA NA NA NA NA NA NA NA 
8 c 8 27 47 9 28 48 10 29 49 11 30 50 12 31 51 13 32 52 
14 d 14 33 53 15 34 54 16 35 55 17 36 56 18 37 57 NA NA NA 
+2

在您的示例中,列名和因子都是'a','b','c'和'd' - 如果它們具有不同的名稱,可能會使示例更容易遵循 – user295691

+0

@ user295691 - 好點子。已改名。 – Ewen

+1

只是爲了澄清 - 你的實際問題是......「有沒有更快的方式來做重塑步驟?」爲了加快創建變量計數(在我的測試中,速度提高20到30倍),可以使用'ave()':'df2 < - (df,ave(as.numeric(u), u,FUN = seq_along) })'。除此之外,可能會有多少實際的「u」水平?寬格式數據集將如何幫助您?我想可以想象,有超過150萬的專欄,瀏覽它將是一場噩夢!如果你能澄清你的最終目標和目的,你可能會得到更多有用的答案。 – A5C1D2H2I1M1N2O1R2T1

回答

2

我還是不太明白,爲什麼你想最終從廣泛的轉換數據集長,因爲對我來說,這似乎是這將是一個非常笨拙的數據集的工作。

如果您希望加快枚舉因子水平,可以考慮在基數R中使用ave(),或從「data.table」包中使用.N。考慮到您正在處理很多行,您可能需要考慮後者。

首先,讓我們做了一些數據:

set.seed(1) 
df <- data.frame(u = sample(letters[1:6], 150000, replace = TRUE), 
       v = runif(150000, 0, 10), 
       w = runif(150000, 0, 100), 
       x = runif(150000, 0, 1000)) 
list(head(df), tail(df)) 
# [[1]] 
# u  v  w  x 
# 1 b 6.368412 10.52822 223.6556 
# 2 c 6.579344 75.28534 450.7643 
# 3 d 6.573822 36.87630 283.3083 
# 4 f 9.711164 66.99525 681.0157 
# 5 b 5.337487 54.30291 137.0383 
# 6 f 9.587560 44.81581 831.4087 
# 
# [[2]] 
#  u  v  w  x 
# 149995 b 4.614894 52.77121 509.0054 
# 149996 f 5.104273 87.43799 391.6819 
# 149997 f 2.425936 60.06982 160.2324 
# 149998 a 1.592130 66.76113 118.4327 
# 149999 b 5.157081 36.90400 511.6446 
# 150000 a 3.565323 92.33530 252.4982 
table(df$u) 
# 
#  a  b  c  d  e  f 
# 25332 24691 24993 24975 25114 24895 

加載我們需要的軟件包:

library(plyr) 
library(data.table) 

創建我們的數據

DT <- data.table(df, key = "u") 
DT # Notice that the data are now automatically sorted 
#   u   v   w  x 
#  1: a 6.2378578 96.098294 643.2433 
#  2: a 5.0322400 46.806132 544.6883 
#  3: a 9.6289786 87.915303 334.6726 
#  4: a 4.3393403 1.994383 753.0628 
#  5: a 6.230.810359 579.7548 
#  ---        
# 149996: f 0.6268414 15.608049 669.3838 
# 149997: f 2.3588955 40.380824 658.8667 
# 149998: f 1.6383619 77.210309 250.7117 
# 149999: f 5.1042725 87.437989 391.6819 
# 150000: f 2.4259363 60.069820 160.2324 
DT[, .N, by = key(DT)] # Like "table" 
# u  N 
# 1: a 25332 
# 2: b 24691 
# 3: c 24993 
# 4: d 24975 
# 5: e 25114 
# 6: f 24895 

的 「data.table」 版本現在讓我們進行一些基本的測試。來自ave()的結果沒有排序,但它們在「data.table」和「plyr」中,所以我們還應該在使用ave()時測試排序的時間。

system.time(AVE <- within(df, { 
    count <- ave(as.numeric(u), u, FUN = seq_along) 
})) 
# user system elapsed 
# 0.024 0.000 0.027 

# Now time the sorting 
system.time(AVE2 <- AVE[order(AVE$u, AVE$count), ]) 
# user system elapsed 
# 0.264 0.000 0.262 

system.time(DDPLY <- ddply(df, .(u), transform, 
          count=rank(u, ties.method="first"))) 
# user system elapsed 
# 0.944 0.000 0.984 

system.time(DT[, count := 1:.N, by = key(DT)]) 
# user system elapsed 
# 0.008 0.000 0.004 

all(DDPLY == AVE2) 
# [1] TRUE 
all(data.frame(DT) == AVE2) 
# [1] TRUE 

「data.table」的語法肯定是緊湊的,它的速度是熾烈的!

+0

肯定是。再次感謝您這樣做,感激它。 – Ewen

1

使用base R來創建一個空矩陣然後適當地填充它通常可以明顯更快。在下面的代碼中,我懷疑緩慢的部分會將數據幀轉換爲矩陣和轉置,如前兩行;如果是這樣的話,如果它可以以不同的方式存儲起來,也許可以避免。

g <- df$a 
x <- t(as.matrix(df[,-1])) 

k <- split(seq_along(g), g) 
n <- max(sapply(k, length)) 
out <- matrix(ncol=n*nrow(x), nrow=length(k)) 
for(idx in seq_along(k)) { 
    out[idx, seq_len(length(k[[idx]])*nrow(x))] <- x[,k[[idx]]] 
} 
rownames(out) <- names(k) 
colnames(out) <- paste(rep(rownames(x), n), rep(seq_len(n), each=nrow(x)), sep=".") 
out 
# b.1 c.1 d.1 b.2 c.2 d.2 b.3 c.3 d.3 b.4 c.4 d.4 b.5 c.5 d.5 b.6 c.6 d.6 
# a 1 20 40 2 21 41 3 22 42 4 23 43 NA NA NA NA NA NA 
# b 5 24 44 6 25 45 7 26 46 NA NA NA NA NA NA NA NA NA 
# c 8 27 47 9 28 48 10 29 49 11 30 50 12 31 51 13 32 52 
# d 14 33 53 15 34 54 16 35 55 17 36 56 18 37 57 NA NA NA 
+0

謝謝@Aaron。將每個時間,看看他們如何比較。 – Ewen