2015-04-07 10 views
8

Ho una semplice domanda su aggregando valori in R.combinando valori nelle righe in base a condizioni corrispondenti a R

Supponiamo di avere un dataframe:

DF <- data.frame(col1=c("Type 1", "Type 1B", "Type 2"), col2=c(1, 2, 3)) 

che assomiglia a questo:

 col1 col2 
1 Type 1 1 
2 Type 1B 2 
3 Type 2 3 

Ho notato che ho Type 1 e Type 1B nei dati, quindi mi piacerebbe combinare Type 1B in Type 1.

così decido di usare dplyr:

filter(DF, col1=='Type 1' | col1=='Type 1B') %>% 
    summarise(n = sum(col2)) 

Ma ora ho bisogno di andare avanti con esso:

DF2 <- data.frame('Type 1', filter(DF, col1=='Type 1' | col1=='Type 1B') %>% 
    summarise(n = sum(col2))) 

Credo che voglio cbind questo nuovo DF2 nuovo all'originale DF, ma ciò significa che devo impostare i nomi delle colonne per essere coerenti:

names(DF2) <- c('col1', 'col2') 

OK , ora posso rbind:

rbind(DF2, DF[3,]) 

Il risultato? Ha funzionato ....

col1 col2 
1 Type 1 3 
3 Type 2 3 

... ma ugh! E 'stato terribile! Deve esserci un modo migliore per combinare semplicemente i valori.

risposta

2

Si può provare:

library(data.table) 

setDT(transform(DF, col1=gsub("(.*)[A-Z]+$","\\1",DF$col1)))[,list(col2=sum(col2)),col1] 

#  col1 col2 
# 1: Type 1 3 
# 2: Type 2 3 

O ancora più diretto:

setDT(DF)[, .(col2 = sum(col2)), by = .(col1 = sub("[[:alpha:]]+$", "", col1))] 
+0

Ci deve essere un modo più generalizzabile per fare qualcosa di così semplice, no? Sicuramente un'operazione così semplice non dovrebbe includere la corrispondenza del tipo regex !! –

+0

In una riga ora. Ma avrai bisogno di 'gsub' o troverai un altro pattern per riconoscere che' type 1' e 'type1B' sono simili. L'aggregazione può essere eseguita con 'aggregate',' dplyr', 'data.table', ecc. –

4

Ecco un possibile approccio dplyr:

library(dplyr) 
DF %>% 
    group_by(col1 = sub("(.*\\d+).*$", "\\1", col1)) %>% 
    summarise(col2 = sum(col2)) 
#Source: local data frame [2 x 2] 
# 
# col1 col2 
#1 Type 1 3 
#2 Type 2 3 
4

Utilizzando sub() con aggregate(), removin g altro che una cifra da fine col1,

do.call("data.frame", 
    aggregate(col2 ~ cbind(col1 = sub("\\D+$", "", col1)), DF, sum) 
) 
#  col1 col2 
# 1 Type 1 3 
# 2 Type 2 3 

Il do.call() avvolgitore c'è così che la prima colonna dopo aggregate() correttamente cambiato da una matrice per un vettore. In questo modo non ci sono sorprese più avanti lungo la strada.

1

A mio parere, aggregate() è la funzione perfetta per questo scopo, ma non è necessario eseguire alcuna elaborazione di testo (ad esempio gsub()). Voglio fare questo in un processo in due fasi:

  1. sovrascrivere col1 con il nuovo raggruppamento desiderato.
  2. Calcolare l'aggregazione utilizzando il nuovo col1 per specificare il raggruppamento.

DF$col1 <- ifelse(DF$col1 %in% c('Type 1','Type 1B'),'Type 1',levels(DF$col1)); 
DF; 
##  col1 col2 
## 1 Type 1 1 
## 2 Type 1 2 
## 3 Type 2 3 
DF <- aggregate(col2~col1, DF, FUN=sum); 
DF; 
##  col1 col2 
## 1 Type 1 3 
## 2 Type 2 3 
+0

Penso che questa sia la migliore risposta dal momento che evita di mescolarsi al testo. Mantiene la complessità bassa. –

Problemi correlati