在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
下收集的。只是为了解释为什么我的数据/示例看起来像它那样。
答案 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
中加入的任何其他列。