2015-05-18 23 views
17

Mam ramkę danych, która zawiera kolumnę identyfikatora/klucza, po której następuje kilka wierszy kolumn wartości. Chcę rozwinąć kolumnę danych, biorąc unikatowe pary wpisów w kolumnie klucza jako nowe wiersze i przekształcić kolumny wartości za pomocą operacji binarnych we wpisach z odpowiednich wierszy.Rozwiń ramkę danych w kombinacje par wierszy.

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 

Niektóre kolumny mogą zawierać lub mogą nie zawierać brakujących wartości.

Chciałbym wziąć każdą parę pozycji SYS, np. SYS1 SYS2 i obliczyć operację binarną na odpowiednich wierszach wartości E.g. Sys1 sys2 dE_water_free (SYS == sys1) -dE_water_free (SYS == sys2) ... itd

 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. 

mogę użyć funkcji combn() aby uzyskać tablicę par z kolumny SYSTEM tworząc wpisy w sys1 i SYS2, ale nie wiem, jak go użyć do zbudowania nowej ramki danych ...

Wiem, że jedną z opcji byłoby użycie czegoś takiego jak mapply i samodzielne zbudowanie każdej kolumny ręcznie, a następnie wklejenie ich wszystkich do nowa ramka danych, ale wygląda na to, że będzie wolna i wolna, i powinna istnieć bardziej automatyczna funkcja, taka jak przekształcanie, scalanie lub przekształcanie ... ale nie mogę się domyślić, jak to działa .

+0

Luźno powiązane: http://stackoverflow.com/q/30237924/1191259 – Frank

+0

Przy okazji, jeśli chcesz * ALL * par, jak 'a, B' i' B, A' , będziesz potrzebować 'expand.grid' (lub' CJ' w pakiecie 'data.table') zamiast' combn', jak sądzę. – Frank

Odpowiedz

10

Twój combn była dobra droga. Spróbuj tego:

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

doskonały, który wydaje się być prawie tym, czego szukam. Czy jest możliwe automatyczne zastosowanie tego do każdej kolumny wartości z pierwotnej ramki danych, czy też musiałbym ją powtarzać dla każdej kolumny? – wmsmith

+0

To rzeczywiście działa po zapakowaniu w mapply:> mapply (funkcja (y) combn (Test_data [, y], 2, FUN = funkcja (x) x [1] -x [2]), c ("dE_water_free", "dE_water_periodic")) – wmsmith

8

Oto dwa rozwiązania, które przyjmują krzyżowy produkt/połączenie danych z samym sobą.

w bazie R, Pomyślę outer:

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

Jeśli nie chcesz wynik w matrycy, nie

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

Z data.table, I d użyć @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, prawie taka sama odpowiedź (+1) – BrodieG

+0

@BrodieG Yup. Wasz 'setNames' wcześniej jest fajnym skrótem :) – Frank

+0

Hmm ... Pobrałem pakiet optiRum z CRAN i próbowałem uruchomić: 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)] ... ale dało mi to błąd: nie znaleziono "i.dE_water_free". – wmsmith

10

outer dobrze nadaje się do tego typu problemu:

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

produkuje: rozwiązanie

  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

ciekawe, być może będę musiał pamiętać to polecenie, kiedy idę do tworzenia macierzy korelacji. Niestety, muszę to zrobić dla kilku kolumn wartości, aby móc tworzyć fabuły, więc podejście matryca/siatka prawdopodobnie nie zadziała dla mnie. – wmsmith

6

Franka wygląda o wiele prostsze i łatwiejsze. Ale tutaj jest inne podejście do łączenia.

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

Nowy pomysł powołując się na 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 
    ) 
Powiązane problemy