使用行中的用户条目重塑R数据,为每个用户折叠

时间:2015-08-17 22:57:02

标签: r reshape

请原谅我对R世界的新任务,请提前感谢您的帮助。

我想分析实验数据。

数据以长格式显示,需要重新调整为宽,但我无法确切知道如何做到这一点。大多数熔化/铸造和重塑的例子都涉及更简单的数据帧。

每当受试者回答关于实验的问题时,他的用户ID,位置,年龄和性别被记录在一行中,然后他的一系列问题的实验数据被输入这些变量旁边。在这里,他们可以回答关于实验的任何问题,他们可能会回答不同的项目(这很复杂,但必须是这样)。

原始数据如下所示:

User_id, location, age, gender, Item, Resp
1, CA, 22, M, A, 1 
1, CA, 22, M, B, -1 
1, CA, 22, M, C, -1 
1, CA, 22, M, D, 1 
1, CA, 22, M, E,-1
2, MD, 27, F, A, -1 
2, MD, 27, F, B, 1 
2, MD, 27, F, C, 1 
2, MD, 27, F, E, 1 
2, MD, 27, F, G, -1 
2, MD, 27, F, H, -1 

我想重塑这些数据,让每个用户都在一行,看起来像这样:

User_id, location, age, gender, A, B, C, D, E, F, G, H
1, CA, 22, M, 1, -1, -1, 1, -1, 0, 0, 0, 
2, MD, 27, F, -1, 1, 1, 1, 0, 1, -1, -1

我认为这只是找到正确的重塑方程式的问题,但我已经使用了几个小时,而且我不能完全得到我想要的东西,因为大多数例子中没有重复的人口统计数据,因此可以更简单地旋转。如果我忽略了一些简单的事情,我感到非常抱歉。

3 个答案:

答案 0 :(得分:11)

使用data.table即可:

library(data.table)
> dcast(dt, User_id + location + age ~ Item, value.var = "Resp", fill = 0L)
   User_id location age  A  B  C  D  E  G  H
1:       1       CA  22  1 -1 -1  1 -1  0  0
2:       2       MD  27 -1  1  1  0  1 -1 -1

答案 1 :(得分:10)

有一个名为tidyr的软件包可以更轻松地融化和重塑数据框架。在您的情况下,您可以直接使用tidyr::spread

result = spread(df, Item, Resp)

然而,这将使用NA填充缺少的条目:

  User_id location age gender  A  B  C  D  E  G  H
1       1       CA  22      M  1 -1 -1  1 -1 NA NA
2       2       MD  27      F -1  1  1 NA  1 -1 -1

您可以通过替换它们来解决此问题:

result[is.na(result)] = 0
result
#   User_id location age gender  A  B  C  D  E  G  H
# 1       1       CA  22      M  1 -1 -1  1 -1  0  0
# 2       2       MD  27      F -1  1  1  0  1 -1 -1

...或使用fill参数:

result = spread(df, Item, Resp, fill = 0)

为了完整起见,反之亦然(即复制原始data.frame)通过gather(通常称为“融化”)起作用:

gather(result, Item, Resp, A : H)

- 这里的最后一个参数告诉gather要收集哪些列(并且它支持简洁的范围语法)。

答案 2 :(得分:10)

这里总是优雅的stats::reshape版本

(newdf <- reshape(df, direction = "wide", timevar = "Item", idvar = names(df)[1:4]))
#   User_id location age gender Resp. A Resp. B Resp. C Resp. D Resp. E Resp. G Resp. H
# 1       1       CA  22      M       1      -1      -1       1      -1      NA      NA
# 6       2       MD  27      F      -1       1       1      NA       1      -1      -1

NA中的reshape()缺少值,而且名称不是我们想要的。所以我们需要做更多的工作。在这里,我们可以更改名称,并将NA s替换为同一行中的零,以达到您想要的结果。

replace(setNames(newdf, sub(".* ", "", names(newdf))), is.na(newdf), 0)
#   User_id location age gender  A  B  C D  E  G  H
# 1       1       CA  22      M  1 -1 -1 1 -1  0  0
# 6       2       MD  27      F -1  1  1 0  1 -1 -1

当然,如果我们把它分成两个单独的行,那么代码肯定会更清晰。另请注意,原始数据中的F中没有Item,因此与您的输出存在差异。

数据:

df <- structure(list(User_id = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 
2L, 2L), location = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
2L, 2L, 2L), .Label = c(" CA", " MD"), class = "factor"), age = c(22L, 
22L, 22L, 22L, 22L, 27L, 27L, 27L, 27L, 27L, 27L), gender = structure(c(2L, 
2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c(" F", " M"
), class = "factor"), Item = structure(c(1L, 2L, 3L, 4L, 5L, 
1L, 2L, 3L, 5L, 6L, 7L), .Label = c(" A", " B", " C", " D", " E", 
" G", " H"), class = "factor"), Resp = c(1, -1, -1, 1, -1, -1, 
1, 1, 1, -1, -1)), .Names = c("User_id", "location", "age", "gender", 
"Item", "Resp"), class = "data.frame", row.names = c(NA, -11L
))