【问题标题】:How to get a frequency table of all columns of complete data frame in R?如何获取R中完整数据框所有列的频率表?
【发布时间】:2015-08-26 07:15:54
【问题描述】:

我想从数据框中创建一个频率表并将其保存在 excel 中。使用table() 函数我只能创建特定列的频率。但是我想为所有列创建频率表,并且对于每一列,变量的级别或类型也可能不同。就像数据框的总结一样,但不会有平均值或其他度量,只有频率。 我正在尝试这样的事情

 for(i in 1:230){
 rm(tb)
 tb<-data.frame(table(mydata[i]))
 tb2<-cbind(tb2,tb)
 }

但它显示以下错误

data.frame(..., check.names = FALSE) 中的错误:参数暗示 不同的行数:15、12

代替cbind(),我还使用了data.frame(),但错误没有改变。

【问题讨论】:

  • lapply(mydata,table) 呢?
  • 错误表示tb2包含15行,tb包含12行。
  • 我刚刚尝试使用 write.csv 将其保存在 csv 文件中时 lapply(mydata,table),它会产生错误 Error in data.frame(s_id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, : arguments imply differing number of rows: 24066, 27558, 17779, 18466, 3, 15, 5, 12, 13, 10, 4, 9, 7, 2, 21, 20, 51, 14, 23, 24, 31, 6, 26, 8, 55, 576, 1027, 2459, 363, 1973, 765。在我尝试使用 data.frame() 时也出现同样的错误。
  • 如您所说,变量的级别可能会有所不同。您希望如何创建一个包含所有变量频率的数据框?您可能可以执行诸如最小值、最大值、平均值、频率之类的操作,因为无论如何您的所有列都会产生 3 个值。

标签: r


【解决方案1】:

也许 rbind 解决方案更好,因为它允许您处理不同级别的变量:

dt = data.frame(x = c("A","A","B","C"),
                y = c(1,1,2,1))

dt

#   x y
# 1 A 1
# 2 A 1
# 3 B 2
# 4 C 1

dt_res = data.frame()

for (i in 1:ncol(dt)){

dt_temp = data.frame(t(table(dt[,i])))
dt_temp$Var1 = names(dt)[i]

dt_res = rbind(dt_res, dt_temp)

}

names(dt_res) = c("Variable","Levels","Freq")

dt_res

#   Variable Levels Freq
# 1        x      A    2
# 2        x      B    1
# 3        x      C    1
# 4        y      1    3
# 5        y      2    1

还有一个使用 apply 的替代(可能更快)过程:

dt = data.frame(x = c("A","A","B","C"),
                y = c(1,1,2,1))

dt

ff = function(x){

  y = data.frame(t(table(x)))
  y$Var1 = NULL
  names(y) = c("Levels","Freq")
  return(y)
}

dd = do.call(rbind, apply(dt, 2, ff)) 

dd

#     Levels Freq
# x.1      A    2
# x.2      B    1
# x.3      C    1
# y.1      1    3
# y.2      2    1


# extract variable names from row names
dd$Variable = sapply(row.names(dd), function(x) unlist(strsplit(x,"[.]"))[1])

dd

#     Levels Freq Variable
# x.1      A    2        x
# x.2      B    1        x
# x.3      C    1        x
# y.1      1    3        y
# y.2      2    1        y

【讨论】:

    【解决方案2】:

    您遇到错误是因为您尝试组合具有不同维度的数据框。据我了解,您的问题有两个:(1)您想获得每列的频率分布,而不管类型如何;并且,(2) 您希望将所有结果保存在一个 Excel 工作表中。

    对于第一个问题,可以使用mapply()函数。

    set.seed(1)
    
    dat <- data.frame(
      x = sample(LETTERS[1:5], 15, replace = TRUE),
      y = rbinom(5, 15, prob = 0.4)
    )
    
    mylist <- mapply(table, dat); mylist
    
    # $x
    # 
    # A B C D E 
    # 2 5 1 4 3 
    # 
    # $y
    # 
    # 5  6  7 11 
    # 3  3  6  3 
    

    您也可以使用purrr::map()

    library(purrr)
    dat %>% map(table)
    

    第二个问题在这个问题中有几个解决方案:Export a list into a CSV or TXT file in R。特别是,LyzanderR 的回答将使您能够按照自己的意愿去做。如果您希望将输出保存在单独的文件中,您可以这样做:

    mapply(write.csv, mylist, file=paste0(names(mylist), '.csv'))
    

    【讨论】:

      【解决方案3】:

      编辑(2021-03-29):tidyverse 原则

      这里是一些使用tidyverse 的更新代码,特别是来自dplyrtibblepurrr 的函数。该代码更具可读性并且更易于执行。提供了示例数据集。

      tibble(
          a = rep(c(1:3), 2),
          b = factor(rep(c("Jan", "Feb", "Mar"), 2)),
          c = factor(rep(LETTERS[1:3], 2))
          ) -> 
          dat
      
      dat #print df
      
      # A tibble: 6 x 3
          a    b    c    
        <int> <fct> <fct>
      1     1 Jan   A    
      2     2 Feb   B    
      3     3 Mar   C    
      4     1 Jan   A    
      5     2 Feb   B    
      6     3 Mar   C
      

      获取跨列的计数和比例。

      library(purrr)
      library(dplyr)
      library(tibble)
      #library(tidyverse) #to load assortment of pkgs
      
      #output tables - I like to use parentheses & specifying my funs
      purrr::map(
          dat, function(.x) {
              count(tibble(x = .x), x) %>% 
                  mutate(pct = (n / sum(n) * 100)) 
              })
      
      #here is the same code but more concise (tidy eval)
      purrr::map(dat, ~ count(tibble(x = .x), x) %>% 
                     mutate(pct = (n / sum(n) * 100)))
      
      $a
      # A tibble: 6 x 3
            x     n   pct
        <int> <int> <dbl>
      1     1     1  16.7
      2     2     1  16.7
      3     3     1  16.7
      4     4     1  16.7
      5     5     1  16.7
      6     6     1  16.7
      
      $b
      # A tibble: 3 x 3
        x         n   pct
        <fct> <int> <dbl>
      1 Feb       2  33.3
      2 Jan       2  33.3
      3 Mar       2  33.3
      
      $c
      # A tibble: 2 x 3
        x         n   pct
        <fct> <int> <dbl>
      1 A         3    50
      2 B         3    50
      

      旧代码...

      table() 函数返回一个“表”对象,根据我的经验,使用 R 几乎不可能操作它。我倾向于只编写自己的函数来规避这个问题。让我们首先创建一个包含一些分类变量/特征(宽格式数据)的数据框。

      我们可以将lapply() 与base R 中的table() 函数结合使用,为每个特征创建频率计数列表。

      freqList = lapply(select_if(dat, is.factor), 
                    function(x) {
                        df = data.frame(table(x))
                        names(df) = c("x", "y")
                        
                        return(df) 
                          }
                      )
      

      这种方法使每个列表对象都可以很容易地被索引并在必要时进一步操作,这对于包含许多特征的数据框来说非常方便。使用print(freqList)查看所有频率表。

      【讨论】:

      • 如果比例表(即总观察的百分比)是多列的目标,那么试试我的帖子here
      猜你喜欢
      • 1970-01-01
      • 2020-04-16
      • 1970-01-01
      • 2020-07-08
      • 2011-08-23
      • 2020-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多