【问题标题】:Transforming long table into wide format with counts for only one column将长表转换为宽格式,仅计算一列
【发布时间】:2020-07-27 03:58:46
【问题描述】:

我有一个如下所示的长格式表,在这个输入表中每一行都是唯一的:-

 year variable
  2014   ab  
  2014   cd  
  2014   ef 
  2016   ef 
  2016   gh
  2014   ab  
  2014   cd  
  2014   ef 
  2016   ef 
  2016   gh

我想将此表转换为宽格式,但仅限variable 列,它看起来像一个应急矩阵。例如 - 如下输出表所示,ab+cd 的组合在 2014 年出现 ONCE,ab+ef 组合在 2014 年也出现 ONCE。这样,我的输出表的第一行清楚地显示所有Counts 的不同组合variable 不同年份输入表的列。

year    value  ab  cd  ef  gh  
2014    ab     2    2   2   0
2014    cd     2    2   2   0 
2014    ef     2    2   2   0 
2014    ef     0    0   2   2 
2016    gh     0    0   2   2 

我尝试了很多次重塑表格,但未能达到我想要的结果。如果解决方案包括使用data.table,我将非常感激。谢谢你。

【问题讨论】:

  • 您想要的输出似乎与输入不一致。例如,在 2014 年,cdef 都存在,但在您的输出中,相应的单元格有一个 0
  • 谢谢。我改了。
  • 不应该 "ef+cd" 为 1,就像 "cd+ef" 吗?

标签: r dplyr data.table reshape2 dcast


【解决方案1】:

假设您希望 ef-cd 单元格为 1 而不是 0,这里是使用 igraphtidyverse 的一种稍微复杂的方法。这个想法是创建一个二分图,找到 1-mode 投影,并从该投影创建一个邻接矩阵:

library(tidyverse)
library(igraph)

df <- tibble(year = c("2014",
                "2014",
                "2014",
                "2016",
                "2016"),
             variable = c("ab",
                          "cd",
                          "ef",
                          "ef",
                          "gh"))

tab <- df %>% 
  group_split(year) %>% 
  map(~ .x %>% 
        graph_from_data_frame(directed = FALSE) %>% 
        set_vertex_attr("type", value = ifelse(V(.)$name %in% .x$year, TRUE, FALSE)) %>% 
        bipartite_projection(which = FALSE) %>% 
        add_edges(rep(1:length(unique(.x$variable)), 2) %>% sort()) %>% 
        as_adjacency_matrix(sparse = FALSE) %>% 
        as_tibble()) %>% 
  bind_rows() %>% 
  mutate_all(coalesce, 0)

cbind(df, tab)
#>   year variable ab cd ef gh
#> 1 2014       ab  1  1  1  0
#> 2 2014       cd  1  1  1  0
#> 3 2014       ef  1  1  1  0
#> 4 2016       ef  0  0  1  1
#> 5 2016       gh  0  0  1  1

reprex package (v0.3.0) 于 2020-04-14 创建

【讨论】:

    【解决方案2】:

    一种方法是按年份为变量的每次出现分配一个 id,转为宽格式,按年份拆分,取这些表的叉积,然后重新组合。

    library(dplyr)
    library(purrr)
    library(tidyr)
    
    df %>% 
      group_by(year, variable) %>%
      mutate(x = 1,
             id = seq_along(x)) %>%
      pivot_wider(names_from = variable, values_from = x, values_fill = list(x = 0)) %>%
      split(x = ., f = .$year) %>%
      map_df(~ crossprod(as.matrix(.x[-c(1,2)])) %>%
            subset(., rowSums(.) > 0) %>%
            as.data.frame() %>%
            rownames_to_column(), .id = "year")
    
      year rowname ab cd ef gh
    1 2014      ab  2  2  2  0
    2 2014      cd  2  2  2  0
    3 2014      ef  2  2  2  0
    4 2016      ef  0  0  2  2
    5 2016      gh  0  0  2  2
    

    【讨论】:

      【解决方案3】:

      这是一个使用data.table的选项:

      vs <- DT[, unique(variable)]
      for (x in vs) set(DT, j=x, value=0L)
      DT[, (vs) := {
              m <- as.matrix(.SD)
              m[, match(variable, vs)] <- 1L
              as.data.table(m)
          }, year, .SD=vs]
      DT
      

      还有:

      DT[, (vs) := {
              m <- copy(.SD)
              m[, match(variable, vs)] <- 1L
              m
          }, year, .SD=vs]
      

      根据问题描述输出(正如 Daniel O 和 meriops 所指出的,期望的输出和问题描述之间存在一些不一致):

         year variable ab cd ef gh
      1: 2014       ab  1  1  1  0
      2: 2014       cd  1  1  1  0
      3: 2014       ef  1  1  1  0
      4: 2016       ef  0  0  1  1
      5: 2016       gh  0  0  1  1
      

      数据:

      library(data.table)
      DT <- fread("year variable
      2014   ab  
      2014   cd  
      2014   ef 
      2016   ef 
      2016   gh")
      

      【讨论】:

      • 嘿,我想我需要时间来理解代码。我对此很陌生。我可以知道如何进一步更改代码以获得与列联表相同的数字而不是 1 或 0?再次感谢。
      • 我可能需要一些时间来了解列联表。您是否可以更新您的示例以显示示例?
      • 我更改了输入输出数据示例。如您所见,不是从您的代码中获取由 1 和 0 组成的稀疏矩阵。我想要减少矩阵,其中包括所述组合的出现次数之和。我希望这很清楚。再次非常感谢您。
      • @newbie,fread("year variable\n 2014 ab\n 2014 cd\n 2014 ef\n 2014 ab") 的预期输出是什么?
      【解决方案4】:

      这是Base R 中完成此任务的一些代码

      df_new <- t(sapply(unique(df$year), function(X) lapply(unique(df$variable), function(Y)  length(which(df$variable== Y & df$year == X)))))
      row.names(df_new) <- unique(df$year)
      colnames(df_new) <- unique(df$variable)
      

      输出:

           ab cd ef gh
      2014 1  1  1  0 
      2016 0  0  1  1 
      

      输入数据:

      Input = (
        ' year variable
        2014   ab  
        2014   cd  
        2014   ef 
        2016   ef 
        2016   gh')
      df = read.table(textConnection(Input), header = T)
      

      【讨论】:

      • 我对@9​​87654325@ 列中的计数组合感兴趣,而不是year 列的整体计数。您缺少我的输出表中显示的第二列。
      【解决方案5】:
      df <- data.table(df)
      df_dcast <- dcast.data.table(df,year~value,fun=length)
      

      【讨论】:

      • 不,这不正确。您正在将整个输入表转换为纯宽格式。输出表包括ab+cd和ab+ef的组合
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-18
      • 1970-01-01
      • 1970-01-01
      • 2017-11-04
      • 2021-04-09
      相关资源
      最近更新 更多