将数据框展开为行对

时间:2015-05-18 20:05:49

标签: r dataframe

我有一个数据框,其中包含一个标识符/键列,后跟几行值列。 我想通过将键列中的唯一条目对作为新行来扩展数据列,并使用对相应行的条目的二进制运算来转换值列。

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

某些列可能包含也可能不包含缺失值。

我想要的是每对SYS条目,例如SYS1 SYS2并在相应的值行上计算二进制运算 例如。 SYS1 SYS2 dE_water_free(SYS == SYS1)-dE_water_free(SYS == SYS2)... etc

        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这样的东西,然后手动单独构建每一列,然后将它们全部粘贴到一个新的数据框中,但这似乎是笨重而且速度慢,应该有更自动的功能这样做,比如重塑,合并或重铸......但我似乎无法弄清楚如何使它发挥作用。

4 个答案:

答案 0 :(得分:11)

Collector.OfXxx非常适合此类问题:

outer

产生

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

答案 1 :(得分:10)

您的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 :(得分:8)

以下两个解决方案将数据的交叉产品/连接与自身结合起来。

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

答案 3 :(得分:6)

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
    )