2015-12-24 24 views
6

Mi stavo chiedendo se qualcuno avesse un bel modo per raggiungere questo obiettivo. Ho una struttura dati in cui ogni osservazione (= item), appartenenti ad un determinato gruppo (= condizione) ha un dato valore:Come utilizzare una tabella di ricerca in R senza creare duplicati?

# Create sample data. 
item  = rep(1:3,2)        #6 items 
condition = c(rep("control",3), rep("related",3)) #2 conditions 
value  = c(10,11,12,20,21,22)      #6 values   
df   = data.frame(item, condition, value) 

    item condition value 
1 1 control 10 
2 2 control 11 
3 3 control 12 
4 1 related 20 
5 2 related 21 
6 3 related 22 

ho anche una tabella di look-up, che contiene la media di ciascun gruppo :

# Create lookup table. 
condition = c("control", "related") 
mean  = c(11,21) 
table  = data.frame(condition, mean) 

    condition mean 
1 control 11 
2 related 21 

voglio modificare il mio frame di dati originali, in modo tale che essa contiene una nuova colonna, label, che dice "bassa" se il valore della voce è inferiore alla media di gruppo, e "alto "altrimenti. Esso dovrebbe essere così:

# How the output should look like. 
# If the item value is less than the group mean, write "low". Write "high" otherwise. 
item  = rep(1:3,2)        
condition = c(rep("control",3), rep("related",3))  
value  = c(10,11,12,20,21,22)      
label  = c(rep(c("low", "high", "high"),2)) 
output  = data.frame(item, condition, value, label) 

    item condition value label 
1 1 control 10 low 
2 2 control 11 high 
3 3 control 12 high 
4 1 related 20 low 
5 2 related 21 high 
6 3 related 22 high 

Se questa fosse una questione di semplice copia del gruppo significa il mio telaio dati originali, userei merge. Ma ciò di cui ho bisogno è prendere in considerazione il significato del gruppo per scrivere una nuova etichetta per ogni articolo che dice "basso" o "alto" a seconda della media del gruppo.

Una cosa che ho provato era di unire prima il mio telaio di dati con la tavola, e quindi utilizzare ifelse per confrontare la colonna valore con il significare colonna. Funziona, ma alla fine mi ritrovo con una colonna media nella mia cornice dati, che non mi serve (ho solo bisogno della colonna etichetta ). Naturalmente, potrei cancellare la colonna media a a mano, ma sembra goffo. Quindi mi stavo chiedendo: qualcuno conosce una soluzione migliore/più elegante?

Grazie mille!

+0

Se il gruppo media è 11, qualora il Contro l il valore della condizione 11 è "alto"? E i legami? – Minnow

+0

se il valore è uguale o superiore alla media del gruppo, l'etichetta dovrebbe essere "alta". Ma se vuoi qualcosa di diverso, puoi cambiare "<" con "<=". – Sol

risposta

11

Ecco alcune alternative. (1) e (2) utilizzare solo base R e (2), (3) e (5) non creare una colonna media solo per essere cancellati in modo esplicito. In (1), (3) e (4) abbiamo usato i join di sinistra anche se i join interni avrebbero dato lo stesso risultato con questi dati e nel caso di (1a) ci permettono di scrivere (1) come una singola riga.

1) fondono

m <- merge(df, table, all.x = TRUE) 
transform(m, label = ifelse(value < mean, "low", "high"), mean = NULL) 

dando:

item condition value label 
1 1 control 10 low 
2 2 control 11 high 
3 3 control 12 high 
4 1 related 20 low 
5 2 related 21 high 
6 3 related 22 high 

1a) Con un inner join potrebbe essere ridotto a:

transform(merge(df, table), label = ifelse(value < mean, "low", "high"), mean = NULL) 

2) partita

transform(df, 
    label = ifelse(value < table$mean[match(condition, table$condition)], "low", "high") 
) 

dare lo stesso.

3) sqldf

library(sqldf) 
sqldf("select 
     df.*, 
     case when value < mean 
       then 'low' 
       else 'high' 
       end label 
     from df 
     left join 'table' using (condition)") 

4) dplyr

library(dplyr) 
df %>% 
    left_join(table) %>% 
    mutate(label = ifelse(value < mean, "low", "high")) %>% 
    select(- mean) 

5) data.table

library(data.table) 
dt <- as.data.table(df) 
setkey(dt, "condition") 
dt[table, label := ifelse(value < mean, "low", "high")] 
+1

wow, questo è veramente accurato, grazie! E queste soluzioni sono molto meglio di quello che stavo facendo: sono contento di averlo chiesto! C'è un errore di battitura nella soluzione 2 (un preventivo mancante in "basso", ma non riesco a risolverlo perché la modifica è inferiore a 6 caratteri. – Sol

+0

Hai risolto errori di battitura. –