用指标向量重塑长到长

问题描述 投票:0回答:4

我有一个这样的数据框:

df <- data.frame(v11=rnorm(1), v12=rnorm(1), v21=rnorm(1), v31=rnorm(1), v41=rnorm(1), v42=rnorm(1), v43=rnorm(1))

此数据框只有一行

df
#          v11       v12        v21       v31       v41       v42       v43
# 1 -0.4425873 0.6062714 -0.3816921 0.2477926 0.1292103 0.2801346 0.4290997

一些列是对同一主题的重复观察,例如v11v12是来自同一主题的两个观察结果。 v21v32只是单一观察。 v4x有三个观察结果。

我想重塑数据框看起来像这样:

v11  v21 v31  v41
v12   NA  NA  v42
 NA   NA  NA  v43

请注意,它应包含变量的值而不是其名称。

我有一个指示器矢量,标记哪个观察是什么:

v <- c(1, 2, 1, 1, 1, 2, 3)

每个“1”标记新列的开始。

我的第一个想法是自己构建每一行:

row1 <- df[, v == 1]
row2 <- df[, v == 2]
row3 <- df[, v == 3]

但这不包含NA。必须有一个更简单的方法。

注意:解决方案不应该依赖于原始列名v11v41等,而只能依赖于矢量v

r dplyr reshape tidyr
4个回答
2
投票

这是dplyr + tidyr的解决方案:

library(dplyr)
library(tidyr)

v <- c(1,2,1,1,1,2,3)

df %>%
  gather(var, value) %>%
  mutate(row_num = v,
         col_num = paste0("v", cumsum(v==1))) %>%
  select(-var) %>%
  spread(col_num, value)

结果:

  row_num         v1       v2         v3        v4
1       1 -0.5604756 1.558708 0.07050839 0.1292877
2       2 -0.2301775       NA         NA 1.7150650
3       3         NA       NA         NA 0.4609162

数据:

df = structure(list(v11 = -0.560475646552213, v12 = -0.23017748948328, 
    v21 = 1.55870831414912, v32 = 0.070508391424576, v41 = 0.129287735160946, 
    v42 = 1.71506498688328, v43 = 0.460916205989202), .Names = c("v11", 
"v12", "v21", "v32", "v41", "v42", "v43"), row.names = c(NA, 
-1L), class = "data.frame")

0
投票

你也可以用来自meltdcastreshape2transform做到这一点:

library(reshape2)
dcast(transform(melt(df),
                rownum = substr(variable,3,3),
                cols = substr(variable,1,2)),
      rownum ~ cols, value.var = 'value')

结果:

  rownum          v1        v2        v3          v4
1      1  1.43420148 0.7391372 -1.758605 -0.06982523
2      2 -0.07729196        NA        NA  0.45190553
3      3          NA        NA        NA -1.95836646

数据:

set.seed(2017)
df <- data.frame(v11=rnorm(1), v12=rnorm(1), v21=rnorm(1), v31=rnorm(1), v41=rnorm(1), v42=rnorm(1), v43=rnorm(1))

0
投票

这是基础R的解决方案,仅取决于您对测量数据进行分组的矢量v

首先,示例数据:

set.seed(0)
df <- data.frame(v11=rnorm(1), v12=rnorm(1), v21=rnorm(1), v31=rnorm(1), v41=rnorm(1), v42=rnorm(1), v43=rnorm(1))

#       v11        v12      v21      v31       v41      v42       v43
#1 1.262954 -0.3262334 1.329799 1.272429 0.4146414 -1.53995 -0.928567


v <- c(1,2,1,1,1,2,3)

然后做:

v_grp <- cumsum(v == 1) # create index that groups the measurement data

out <- split(unlist(df), v_grp) # split vector of measurements by group

## following required to pad split vectors with `NA`.
## There are packages that give functions that do this

max_in_group <- max(summary(factor(v_grp)))    
out <- lapply(out, function(v) {
    num_in_vec <- length(v)
    if (num_in_vec < max_in_group) {
        v <- c(v, rep(NA, max_in_group - num_in_vec))
    }
    return(unname(v))
})


out <- do.call(cbind, out)

out
#              1        2        3          4
# v11  1.2629543 1.329799 1.272429  0.4146414
# v12 -0.3262334       NA       NA -1.5399500
#             NA       NA       NA -0.9285670

0
投票

这是使用矩阵索引的完美案例,因为您已经拥有行索引。

以下是它的完成方式:

M <- matrix(NA, nrow = max(v), ncol = sum(v == 1))
M[cbind(v, cumsum(v == 1))] <- unlist(df, use.names = FALSE)
M
#            [,1]     [,2]       [,3]      [,4]
# [1,] -0.5604756 1.558708 0.07050839 0.1292877
# [2,] -0.2301775       NA         NA 1.7150650
# [3,]         NA       NA         NA 0.4609162

基本上,您首先创建一个填充matrix值的NA,然后使用“v”(您的行索引)来创建列索引,该矩阵的子集,并将值替换为“df”中未列出的值。


df在这个答案中来自useR的答案。

© www.soinside.com 2019 - 2024. All rights reserved.