2012-05-23 13 views
5

Per un data.table (o data.frame) in R, desidero trovare tutte le righe che contengono un valore nella colonna "valore" che sono una distanza determinata distanza 'da un altro valore in fila con la stessa chiave. Quindi, data la seguente:Trova le righe con una determinata differenza tra i valori in una colonna

distance <- 22 
    key value 
    A  1 
    B  1 
    C  1 
    D  1 
    A  4 
    B  4 
    A 23 
    B 23 
    B 26 
    B 26 
    C 30 

Vorrei annotata la tabella originale con un conteggio di quante righe esistere con la stessa chiave, e un valore che è 22 da esso:

key value count 
    A  1  1 
    B  1  1 
    C  1  0 
    D  1  0 
    A  4  0 
    B  4  2 
    A 23  0 
    B 23  0 
    B 26  0 
    B 26  0 
    C 30  0 

Non so davvero da dove cominciare questo approccio autoreferenziale alla manipolazione dei dati in R. I miei tentativi iniziali consistevano nel creare un secondo tavolo e cercare di combatterlo, ma mi sembrava un approccio strano e povero.

Nota: sto utilizzando il pacchetto data.table ma sono felice di lavorare su data.frame in questo caso, se ciò rende le cose più semplici.

riproducibile:

require(data.table) 
source <- data.table(data.frame(key=c("A","B","C","D","A","B","A","B","B","B", "C"),value=c(1,1,1,1,4,4,23,23,26,26,30))) 
result <- data.table(data.frame(key=c("A","B","C","D","A","B","A","B","B","B","C"),value=c(1,1,1,1,4,4,23,23,26,26,30),count=c(1,1,0,0,0,2,0,0,0,0,0))) 

risposta

5

Ecco una soluzione basata data.table. Sarò interessato a sapere quali (eventuali) miglioramenti possono essere apportati ad esso.

# Your code 
library(data.table) 
source <- 
data.table(data.frame(key = c("A","B","C","D","A","B","A","B","B","B", "C"), 
         value = c(1,1,1,1,4,4,23,23,26,26,30))) 

Quella strana data.table(data.frame(... è perché data.table() ha un argomento chiamato key, anche. Questo è un modo per creare un data.table con una colonna chiamata "key". Capitalizzando al fine di evitare il conflitto di nomi argomento illustra la sintassi più standard:

source <- data.table(Key = c("A","B","C","D","A","B","A","B","B","B","C"), 
        Value = c(1,1,1,1,4,4,23,23,26,26,30)) 

Avanti per evitare di dover as.integer() tardi, cambieremo il tipo della colonna Valuenumeric-integer ora. Ricorda che 1 è numeric in R, è 1L ovvero integer. Di solito è meglio per l'efficienza memorizzare i dati integer come integer, rispetto a integer come numeric. La riga successiva è più facile che digitare un sacco di L s sopra.

source[,Value:=as.integer(Value)] # change type from `numeric` to `integer` 

Ora procediamo

distance <- 22L 
setkey(source, Key, Value) 

# Heart of the solution (following a few explanatory comments): 
# "J()" : shorthand for 'data.table()' 
# ".N" : returns the number of rows that matched a line (see ?data.table) 
# "[[3]]" : as with simple data.frames, extracts the vector in column 3 

source[,count:=source[J(Key,Value+distance),.N][[3]]] 
source 
     key value count 
[1,] A  1  1 
[2,] A  4  0 
[3,] A 23  0 
[4,] B  1  1 
[5,] B  4  2 
[6,] B 23  0 
[7,] B 26  0 
[8,] B 26  0 
[9,] C  1  0 
[10,] C 30  0 
[11,] D  1  0 

Nota che := cambiato source facendo riferimento direttamente, in modo che è tutto. Ma setkey() ha anche cambiato l'ordine dei dati originali. Se è necessario mantenere l'ordine originale, allora:

source <- data.table(Key = c("A","B","C","D","A","B","A","B","B","B","C"), 
        Value = c(1,1,1,1,4,4,23,23,26,26,30)) 
source[,Value:=as.integer(Value)] 
source[,count:=setkey(copy(source))[source[,list(Key,Value+distance)],.N][[3]]] 

     Key Value count 
[1,] A  1  1 
[2,] B  1  1 
[3,] C  1  0 
[4,] D  1  0 
[5,] A  4  0 
[6,] B  4  2 
[7,] A 23  0 
[8,] B 23  0 
[9,] B 26  0 
[10,] B 26  0 
[11,] C 30  0 
+0

Grazie, puoi spiegare la linea che assegna il risultato $ count? Qual è il. N per, e il [[3]]? – Ina

+3

Sicuro. Ho appena aggiunto alcuni commenti nel codice, che iniziano a decomprimere i dati.sintassi compatta di table call. –

+1

Molto bello, grazie! – Ina

1

Si potrebbe utilizzare mapply a ciclo attraverso tutte le combinazioni di valore di chiave e:

data.table(t(mapply(function(key,val) 
     c(key=key,value=val,count=length(source$value[source$key==key & source$value>(val+distance)])) 
    , as.character(source$key),source$value))) 
+0

Ciò sembra produrre i risultati errati, ottengo un conteggio di 2 nella seconda riga e un conteggio di 1 nella terza fila con questa formula. Penso di capire cosa sta facendo, ma non riesco a vedere un errore di battitura ovvio che renderebbe questo un semplice errore. Inoltre, idealmente la risposta non sarebbe n^2 in complessità, ma potrebbe non essere possibile. – Ina

Problemi correlati