如何在R中正确拆分调查响应

axkjgtzd  于 2023-01-22  发布在  其他
关注(0)|答案(4)|浏览(115)

在调查统计数据中,当允许对一个问题进行多个回答时,可以在单个列中记录多个回答标签。
在分析此类数据时,您可能希望在单独的列中存储多个响应,这就需要进行字符串拆分。
将以下代码作为示例运行。

smp <- data.frame(
  x = c("1,2,3", "2,5,9", "1,5", "2,7,8,9,10")
)
smp
#>            x
#> 1      1,2,3
#> 2      2,5,9
#> 3        1,5
#> 4 2,7,8,9,10

创建于2023年1月21日,使用reprex v2.0.2
在此数据中,每行表示不同响应者的响应,分析师知道总共有多少个选项,但不知道将选择哪些响应或选择多少响应。
将其适当划分的结果应如下所示

out <- data.frame(
  d_1 = c(1,NA,1,NA),
  d_2 = c(2,2,NA,2),
  d_3 = c(3,NA,NA,NA),
  d_4 = c(NA,NA,NA,NA),
  d_5 = c(NA,5,5,NA),
  d_6 = c(NA,NA,NA,NA),
  d_7 = c(NA,NA,NA,7),
  d_8 = c(NA,NA,NA,8),
  d_9 = c(NA,9,NA,9),
  d_10 = c(NA,NA,NA,10)
)
out
#>   d_1 d_2 d_3 d_4 d_5 d_6 d_7 d_8 d_9 d_10
#> 1   1   2   3  NA  NA  NA  NA  NA  NA   NA
#> 2  NA   2  NA  NA   5  NA  NA  NA   9   NA
#> 3   1  NA  NA  NA   5  NA  NA  NA  NA   NA
#> 4  NA   2  NA  NA  NA  NA   7   8   9   10

创建于2023年1月21日,使用reprex v2.0.2
有什么好办法把数据整理成这个表格吗?

vx6bjr1n

vx6bjr1n1#

这个并不优雅的函数可以给予你预期的结果。

split_survey <- function(data){
  df <- data
  
  val <- df %>% 
    tidyr::separate_rows(x, sep=",", convert = TRUE) %>% 
    range() 
  
  Names <- paste0("d_", seq(val[1], val[2]))
  df <- data.frame(do.call(rbind, list(Names)))
  names(df) <- df[1,]
  df[1:nrow(data), ] <- NA
  
  values <- lapply(strsplit(data$x, ","), function(x) paste0("d_",sub("\\s+", "", x)))

  for(i in seq_len(nrow(df))){
    ind <- names(df) %in%  values[[i]] 
    df[i, ind] <- as.integer(sub("\\D+", "", values[[i]]))
  }
  
  df[] <- lapply(df, as.integer)

  return(df)
}

split_survey(smp)
 d_1 d_2 d_3 d_4 d_5 d_6 d_7 d_8 d_9 d_10
1   1   2   3  NA  NA  NA  NA  NA  NA   NA
2  NA   2  NA  NA   5  NA  NA  NA   9   NA
3   1  NA  NA  NA   5  NA  NA  NA  NA   NA
4  NA   2  NA  NA  NA  NA   7   8   9   10

如果smp只包含一个名为x的变量(如示例中所示),则此方法有效。

fjnneemd

fjnneemd2#

可能是真值表,以R为基

smp <- data.frame(
  x = c("1,2,3", "2,5,9", "1,5", "2,7,8,9,10")
)
smp_mtx <- matrix(NA, nrow = 4, ncol = 10)

for (i in 1:nrow(smp)) {
smp_mtx[i, which(c(1,2,3,4,5,6,7,8,9,10) %in% as.numeric(unlist(strsplit(smp[i, ], split = ','))) == TRUE)] <- TRUE
}
smp_mtx
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] TRUE TRUE TRUE   NA   NA   NA   NA   NA   NA    NA
[2,]   NA TRUE   NA   NA TRUE   NA   NA   NA TRUE    NA
[3,] TRUE   NA   NA   NA TRUE   NA   NA   NA   NA    NA
[4,]   NA TRUE   NA   NA   NA   NA TRUE TRUE TRUE  TRUE

which(提供了一个奇怪的、有点神秘的arr.ind = TRUE),它可能允许我们将值重新放回真值表中......我发现最简单的方法是先将其作为一个对象

arr_idx_T <- which(smp_mtx == TRUE, arr.ind = TRUE)
arr_idx_T
      row col
 [1,]   1   1
 [2,]   3   1
 [3,]   1   2
 [4,]   2   2
 [5,]   4   2
 [6,]   1   3
 [7,]   2   5
 [8,]   3   5
 [9,]   4   7
[10,]   4   8
[11,]   2   9
[12,]   4   9
[13,]   4  10
arr_idx_T[, 2][which(arr_idx_T[,1] == 1)]
[1] 1 2 3
arr_idx_T[, 2][which(arr_idx_T[,1] == 2)]
[1] 2 5 9

同时给出列和值,现在只是将它们重新插入的技术,其表示法现在使我的大脑出现了一个小问题。虽然which(x arr.ind =TRUE)非常值得注意,但我在这里的错误在于引入了“真值表”,而不是直接根据df填充char元素

smp_int_df <- data.frame(matrix(NA_integer_, nrow =4, ncol = 10))
smp_int_df
  X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
1 NA NA NA NA NA NA NA NA NA  NA
2 NA NA NA NA NA NA NA NA NA  NA
3 NA NA NA NA NA NA NA NA NA  NA
4 NA NA NA NA NA NA NA NA NA  NA

for (i in 1:nrow(smp_int_df)) {
 smp_int_df[i, which(c(1:10) %in% as.numeric(unlist(strsplit(smp[i, ],split=','))))] <- c(1:10)[which(c(1:10) %in% as.numeric(unlist(strsplit(smp[i, ],split=','))))] 
 }
smp_int_df
  X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
1  1  2  3 NA NA NA NA NA NA  NA
2 NA  2 NA NA  5 NA NA NA  9  NA
3  1 NA NA NA  5 NA NA NA NA  NA
4 NA  2 NA NA NA NA  7  8  9  10

然后你就可以随意命名了。

bzzcjhmw

bzzcjhmw3#

以下是tidyverse解决方案,其中使用了tidyverse系列中的各种函数:

library(dplyr)
library(readr)
library(tidyr)

smp %>% 
  mutate(id = row_number()) %>% 
  separate_rows(x) %>% 
  type.convert(as.is = TRUE) %>% 
  arrange(x) %>% 
  complete(x = first(x):last(x)) %>% 
  mutate(x = paste0("d_", x)) %>% 
  count(id, x) %>% 
  pivot_wider(names_from = x, values_from = n) %>%
  filter(row_number() <= n()-1) %>% 
  mutate(across(-id, ~case_when(. == 1 ~ readr::parse_number(cur_column())))) %>% 
  select(order(readr::parse_number(names(.))), -id)
d_1   d_2   d_3   d_4   d_5   d_6   d_7   d_8   d_9  d_10
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1     1     2     3    NA    NA    NA    NA    NA    NA    NA
2    NA     2    NA    NA     5    NA    NA    NA     9    NA
3     1    NA    NA    NA     5    NA    NA    NA    NA    NA
4    NA     2    NA    NA    NA    NA     7     8     9    10
dpiehjr4

dpiehjr44#

下面是另一种方法,其中我使用了连接

数据

smp <- data.frame(
  x = c("1,2,3", "2,5,9", "1,5", "2,7,8,9,10")
)

编号

library(tidyverse)

dummmy <- data.frame(x=1:10) %>% mutate(x=as.character(x))

df <- tibble(x=strsplit(smp$x,',')) %>% mutate(len=row_number(), value=x) %>% 
  unnest(c(x,value)) %>% 
  full_join(dummmy, by='x') %>% 
  mutate(name=paste0('d_',x), x=as.numeric(x), value=as.numeric(value)) %>% 
  arrange(x) %>%   
  pivot_wider(len, names_from = name, values_from = value) %>% select(-len) %>% 
  mutate(sum=rowSums(across(starts_with('d')),na.rm=T)) %>% 
  filter(sum>0) %>% select(-sum)

创建于2023年1月21日,使用reprex v2.0.2

输出

# A tibble: 4 × 10
    d_1   d_2   d_3   d_4   d_5   d_6   d_7   d_8   d_9  d_10
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1     1     2     3    NA    NA    NA    NA    NA    NA    NA
2     1    NA    NA    NA     5    NA    NA    NA    NA    NA
3    NA     2    NA    NA     5    NA    NA    NA     9    NA
4    NA     2    NA    NA    NA    NA     7     8     9    10

相关问题