Подтвердить что ты не робот

Разверните фрейм данных в комбинации пар строк

У меня есть кадр данных, который содержит столбец идентификатор/ключ, за которым следуют несколько столбцов столбцов значений. Я хочу расширить столбец данных, взяв уникальные пары записей в ключевом столбце в качестве новых строк и преобразуя столбцы значений, используя двоичные операции над записями из соответствующих строк.

например.

> 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

Некоторые из столбцов могут содержать или не содержать отсутствующие значения.

то, что я хотел бы, это взять каждую пару записей SYS, например. SYS1 SYS2 и вычислить двоичную операцию в соответствующих строках значений Например. SYS1 SYS2 dE_water_free (SYS == SYS1) -dE_water_free (SYS == SYS2)... и т.д.

        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.

Я могу использовать функцию combn(), чтобы получить массив пар из столбца SYSTEM, чтобы сформировать записи в SYS1 и SYS2, но я не уверен, как использовать его для создания нового фрейма данных...

Я знаю, что одним из вариантов было бы использовать что-то вроде mapply и строить каждый столбец индивидуально вручную, а затем вставлять их все в новый фрейм данных, но похоже, что он будет klunky и медленным, и должна быть более автоматическая функция для этого, например, изменить форму, слить или переделать... но я не могу понять, как это работает.

4b9b3361

Ответ 1

Ваш combn был хорошим способом. Попробуйте следующее:

 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
 ........

Ответ 2

outer хорошо подходит для такого типа проблем:

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

дает:

           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

Ответ 3

Вот два решения, которые принимают перекрестное произведение/объединение данных с самим собой.

В базе R я бы рассмотрел outer:

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

Если вам не нужен результат в матрице,

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

С data.table, я бы использовал @JanGorecki CJ.dt функцию

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

Ответ 4

Решение Frank выглядит намного проще и проще. Но здесь другой подход слияния.

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

Новая идея, полагающаяся на 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
    )