#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
, поэтому после первой итерации не останется исходных данных для обобщения.