#r #dataframe
#r #фрейм данных
Вопрос:
У меня есть следующий пример набора данных опроса:
df <- data.frame(sex = c(1, 1, 2, 2, 1, 2, 2, 2, 1, 2),
age = c(15, 40, 97, 25, 99, 65, 20, 99, 39, 48),
nationality= c(1, 3, 1, 2, 4, 97, 2, 2, 2, 99),
employment = c(2, 1, 99, 1, 1, 1, 1, 1, 2, 2),
income = c(-1, 2500, 999997, 10000, 65000, 999998, 999999, 15000, -1, -1),
weight = c(100, 20, 400, 300, 50, 50, 80, 250, 100, 100))
Следующий список содержит выбранные переменные, которые я хочу использовать в цикле for:
list <- list(age = df$age, employment = df$employment, income = df$income)
Я хочу перебрать список выбранных переменных в фрейме данных, и для каждой переменной в списке применить фильтр (условие) и получить таблицу взвешенных частот из отфильтрованных данных. В псевдокоде это то, что я хочу сделать:
for i in list {
filter(i >= 1 amp; i <= max(i)-2 %>%
weighted frequency of var i based on 'weight'
}
Я перепробовал много способов сделать это в R, но я все еще не могу понять, как. В прошлый раз, когда я использовал это:
library(dplyr)
library(expss)
for (i in list){
filter(i > 1 amp; i < max(i))-2 %>%
fre(i, weight = df$weight)
}
Но я получаю это сообщение об ошибке:
Error in UseMethod("filter_") :
no applicable method for 'filter_' applied to an object of class "logical"
Мне нужно выяснить, как это сделать, потому что мне нужно перебрать список из 256 переменных.
Результаты должны быть:
library(dplyr)
library(expss)
age: <br />
F <- df %>% filter(age >= 1 amp; age < 97)
fre(F$age, weight = F$weight)
| F$age | Count | Valid percent | Percent | Responses, % | Cumulative responses, % |
| ------ | ----- | ------------- | ------- | ------------ | ----------------------- |
| 15 | 100 | 13.3 | 13.3 | 13.3 | 13.3 |
| 20 | 80 | 10.7 | 10.7 | 10.7 | 24.0 |
| 25 | 300 | 40.0 | 40.0 | 40.0 | 64.0 |
| 39 | 100 | 13.3 | 13.3 | 13.3 | 77.3 |
| 40 | 20 | 2.7 | 2.7 | 2.7 | 80.0 |
| 48 | 100 | 13.3 | 13.3 | 13.3 | 93.3 |
| 65 | 50 | 6.7 | 6.7 | 6.7 | 100.0 |
| #Total | 750 | 100.0 | 100.0 | 100.0 | |
| <NA> | 0 | | 0.0 | | |
employment: <br />
F <- df %>% filter(employment >= 1 amp; employment < 97)
fre(F$employment, weight = F$weight)
| F$employment | Count | Valid percent | Percent | Responses, % | Cumulative responses, % |
| ------------ | ----- | ------------- | ------- | ------------ | ----------------------- |
| 1 | 750 | 71.4 | 71.4 | 71.4 | 71.4 |
| 2 | 300 | 28.6 | 28.6 | 28.6 | 100.0 |
| #Total | 1050 | 100.0 | 100.0 | 100.0 | |
| <NA> | 0 | | 0.0 | | |
income: <br />
F <- df %>% filter(income >= 1 amp; income < 999997)
fre(F$income, weight = F$weight)
| F$income | Count | Valid percent | Percent | Responses, % | Cumulative responses, % |
| -------- | ----- | ------------- | ------- | ------------ | ----------------------- |
| 2500 | 20 | 3.2 | 3.2 | 3.2 | 3.2 |
| 10000 | 300 | 48.4 | 48.4 | 48.4 | 51.6 |
| 15000 | 250 | 40.3 | 40.3 | 40.3 | 91.9 |
| 65000 | 50 | 8.1 | 8.1 | 8.1 | 100.0 |
| #Total | 620 | 100.0 | 100.0 | 100.0 | |
| <NA> | 0 | | 0.0 | | |
Комментарии:
1. Один краткий комментарий — фрейм данных — это список, где каждый элемент списка представляет собой столбец и должен иметь одинаковую длину. Извлечение столбцов из фрейма данных и помещение их в список на самом деле ничего не дает…
list <- list(age = df$age, employment = df$employment, income = df$income)
это долгий способ записиdf[c("age", "employment", "income")]
, возможно, завернутый,as.list()
если вы действительно не хотите, чтобы это был фрейм данных. Чтобы выполнить цикл по набору столбцов, часто лучше поместить имена только в вектор, например, ,cols = c("age", "employment", "income")
, а затем вы можете использоватьdf[[i]]
в своем цикле.
Ответ №1:
lapply
Версия.
library(dplyr)
library(expss)
vars_to_run <- c('age' , 'employment', 'income')
lapply(setNames(vars_to_run, vars_to_run), function(x){
z <- sym(x)
df_filter <- df %>%
filter(!!z >= 1 amp; !!z <= max(!!z) - 2 )
fre(df_filter[, x], weight = df_filter[, 'weight'])
})
Или с использованием базы R и [
.
lapply(setNames(vars_to_run, vars_to_run), function(x){
df_filter <- df[df[x] >= 1 amp; df[x] <= max(df[x]) - 2, ]
expss::fre(df_filter[x], weight = df_filter[ , 'weight'])
})
Оба ответа возвращают именованный список
$age
| df_filter[x] | Count | Valid percent | Percent | Responses, % | Cumulative responses, % |
| ------------ | ----- | ------------- | ------- | ------------ | ----------------------- |
| 15 | 100 | 8.7 | 8.7 | 8.7 | 8.7 |
| 20 | 80 | 7.0 | 7.0 | 7.0 | 15.7 |
| 25 | 300 | 26.1 | 26.1 | 26.1 | 41.7 |
| 39 | 100 | 8.7 | 8.7 | 8.7 | 50.4 |
| 40 | 20 | 1.7 | 1.7 | 1.7 | 52.2 |
| 48 | 100 | 8.7 | 8.7 | 8.7 | 60.9 |
| 65 | 50 | 4.3 | 4.3 | 4.3 | 65.2 |
| 97 | 400 | 34.8 | 34.8 | 34.8 | 100.0 |
| #Total | 1150 | 100.0 | 100.0 | 100.0 | |
| <NA> | 0 | | 0.0 | | |
$employment
| df_filter[x] | Count | Valid percent | Percent | Responses, % | Cumulative responses, % |
| ------------ | ----- | ------------- | ------- | ------------ | ----------------------- |
| 1 | 750 | 71.4 | 71.4 | 71.4 | 71.4 |
| 2 | 300 | 28.6 | 28.6 | 28.6 | 100.0 |
| #Total | 1050 | 100.0 | 100.0 | 100.0 | |
| <NA> | 0 | | 0.0 | | |
$income
| df_filter[x] | Count | Valid percent | Percent | Responses, % | Cumulative responses, % |
| ------------ | ----- | ------------- | ------- | ------------ | ----------------------- |
| 2500 | 20 | 2.0 | 2.0 | 2.0 | 2.0 |
| 10000 | 300 | 29.4 | 29.4 | 29.4 | 31.4 |
| 15000 | 250 | 24.5 | 24.5 | 24.5 | 55.9 |
| 65000 | 50 | 4.9 | 4.9 | 4.9 | 60.8 |
| 999997 | 400 | 39.2 | 39.2 | 39.2 | 100.0 |
| #Total | 1020 | 100.0 | 100.0 | 100.0 | |
| <NA> | 0 | | 0.0 | | |
Ответ №2:
Давайте посмотрим здесь. Вам нужно будет обновить for
синтаксис цикла. Я добавил круглые скобки и преобразовал индекс в число. Вы также должны инициализировать объект, который вы хотите заполнить циклом.
Далее вам нужно преобразовать столбцы в их имена и отфильтровать, используя rlang
синтаксис, который преобразует 'age'
в age
(стандартная оценка в нестандартную оценку).
library(dplyr)
library(rlang)
df <- data.frame(sex = c(1, 1, 2, 2, 1, 2, 2, 2, 1, 2),
age = c(15, 40, 97, 25, 99, 65, 20, 99, 39, 48),
nationality= c(1, 3, 1, 2, 4, 97, 2, 2, 2, 99),
employment = c(2, 1, 99, 1, 1, 1, 1, 1, 2, 2),
income = c(-1, 2500, 999997, 10000, 65000, 999998, 999999, 15000, -1, -1),
weight = c(100, 20, 400, 300, 50, 50, 80, 250, 100, 100))
## just list the names in a vector
loop_over <- c('age' ,'employment', 'income')
## initialize the object you want the loop to fill
final <- list()
for (i in 1:length(loop_over)) {
## !!sym() coverts the column name to non-standard evaluation
temp <- df %>%
filter( !!sym(loop_over[i]) >= 1 amp; !!sym(loop_over[i]) <= max(!!sym(loop_over[i])) - 2 )
avg <- fre( temp[[ loop_over[i] ]], weight = temp$weight )
final[i] <- list(avg)
}