2016-05-12 3 views
0

Ich arbeite an einem großen Datensatz, ich, was zu zählen, wie viel Zeit zwei Spalten die gleichen Werte haben. Hier ist ein Beispiel des Datensatzes:Alternative verschachtelte für Schleifen zum Zählen von Wert Auftreten in R Datenrahmen

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 
} 

Meine reale Daten über 50000 x 10 Dimension und die ID und Name Felder sind zufällig verstreut. Kann jemand einen besseren Weg vorschlagen, damit umzugehen? weil mein Ansatz funktioniert, aber zu langsam. dplyr oder plyr Methoden?

Danke,

EDIT:

kurze Version meines Datenrahmen:

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 

Ausgang:

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

[[2]] 
[1] 0 5 0 

[[3]] 
[1] 0 0 5 

jedes Listenelement für id ist, und die Liste Vec ist für Namen zählen. mit anderen Worten as.vector(unique(df$id)) bzw. as.vector(unique(df$names)).

+1

I don nicht sehen, wie die Spalten "id", "names" und "times" einander immer gleich sind. Wo definierst du deinen _original_ Datenrahmen? –

+0

Ich dachte "mal" war die Spalte, die OP erstellen möchte und es einfach in das Beispiel als erwartete Ausgabe aufgenommen hat. (?) ... Weiß nicht ... – Sotos

+0

Ich habe versucht, es mit einer kleineren Größe auszuführen 'df' (500 Zeilen), aber die resultierende Anzahl ist nur eine Liste von 4, jede besteht aus 125 Einsen. – zyurnaidi

Antwort

1

Macht das, was Sie wollen?

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

replace' summieren (n = Summe (mal)) 'mit' fasse zusammen (n = n()) 'um Zählimpulse zu erhalten. Nicht eine Liste jedoch – Adrian

0

Ohne plyr und dplyr können Sie die Rechenzeit um 25% reduzieren.

Zu einer vernünftigen Rechenzeit habe ich die ersten 1000 Zeilen Ihrer Daten in Teilmengen aufgeteilt.

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

Dann definiere ich drei Funktionen, default, Summierung und sum + Vorbelegung

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

Tests mit Show-Micro:

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 

Wie funktioniert es vergleichen mit dplyr Lösung von @Adrian ?

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

Also etwa 200 mal schneller für dplyr!

2

Sie können data.table verwenden, die wahrscheinlich die schnellste Lösung ist:

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 

Wenn Sie die Ausgabe wollen ein list sein, können Sie die Ausgabe auf verschiedene Weise konvertieren:

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

Das ist das gleiche wie meine Antwort in Kommentaren, die ich nicht gepostet habe, da seine Ausgabe nicht die gleichen wie die OPs ist ... Ich hatte erwartet, von OP zu hören, wenn es akzeptabel ist, und es dann zu posten. – Sotos

+0

@Sotos, Entschuldigung, ich habe Ihren Kommentar nicht gesehen. Bitte gehen Sie weiter und posten Sie Ihre Antwort. –

+1

Das ist in Ordnung. Wir können deine verlassen, da es geht :) – Sotos

Verwandte Themen