Количество R по функции группы / цикла и вывод в csv

#r #loops #count

Вопрос:

У меня есть фрейм данных, содержащий пользовательские данные :

 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
 

Мои (не очень умелые) попытки ввести это в цикл не увенчались успехом. Как бы мне лучше всего это сделать ?

Ответ №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
 

но я решил разбить рабочий процесс с комментариями для ясности:

 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)
)
 

этот рабочий процесс должен привести к следующему list results :

 $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 , но не стесняйтесь исключать переменные, например age , изменяя for -цикл.

Чтобы записать все это в виде файла stat.csv , разделенного ; как в вашем коде, просто завершите:

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

Комментарии:

1. это делает именно то, что мне было нужно ! отчасти из-за того, что мой цикл не удался, также отсутствовала функция sym ()

2. @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'))
}
 

Комментарии:

1. К вашему сведению, эта dplyr::count_() функция устарела . К сожалению, ваш код for (i in class) выдает ошибку, как и ваша ссылка на неопределенную переменную users . Наконец, структура вашего цикла изменяется , а затем не сбрасывается df , поэтому после первой итерации не останется исходных данных для обобщения.