2015-05-18 11 views
17

Tôi có một khung dữ liệu chứa một mã định danh/khóa chính được theo sau bởi một vài hàng của các cột giá trị. Tôi muốn mở rộng cột dữ liệu bằng cách lấy các cặp mục duy nhất trong cột khóa làm các hàng mới và chuyển đổi các cột giá trị sử dụng phép toán nhị phân trên các mục từ các hàng tương ứng.Mở rộng khung dữ liệu thành các tổ hợp của các cặp hàng

Ví dụ:

> 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 

Một số cột có thể hoặc không thể chứa (các) giá trị còn thiếu.

điều tôi muốn là lấy từng cặp mục nhập SYS, ví dụ: SYS1 SYS2 và tính toán một phép toán nhị phân trên các hàng có giá trị tương ứng Ví dụ: SYS1 SYS2 dE_water_free (SYS == SYS1) -dE_water_free (SYS == SYS2) ... vv

 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. 

tôi có thể sử dụng chức năng combn() để có được một mảng của các cặp từ cột HỆ THỐNG để tạo thành các mục trong SYS1 và SYS2, nhưng tôi không biết cách sử dụng nó để xây dựng khung dữ liệu mới ...

Tôi biết một tùy chọn sẽ sử dụng một cái gì đó như mapply và xây dựng từng cột một cách thủ công, sau đó dán tất cả vào một khung dữ liệu mới, nhưng điều đó có vẻ như nó sẽ là klunky và chậm và sẽ có một chức năng tự động hơn để thực hiện việc này, như định dạng lại, hợp nhất hoặc lặp lại ... nhưng tôi không thể tìm ra cách làm việc đó .

+0

Lỏng lẻo liên quan: http://stackoverflow.com/q/30237924/1191259 – Frank

+0

Bằng cách này, nếu bạn muốn * tất cả * cặp, như 'A, b' và 'B, A' , bạn sẽ muốn 'expand.grid' (hoặc' CJ' trong gói 'data.table') thay vì' combn', tôi nghĩ vậy. – Frank

Trả lời

10

bạn combn là một cách tốt để đi. Hãy thử điều này:

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

hoàn hảo mà dường như là khá nhiều những gì tôi sau. Có thể tự động áp dụng điều này cho mỗi cột giá trị từ khung dữ liệu gốc hay tôi phải lặp lại cho mỗi cột? – wmsmith

+0

Điều này thực sự hoạt động khi được bọc trong một cách tinh tế:> ánh xạ (hàm (y) combn (Test_data [, y], 2, FUN = hàm (x) x [1] -x [2]), c ("dE_water_free", "dE_water_periodic")) – wmsmith

8

Dưới đây là hai giải pháp lấy sản phẩm/tham gia chéo của dữ liệu với chính nó.

Trong cơ sở R, tôi muốn xem xét outer:

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

Nếu bạn không muốn kết quả trong một ma trận, có

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

Với data.table, tôi d sử dụng @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, gần như cùng một câu trả lời (+1) – BrodieG

+0

@BrodieG Yup. 'SetNames' của bạn trước là một phím tắt đẹp :) – Frank

+0

Hmm ... Tôi đã tải xuống gói optiRum từ CRAN và thử chạy: 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)] ... nhưng nó đã cho tôi lỗi: "i.dE_water_free" không tìm thấy. – wmsmith

10

outer là rất thích hợp cho loại hình này của vấn đề:

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

sản xuất: giải pháp

  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

thú vị, tôi có thể phải nhớ rằng lệnh khi tôi đi để làm cho ma trận tương quan. Thật không may, tôi cần phải làm điều này cho một số cột giá trị để tôi có thể làm cho cốt truyện để ma trận/lưới phương pháp tiếp cận có lẽ sẽ không làm việc cho tôi. – wmsmith

6

Frank trông đơn giản hơn rất nhiều và dễ dàng hơn. Nhưng đây là một cách tiếp cận khác với sự hợp nhất.

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

ý tưởng mới dựa vào 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 
    ) 
Các vấn đề liên quan