将第2列中的值附加到第1列中的值

时间:2013-12-13 17:57:35

标签: r merge dataframe

在R中,我有两个共享列(A and B)的数据框(1, 2 and 3)。第1列具有唯一标识符,并且对于每个数据帧都是相同的;第2列和第3列有不同的信息。我尝试合并这两个数据帧以获得1个具有第1,2和3列的新数据帧,并且其中第2列和第3列中的值是连接的:即新数据帧的第2列包含:[data frame A column 2 + data frame B column 2]

示例:

dfA <- data.frame(Name = c("John","James","Peter"),
                  Score = c(2,4,0),
                  Response = c("1,0,0,1","1,1,1,1","0,0,0,0"))

dfB <- data.frame(Name = c("John","James","Peter"),
                  Score = c(3,1,4),
                  Response = c("0,1,1,1","0,1,0,0","1,1,1,1"))

dfA:
    Name Score Response
1  John     2  1,0,0,1
2 James     4  1,1,1,1
3 Peter     0  0,0,0,0

dfB:
   Name Score Response
1  John     3  0,1,1,1
2 James     1  0,1,0,0
3 Peter     4  1,1,1,1

应该导致:

dfNew <- data.frame(Name = c("John","James","Peter"),
                    Score = c(5,5,4),
                    Response = c("1,0,0,1,0,1,1,1","1,1,1,1,0,1,0,0","0,0,0,0,1,1,1,1"))

dfNew:
   Name Score Response
1  John     5  1,0,0,1,0,1,1,1
2 James     5  1,1,1,1,0,1,0,0
3 Peter     4  0,0,0,0,1,1,1,1

我已尝试merge,但只是添加了列(非常类似于cbind

有没有办法做到这一点,而不必遍历所有列,如:

colnames(dfNew) <- c("Name","Score","Response")
dfNew$Score <- dfA$Score + dfB$Score
dfNew$Response <- paste(dfA$Response, dfB$Response, sep=",")

正如您可能已经注意到的那样,增加的难度是,对于某些列,我们需要使用加法,而其他列则需要用逗号分隔的连接(需要添加的列格式化为数字,其他列格式为文本,这可能会使它更容易吗?)

提前致谢!

PS。字符串1,0,0,1,0,1,1,1等捕获每次试验的响应 - 此示例有8个试验,参与者可以正确响应(1)或不正确(0);最终得分是在Score下收集的。只是为了解释为什么我的数据/示例看起来像它那样。

2 个答案:

答案 0 :(得分:2)

就个人而言,我会尽量避免从一开始就将“每次试验的响应”连接到一个变量(“响应”),以使数据不那么静态,并促进任何后续的分析或数据管理步骤。鉴于个别试验已经连接起来,如你的例子所示,我会考虑将它们分开。格式化数据框以获得最终的,漂亮的打印输出,我会考虑另外一个不同的问题。

# merge data (cbind would also work if data are ordered properly)
df <- merge(x = dfA[ , c("Name", "Response")], y = dfB[ , c("Name", "Response")],
            by = "Name")

# rename
names(df) <- c("Name", c("A", "B"))

# split concatenated columns
library(splitstackshape)
df2 <- concat.split.multiple(data = df, split.cols = c("A", "B"),
                             seps = ",", direction = "wide")

# calculate score
df2$Score <- rowSums(df2[ , -1])
df2
#    Name A_1 A_2 A_3 A_4 B_1 B_2 B_3 B_4 Score
# 1 James   1   1   1   1   0   1   0   0     5
# 2  John   1   0   0   1   0   1   1   1     5
# 3 Peter   0   0   0   0   1   1   1   1     4

答案 1 :(得分:1)

我会在要合并的列名称上使用for循环来处理此问题。给出您的示例数据:

cols <- c("Score", "Response")

dfNew <- dfA[,"Name",drop=FALSE]
for (n in cols) {
  switch(class(dfA[[n]]),
         "numeric" = {dfNew[[n]] <- dfA[[n]] + dfB[[n]]},
         "factor"=, "character" = {dfNew[[n]] <- paste(dfA[[n]], dfB[[n]], sep=",")})
}

这个解决方案基本上就是你的想法,但有一个循环。查看数据集以查看它们是数字(以数字方式添加)还是字符串或因子(连接字符串)。您可以通过使用两个名称向量来获得类似的结果,一个用于数字,一个用于字符,但如果您还有其他数据类型,这是可扩展的(尽管我不知道它们可能是什么)。该方法的主要缺点是假设数据帧与Name的顺序相同。下一个解决方案没有做出这个假设

dfNew <- merge(dfA, dfB, by="Name")
for (n in cols) {
  switch(class(dfA[[n]]),
         "numeric" = {dfNew[[n]] <- dfNew[[paste0(n,".x")]] + dfNew[[paste0(n,".y")]]},
         "factor"=, "character" = {dfNew[[n]] <- paste(dfNew[[paste0(n,".x")]], dfNew[[paste0(n,".y")]], sep=",")})
  dfNew[[paste0(n,".x")]] <- NULL
  dfNew[[paste0(n,".y")]] <- NULL
}

与上一个相同的一般概念,但使用merge来确保数据正确对齐,然后使用dfNew处理列(其名称后缀为“.x”和“.y”)。添加其他步骤以在加入后删除单独的列。还有一个额外的功能,即携带未指定在cols中加入的任何其他列。