【问题标题】:Proportion Frequency Table with multiple Binary Data具有多个二进制数据的比例频率表
【发布时间】:2020-04-07 14:41:05
【问题描述】:

我在这里发布的第一个问题,希望我没有违反太多政策。

我正在尝试获取由一个或两个其他变量分组的几个二进制变量的相对频率表 分类变量。

country<-c('germany','germany','germany','USA','USA','USA','USA','germany','germany','USA')
sex<-c('female','male','male','female','female','female','male','female','female','female')
binary1<-c(1,1,0,1,0,1,0,0,0,1)
binary2<-c(0,1,0,1,1,1,0,1,0,1)
binary3<-c(0,1,1,1,0,1,0,0,0,1)
df<-cbind(country,sex,binary1,binary2,binary3)

我想要这样的输出:

Germany
  Female                                Male
    variable       0          1           variable       0          1 
    binary1      66.7%      33.3%         binary1      50.0%       50.0%    
    binary2      66.7%      33.3%         binary2      50.0%       50.0%
    binary3      100%        0%           binary3      0%         100%   

USA
  Female                                Male
    variable       0          1           variable       0          1 
    binary1      25%         75%          binary1       100%        0%    
    binary2      0%          100%         binary2       100%        0%
    binary3      25%         75%          binary3       100%        0%    

应该提到我有很多二进制变量,请记住这一点。这是我实现这个的主要问题之一。

您可以提供的任何建议或建议将不胜感激!

【问题讨论】:

    标签: r dplyr data.table


    【解决方案1】:

    也许你可以试试下面的基本 R 代码

    dfout <- lapply(split(df,df$country), 
                    function(v) lapply(split(v,v$sex),
                                       function(x) 100*data.frame(Var0 = 1-colMeans(x[-(1:2)]),Var1=colMeans(x[-(1:2)]))))
    

    这样

    > dfout
    $germany
    $germany$female
                 Var0     Var1
    binary1  66.66667 33.33333
    binary2  66.66667 33.33333
    binary3 100.00000  0.00000
    
    $germany$male
            Var0 Var1
    binary1   50   50
    binary2   50   50
    binary3    0  100
    
    
    $USA
    $USA$female
            Var0 Var1
    binary1   25   75
    binary2    0  100
    binary3   25   75
    
    $USA$male
            Var0 Var1
    binary1  100    0
    binary2  100    0
    binary3  100    0
    

    【讨论】:

      【解决方案2】:

      似乎data.table::cube 非常适合这个问题:

      ans <- cube(melt(DT, id.vars=c("country", "sex")),
          .(c(0L, 1L), tabulate(value + 1L) / length(value)),
          c("country", "sex", "variable"))
      ans[complete.cases(ans)]
      

      输出:

          country    sex variable V1        V2
       1: germany female  binary1  0 0.6666667
       2: germany female  binary1  1 0.3333333
       3: germany   male  binary1  0 0.5000000
       4: germany   male  binary1  1 0.5000000
       5:     USA female  binary1  0 0.2500000
       6:     USA female  binary1  1 0.7500000
       7:     USA   male  binary1  0 1.0000000
       8:     USA   male  binary1  1 1.0000000
       9: germany female  binary2  0 0.6666667
      10: germany female  binary2  1 0.3333333
      11: germany   male  binary2  0 0.5000000
      12: germany   male  binary2  1 0.5000000
      13:     USA female  binary2  0 0.0000000
      14:     USA female  binary2  1 1.0000000
      15:     USA   male  binary2  0 1.0000000
      16:     USA   male  binary2  1 1.0000000
      17: germany female  binary3  0 1.0000000
      18: germany female  binary3  1 1.0000000
      19: germany   male  binary3  0 0.0000000
      20: germany   male  binary3  1 1.0000000
      21:     USA female  binary3  0 0.2500000
      22:     USA female  binary3  1 0.7500000
      23:     USA   male  binary3  0 1.0000000
      24:     USA   male  binary3  1 1.0000000
          country    sex variable V1        V2
      

      数据:

      library(data.table)
      country <- c('germany','germany','germany','USA','USA','USA','USA','germany','germany','USA')
      sex<-c('female','male','male','female','female','female','male','female','female','female')
      binary1 <- c(1,1,0,1,0,1,0,0,0,1)
      binary2 <- c(0,1,0,1,1,1,0,1,0,1)
      binary3 <- c(0,1,1,1,0,1,0,0,0,1)
      DT <- data.table(country,sex,binary1,binary2,binary3)
      

      【讨论】:

      • 谢谢,这正是我想要的!这仅适用于二进制数据(0,1),对吗?是否有可能也使用这个多维数据集函数来处理分类数据?非常感谢您的帮助。
      • 你能发布一些分类变量的样本吗?我可以用它来测试表格
      • @Marius 我在下面编写的函数将适用于任何变量的任意数量级别
      【解决方案3】:

      以上两个答案都完成了工作,但我在这个上浪费了一些时间,可能是自我隔离变得疯狂。我的第一个想法是使用 janitor::tabyl 就像 tabyl(df, sex, binary1, country) %&gt;% adorn_percentages("row") 一样,它几乎可以满足您的需求。不幸的是,它只喜欢单个裸变量,在purrr::map 链中表现不佳。因此,使用基本的tidyverse 工具,我编写了一个自定义函数来创建一个可以与purrr 很好地配合使用的tibble,然后自学更多关于flextable 的知识,我用它来使输出更好。请注意,您的原始数据不是数据框,因此我更改了该部分。

      我的解决方案恕我直言的优点是它具有很强的可扩展性和可修改性。

      library(tidyverse)
      library(flextable)
      #> 
      #> Attaching package: 'flextable'
      #> The following object is masked from 'package:purrr':
      #> 
      #>     compose
      country <- c('germany','germany','germany','USA','USA','USA','USA','germany','germany','USA')
      sex <- c('female','male','male','female','female','female','male','female','female','female')
      binary1 <- c(1,1,0,1,0,1,0,0,0,1)
      binary2 <- c(0,1,0,1,1,1,0,1,0,1)
      binary3 <- c(0,1,1,1,0,1,0,0,0,1)
      
      # make it a true dataframe
      df <- as.data.frame(cbind(country,sex,binary1,binary2,binary3))
      
      xtabs3 <- function(data,
                             x,
                             y,
                             z) {
      
        # internal helper function
        not_a_factor <- function(x){
          !is.factor(x)
        }
      
        # capture variable names
          xlab <- rlang::as_name(rlang::enquo(x))
          ylab <- rlang::as_name(rlang::enquo(y))
          zlab <- rlang::as_name(z)
      
        # create temp local dataframe 
          data <-
            dplyr::select(
              .data = data,
              x = {{ x }},
              y = {{ y }},
              z = {{ z }}
            )
      
        # calculate counts and percents 
      
        # x, y and z need to be a factor or ordered factor
        # also drop the unused levels of the factors and NAs
        data <- data %>%
          dplyr::mutate_if(.tbl = ., not_a_factor, as.factor) %>%
          dplyr::mutate_if(.tbl = ., is.factor, droplevels) %>%
          dplyr::filter_all(.tbl = ., all_vars(!is.na(.))) %>%
          dplyr::as_tibble(x = .)
      
        # convert the data into percentages; group by x, y, z
        # DO NOT Drop zeroes  
        df <-
          data %>%
          dplyr::group_by(.data = ., x, y, z, .drop = FALSE) %>%
          dplyr::summarize(.data = ., counts = n()) %>%
          dplyr::mutate(.data = ., perc = (counts / sum(counts)) * 100) %>%
          dplyr::ungroup(x = .) %>%
          rename(!!xlab := x, !!ylab := y, "level" := z)
      
          return(df)
      
      }
      
      # Make a list of all the binary variables we want to use
      # best if it's a named list variables can be bare or quoted
      fff <- alist(binary1 = binary1, binary2 = binary2, binary3 = binary3)
      # fff <- alist(binary1, binary2, binary3)
      # fff <- alist(binary1 = "binary1", binary2 = "binary2", binary3 = "binary3")
      
      xxx <- purrr::map_dfr(.x = fff, ~ xtabs3(df, country, sex, .x), .id = "Which_binary")
      
      xxx
      #> # A tibble: 24 x 6
      #>    Which_binary country sex    level counts  perc
      #>    <chr>        <fct>   <fct>  <fct>  <int> <dbl>
      #>  1 binary1      germany female 0          2  66.7
      #>  2 binary1      germany female 1          1  33.3
      #>  3 binary1      germany male   0          1  50  
      #>  4 binary1      germany male   1          1  50  
      #>  5 binary1      USA     female 0          1  25  
      #>  6 binary1      USA     female 1          3  75  
      #>  7 binary1      USA     male   0          1 100  
      #>  8 binary1      USA     male   1          0   0  
      #>  9 binary2      germany female 0          2  66.7
      #> 10 binary2      germany female 1          1  33.3
      #> # … with 14 more rows
      
      myft <- flextable(xxx, col_keys = c("Which_binary", "country", "sex", "level", "perc"))
      myft <- theme_vanilla(myft)
      myft <- merge_v(myft, j = c("country", "sex", "Which_binary") )
      myft <- autofit(myft)
      myft <- colformat_num(x = myft, j = c("perc"), digits = 1, suffix = "%")
      # reprex won't let me make an html table
      plot(myft)
      

      # myft
      

      由reprex package (v0.3.0) 于 2020 年 4 月 8 日创建

      【讨论】:

        猜你喜欢
        • 2013-11-05
        • 1970-01-01
        • 1970-01-01
        • 2017-05-30
        • 1970-01-01
        • 2015-09-04
        • 1970-01-01
        • 2011-01-05
        相关资源
        最近更新 更多