2015-05-18 13 views
17

ho un frame di dati che contiene un/colonna identificatore seguito da diverse file di colonne di valore. voglio espandere la colonna dati prendendo coppie uniche di voci nella colonna tonalità delle nuove righe e trasformare le colonne valore usando operazioni binarie sulle voci dalle righe corrispondenti.Expand frame di dati in combinazioni di coppie di righe

E.g.

> Test_data 
     SYS dE_water_free dE_water_periodic dE_membrane_periodic RTlogKi 
1 4NTJ_D294N  -56.542   -56.642     NA -0.9629731 
2 4NTJ_wild  -171.031   -162.030     NA -0.8877264 
3 4PXZ_D294N  -53.430   -50.810     NA -1.1301124 
4 4PXZ_wild  -59.990   -57.320     NA -1.2318835 
5 4PY0_D294N  -77.040   -72.880     NA -1.1351579 
6 4PY0_wild  -79.080   -74.950     NA -1.2297302 

Alcune colonne possono o non possono contenere valori mancanti.

quello che vorrei sarebbe di prendere ogni coppia di voci, ad esempio SYS SYS1 SYS2 e calcola un'operazione binaria sulle righe del valore corrispondente E.g. SYS1 SYS2 dE_water_free (SYS == SYS1) -dE_water_free (SYS == SYS2) ... ecc

 SYS1  SYS2 dE_water_free dE_water_periodic ...etc. 
1 4NTJ_D294N 4NTJ_wild   114.489    105.610 
2 4NTJ_D294N 4PXZ_D294N   -3.112    5.832 
... etc. 

posso utilizzare la funzione combn() per ottenere un array di coppie dalla colonna SYSTEM per formare le voci SYS1 e SYS2, ma non sono sicuro di come usarlo per costruire il nuovo data frame ...

So che un'opzione potrebbe essere quella di utilizzare qualcosa come mapply e creare ogni colonna singolarmente a mano, quindi incollarli tutti in una nuova cornice di dati, ma che sembra sarà klunky e lento e ci dovrebbe essere una funzione più automatico per fare questo, come rimodellare, merge, o rifusione ... ma io non riesco a capire come fare quel lavoro .

+0

Liberamente correlato: http://stackoverflow.com/q/30237924/1191259 – Frank

+0

A proposito, se si desidera che tutte le coppie * *, come 'A, B' e' B, A' , dovresti 'expand.grid' (o' CJ' nel pacchetto 'data.table') piuttosto che' combn', penso. – Frank

risposta

10

tuo combn è stato un buon modo per andare. Prova questo:

combos<-combn(Test_data$SYS,2) 
water<-combn(Test_data$dE_water_free,2,FUN=function(x) x[1]-x[2]) 
data.frame(SYS1=combos[1,],SYS2=combos[2,],water,stringsAsFactors=FALSE) 
#   SYS1  SYS2 water 
#1 4NTJ_D294N 4NTJ_wild 114.489 
#2 4NTJ_D294N 4PXZ_D294N -3.112 
#3 4NTJ_D294N 4PXZ_wild 3.448 
#4 4NTJ_D294N 4PY0_D294N 20.498 
#5 4NTJ_D294N 4PY0_wild 22.538 
........ 
+0

perfetto che sembra essere praticamente quello che sto cercando. È possibile applicare automaticamente questo a ciascuna colonna di valori dal frame di dati originale o dovrei ripetere per ogni colonna? – wmsmith

+0

Funziona davvero quando è mappato in: mapply (function (y) combn (Test_data [, y], 2, FUN = function (x) x [1] -x [2]), c ("dE_water_free", "dE_water_periodic")) – wmsmith

8

Qui ci sono due soluzioni che tengano il prodotto vettoriale/join dei dati con sé.

In base di R, mi piacerebbe prendere in considerazione outer:

diffmat   <- with(Test_data,outer(dE_water_free,dE_water_free,`-`)) 
dimnames(diffmat) <- with(Test_data,list(SYS,SYS)) 

Se non si vuole il risultato in una matrice, non c'è

diffdf <- with(Test_data,data.frame(
    SYS1=SYS, 
    SYS2=rep(SYS,each=length(SYS)), 
    diff=c(diffmat) 
)) 

Con data.table, I' d usare @JanGorecki's CJ.dt function

require(data.table) 
setDT(Test_data) 

res <- CJ.dt(Test_data,Test_data)[,`:=`(
    freediff = dE_water_free-i.dE_water_free, 
    perdiff = dE_water_periodic-i.dE_water_periodic 
)] 
+1

haha, quasi la stessa risposta (+1) – BrodieG

+0

@BrodieG Yup. Il tuo 'setNames' in anticipo è una bella scorciatoia :) – Frank

+0

Hmm ... Ho scaricato il pacchetto optiRum da CRAN e ho provato a eseguire: res <- CJ.dt (Test_data, Test_data) [,': = '(freewdiff = dE_water_free - i .dE_water_free, perwdiff = dE_water_periodic - i.dE_water_periodic, permdiff = dE_membrane_periodic - i.dE_membrane_periodic)] ... ma mi ha dato l'errore: "i.dE_water_free" non trovato. – wmsmith

10

outer è adatto per questo tipo di problema:

de_wf <- with(Test_data, setNames(dE_water_free, SYS)) 
outer(de_wf, de_wf, `-`) 

produce: soluzione

  4NTJ_D294N 4NTJ_wild 4PXZ_D294N 4PXZ_wild 4PY0_D294N 4PY0_wild 
4NTJ_D294N  0.000 114.489  -3.112  3.448  20.498 22.538 
4NTJ_wild -114.489  0.000 -117.601 -111.041 -93.991 -91.951 
4PXZ_D294N  3.112 117.601  0.000  6.560  23.610 25.650 
4PXZ_wild  -3.448 111.041  -6.560  0.000  17.050 19.090 
4PY0_D294N -20.498 93.991 -23.610 -17.050  0.000  2.040 
4PY0_wild  -22.538 91.951 -25.650 -19.090  -2.040  0.000 
+0

interessante, potrei dover ricordare quel comando quando vado a creare matrici di correlazione. Sfortunatamente, ho bisogno di farlo per diverse colonne di valore in modo da poter creare grafici in modo che l'approccio matrice/griglia probabilmente non funzioni per me. – wmsmith

6

di Frank sembra molto più semplice e più facile. Ma ecco un altro approccio con le fusioni.

# Set Up 
Test.data <- data.frame(
    Col1 = c(1,1,1,1,1,1), 
    SYS = c("4NTJ_D294N",'4NTJ_wild',"4PXZ_D294N","4PXZ_wild","4PY0_D294N","4PY0_wild"), 
    dE_water_free = c(-56.542,-171.031,-53.43,-59.99,-77.04,-79.08) 
) 

Nuova idea basandosi su dplyr

library("dplyr") 
nuDat <- dplyr::left_join(
    dplyr::select(Test.data, Col1, SYS1 = SYS, dE_water_free1 = dE_water_free), 
    dplyr::select(Test.data, Col1, SYS2 = SYS, dE_water_free2 = dE_water_free), 
    by = "Col1" 
) %>% 
    dplyr::mutate(
    dE_water_free = dE_water_free1 - dE_water_free2 
    ) %>% 
    dplyr::filter(SYS1 != SYS2) %>% 
    dplyr::select(
    SYS1, SYS2, dE_water_free 
    ) 
Problemi correlati