2016-05-12 3 views
0

私は大きなデータセットを処理しています。ここでは、データセットの例である:Rのデータフレームで値の出現をカウントするためのループのネストされた

id = rep(replicate(4, paste(sample(LETTERS, 3, replace=F), collapse="")), 12500) 
names = rep(replicate(3125, paste(sample(letters, 5, replace=T), collapse="")), 16) 
times = sample(c(3,6,24), 50000, replace = T) 

df = data.frame(id=id, names=names, times=times) 

count <- list() 
ids <- as.vector(unique(df$id)) 
nms <- as.vector(unique(df$names)) 

for(i in 1:length(ids)){ 
    vec <- c() 
    for(j in 1:length(nms)){ 
    vec[j] <- nrow(df[df$id == ids[i] & df$names == nms[j], ]) 
    } 
    count[[i]] <- vec 
} 

私の実際のデータを約50000 x 10寸法を有するとidとnameフィールドがランダムに分散されています。誰もこれを処理するより良い方法を提案することはできますか?私のアプローチはうまくいくものの、遅すぎるからです。 dplyrまたはplyrの方法はありますか?

おかげで、

EDIT:私のデータフレームの

ショートバージョン:

id = rep(replicate(3, paste(sample(LETTERS, 3, replace=F), collapse="")), 5) 
names = rep(replicate(3, paste(sample(letters, 5, replace=T), collapse="")), 5) 
times = sample(c(3,6,24), 15, replace = T) 

df = data.frame(id=id, names=names, times=times) 
df 
    id names times 
1 DEW xxsre 24 
2 QHY xkbhr 24 
3 DQE tuyfk  6 
4 DEW xxsre 24 
5 QHY xkbhr 24 
6 DQE tuyfk  3 
7 DEW xxsre  3 
8 QHY xkbhr 24 
9 DQE tuyfk  3 
10 DEW xxsre 24 
11 QHY xkbhr 24 
12 DQE tuyfk  3 
13 DEW xxsre 24 
14 QHY xkbhr  3 
15 DQE tuyfk  3 

出力:

> count 
[[1]] 
[1] 5 0 0 

[[2]] 
[1] 0 5 0 

[[3]] 
[1] 0 0 5 

各リスト項目は、IDのためである、とリストvecは名前の数です。換言すればas.vector(unique(df$id))およびas.vector(unique(df$names))である。

+1

Iドン'id'、' names'、 'times'カラムがどのように等しくなるかを見ています。 _original_データフレームはどこで定義しますか? –

+0

OPが作成したいと思っていたカラムが 'times 'だと思って、期待通りの出力としてサンプルに含めました。(?)...分かりません... – Sotos

+0

小さいサイズで走ろうとしました'df'(500行)ですが、結果のカウントはちょうど4のリストであり、それぞれ125個のものから成っています。 – zyurnaidi

答えて

1

これは必要な操作ですか?

library(dplyr) 
count <- df %>% 
    group_by(id, names) %>% 
    summarise(n=sum(times)) 
count 
+0

' summarize(n = sum(times)) 'を'集計する(n = n()) 'を数えます。しかし、リストではない – Adrian

0

plyrとdplyrを使用しないと、計算時間を25%削減できます。

計算時間が合理的であるため、私はデータの最初の1000行をサブセット化しました。マイクロベンチマークショーで

library(microbenchmark) 
id = rep(replicate(4, paste(sample(LETTERS, 3, replace=F), collapse="")), 12500) 
names = rep(replicate(3125, paste(sample(letters, 5, replace=T), collapse="")), 16) 
times = sample(c(3,6,24), 50000, replace = T) 

df = data.frame(id=id, names=names, times=times) 
df = df[1:1000,] 
ids <- as.vector(unique(df$id)) 
nms <- as.vector(unique(df$names)) 

は、その後、私は3つの機能を定義し、デフォルト、和、和+事前割り当て

default<-function(ids,nms,df){ 
    count <- list() 

    for(i in 1:length(ids)){ 
    vec <- c() 
    for(j in 1:length(nms)){ 
     vec[j] <- nrow(df[df$id == ids[i] & df$names == nms[j], ]) 
    } 
    count[[i]] <- vec 
    } 
} 

summation<-function(ids,nms,df){ 
    count <- list() 

    for(i in 1:length(ids)){ 
    vec <- c() 
    for(j in 1:length(nms)){ 
     vec[j] <- sum(df$id == ids[i] & df$names == nms[j]) 
    } 
    count[[i]] <- vec 
    } 
} 

summation_and_preallocation<-function(ids,nms,df){ 
    count <- list() 

    for(i in 1:length(ids)){ 
    vec <- integer(length = length(nms)) 
    for(j in 1:length(nms)){ 
     vec[j] <- sum(df$id == ids[i] & df$names == nms[j]) 
    } 
    count[[i]] <- vec 
    } 
} 

テスト:

m<-microbenchmark(default(ids,nms,df),summation(ids,nms,df),summation_and_preallocation(ids,nms,df),times = 10) 
Unit: milliseconds 
             expr  min  lq  mean median  uq  max neval 
        default(ids, nms, df) 994.5040 1012.1560 1040.7012 1042.5689 1072.4689 1074.8893 10 
        summation(ids, nms, df) 735.0831 740.6620 741.2254 742.1361 742.9321 743.7806 10 
summation_and_preallocation(ids, nms, df) 729.1192 733.0536 753.8661 736.8319 791.5001 804.2335 10 

はどのようにそれが@Adrianからdplyrソリューションと比較ん?

dplyr_count(ids, nms, df) 3.154741 3.206819 49.06034 3.275624 3.701375 457.943 10 

dplyrの約200倍速いです!

2

あなたはおそらく最速のソリューションである、data.tableを使用することができます:あなたは出力がlistになりたい場合は、さまざまな方法で出力を変換することができ

library(data.table) 


# convert your dataset into a data.table 
    setDT(df) 


output <- df [ , .N, by = .(id, names)] 


head(output) 
>  id names N 
> 1: FYG vlrcd 4 
> 2: FAL mjhhs 4 
> 3: BZU rfnvc 4 
> 4: HJA zhssf 4 
> 5: FYG pxtne 4 
> 6: FAL qgeqr 4 

L1 <- as.list(as.data.frame(t(output))) # or 

L2 <- split(output, list(output$id, output$names)) # or 

L3 <- split(output, seq(nrow(output))) 
+0

これは私の出力と同じではないので、私は投稿しなかったコメントで私の答えと同じです...私はそれが受け入れ可能な場合は、OPから聞くことを期待していた.. – Sotos

+0

@Sotos、私の謝罪、私はあなたのコメントを見ていない。あなたの答えを投稿してください。 –

+1

それは問題ありません。それが終わってから私たちはあなたのことを残すことができます:) – Sotos

関連する問題