【问题标题】:R count by group / Loop function and output to csvR按组/循环功能计数并输出到csv
【发布时间】:2021-12-02 01:25:21
【问题描述】:

我有一个包含用户数据的数据框:

age = c(45, 21, 32, 33, 46)
gender = c('female', 'female', 'male', 'male', 'female')
income = c('low', 'low', 'medium', 'high', 'low')
education = c('high', 'high', 'high', 'medium', 'medium')

df = data.frame(age, gender ,income, education)

据此,我想获得一个清晰的列表,其中包含每个属性的计数和份额,然后我将附加到表/csv 中,该表应该更清晰,以供进一步使用,而不是作为功能数据框。对于一个类似这样的属性:

nusers = nrow(users)
df = count(users, gender)
df['sot']=df['n']/totuser
write.table(df,'stat.csv',sep=';', row.names = FALSE, append = T)

多个属性需要以下结果:

gender,n,sot
female,10,0.526315789
male,9,0.473684211
income,Freq,sot
low,4,0.210526316
medium,10,0.526315789
high,5,0.263157895
education,Freq,sot
low,8,0.421052632
medium,1,0.052631579
high,10,0.526315789

我(不是很熟练)尝试将其放入循环失败。我最好怎么做?

【问题讨论】:

    标签: r loops count


    【解决方案1】:

    这是dplyr 包的解决方案。

    理论上,实际代码可能仅限于一行

    library(dplyr)
    
    # ...
    
    for(nom in names(df)) write.table(df %>% count(!!sym(nom)) %>% mutate(sot = n/sum(n)), 'stat.csv', sep = ';', row.names = FALSE, append = TRUE)
    

    产生输出文件stat.csv

    "age";"n";"sot"
    21;1;0.2
    32;1;0.2
    33;1;0.2
    45;1;0.2
    46;1;0.2
    "gender";"n";"sot"
    "female";3;0.6
    "male";2;0.4
    "income";"n";"sot"
    "high";1;0.2
    "low";3;0.6
    "medium";1;0.2
    "education";"n";"sot"
    "high";3;0.6
    "medium";2;0.4
    

    但为了清晰起见,我选择使用 cmets 分解工作流程:

    library(dplyr)
    
    
    # ...
    # Code to generate `df`
    # ...
    
    
    # Create list to accumulate the summaries
    results <- list()
    
    # For each variable (by name) in `df`...
    for(nom in names(df)) {
      # ...append to the list the results of summarizing by that variable.
      results <- c(
        results,
        # Wrap summary in a `list` to append properly:
        list(
          df %>%
            # Interpret the variable name as the variable itself, within the context
            # of `df`; and count the occurrences of each of the values that variable
            # takes on within `df`.
            count(!!sym(nom)) %>%
            # Sum up the counts to reconstruct the total amount; then divide the
            # count `n` by that total, to obtain `sot`.
            mutate(sot = n/sum(n))
        ) %>%
          # Name that summary after the variable.
          setNames(nm = nom)
      )
    }
    
    
    # View results
    results
    

    鉴于您的示例df 在此处复制

    structure(
      list(
        age       = c(45      , 21      , 32      , 33      , 46      ),
        gender    = c("female", "female", "male"  , "male"  , "female"),
        income    = c("low"   , "low"   , "medium", "high"  , "low"   ),
        education = c("high"  , "high"  , "high"  , "medium", "medium")
      ),
      class = "data.frame",
      row.names = c(NA, -5L)
    )
    

    此工作流程应产生以下 listresults

    $age
      age n sot
    1  21 1 0.2
    2  32 1 0.2
    3  33 1 0.2
    4  45 1 0.2
    5  46 1 0.2
    
    $gender
      gender n sot
    1 female 3 0.6
    2   male 2 0.4
    
    $income
      income n sot
    1   high 1 0.2
    2    low 3 0.6
    3 medium 1 0.2
    
    $education
      education n sot
    1      high 3 0.6
    2    medium 2 0.4
    

    我的解决方案涵盖了df 中的每个变量,但您可以通过修改for-loop 来排除age 等变量。

    要将所有这些写成文件stat.csv,并在您的代码中以; 分隔,只需完成:

    for(summr in results) {
      write.table(
        x = summr, 
        file = 'stat.csv',
        sep = ';',
        row.names = FALSE,
        append = TRUE
      )
    }
    

    【讨论】:

    • 这正是我所需要的!导致我的循环失败的部分原因也是缺少 sym()
    • @bountan 很高兴我能帮上忙!
    【解决方案2】:

    您可以为此使用sink()

    library(dplyr)
    n_gen <- df %>% group_by(gender) %>% summarise(Feq = n(), sot = n()/nrow(df))
    n_inc <- df %>% group_by(income) %>% summarise(Feq = n(), sot = n()/nrow(df))
    n_edu <- df %>% group_by(education) %>% summarise(Feq = n(), sot = n()/nrow(df))
    
    sink('export.csv')
    
    write.csv(n_gen, row.names = F)
    write.csv(n_inc, row.names = F)
    write.csv(n_edu, row.names = F)
    
    sink()
    

    你可以缩短它并将它写在一个 for 循环中。取决于您有多少列(在 df 中)可能是首选

    【讨论】:

      【解决方案3】:

      您应该使用 'count_()' 而不是 'count()' 它是相同的函数,但它在 'var' 中使用变量而不是字符串。

      library(dplyr)
      
      for (i in class) {
         df = count_(users, i)
         write.csv(df, row.names = T, file = paste0('Title_',i,'.txt'))
      }
      

      【讨论】:

      • 仅供参考,dplyr::count_() 函数是 deprecated。不幸的是,您的代码for (i in class) 会引发错误,您对未定义变量users 的引用也是如此。最后,你的循环结构修改了,然后重置失败df,所以在第一次迭代之后,将没有原始数据可以总结。
      猜你喜欢
      • 2017-05-10
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      • 2018-06-21
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多