#r #dplyr #tidyverse #apply #purrr
#r #dplyr #tidyverse #применить #purrr
Вопрос:
(Использование mtcars и iris для воспроизводимости)
Я создал функцию R get_col_info
для поиска сводки данных, которая соответствует приведенной ниже:
-
Если столбец
numeric/integer/double
равен, то получаем минимальное, максимальное, среднее -
Если столбец
character/factor
, то получите количество уникальных значений и уникальных значенийget_col_info <- function(data,col_name) { c_name <- c(col_name) s <- data[,c_name] type <- typeof(s) if(type %in% c("numeric","double","integer")){ min <- min(s) max <- max(s) mean <- mean(s) aa <- list(min=min, max=max,mean=mean) return(aa) } if(type %in% c("character","factor")){ uni <- unique(s) len <- length(uni) aa <- list(n_values=len,unique_values=c(uni)) return(aa)} } get_col_info(mtcars, "mpg") get_col_info(iris, "Petal.Width") get_col_info(iris, "Species")
Первые два выполняются идеально, третий выдает ошибку, не уверен, почему?
Однако основной запрос теперь заключается в том, что я хочу запустить эту функцию для всех имен столбцов сразу, что-то вроде sapply(iris,mean)
, но я не уверен, как это сделать, потому что функция принимает dataframe amp; имя столбца. Я пытался это сделать, но это выдает ошибку
sapply(iris,get_col_info(iris,names(iris)))
Error in match.fun(FUN) :
'get_col_info(iris, names(iris))' is not a function, character or symbol
Оба решения apply и purrr приветствуются. Я также ищу кого-нибудь, кто мог бы рассказать мне, как я мог бы лучше написать свою функцию, я подозреваю, что созданный мной c_name не является идеальным способом получения имен столбцов.
Комментарии:
1. с помощью вашей написанной функции вы могли бы сделать:
sapply(c("Petal.Length","Petal.Width"), get_col_info, data=iris)
Ответ №1:
Вы должны использовать class
для проверки типа, а не typeof
:
get_col_info <- function(data,col_name) {
s <- data[,col_name]
type <- class(s)
if(type %in% c("numeric","double","integer")){
min <- min(s)
max <- max(s)
mean <- mean(s)
aa <- list(min=min, max=max,mean=mean)
return(aa)
}
else if(type %in% c("character","factor")){
uni <- as.character(unique(s))
len <- length(uni)
aa <- list(n_values=len,unique_values=uni)
return(aa)
}
}
Проверка выходных данных :
get_col_info(mtcars, "mpg")
#$min
#[1] 10.4
#$max
#[1] 33.9
#$mean
#[1] 20.09062
get_col_info(iris, "Species")
#$n_values
#[1] 3
#$unique_values
#[1] "setosa" "versicolor" "virginica"
Чтобы запустить это для нескольких столбцов, вы можете использовать :
sapply(names(iris), get_col_info, data = iris)
Или замените sapply
на map
, если вас интересует purrr
решение.
Другим способом было бы передавать значения столбцов напрямую вместо имени.
get_col_info <- function(s) {
if(is.numeric(s)) {
min <- min(s)
max <- max(s)
mean <- mean(s)
aa <- list(min=min, max=max,mean=mean)
return(aa)
}
else {
uni <- as.character(unique(s))
len <- length(uni)
aa <- list(n_values=len,unique_values=uni)
return(aa)
}
}
sapply(iris, get_col_info)
Комментарии:
1. Честно, получил первую часть. Я проверю разницу между ними. Но основная часть заключается в том, что теперь я хочу запустить эту функцию для всех столбцов сразу. Как я могу это сделать с именованным столбцом в качестве имени списка
2. Спасибо, можете ли вы объяснить мне, есть ли лучший способ «поймать» имя столбца или то, что я написал, в порядке, действительно хочу улучшить написание функций, и я чувствую, что это не здорово, что я написал
3. Я бы передал значения функции вместо имени. Я обновил ответ, чтобы показать это.
Ответ №2:
Вы можете сделать это с помощью summarise
and across
, с проверкой типа (например is.numeric
):
library(dplyr)
iris %>%
summarise(across(where(is.numeric), list(min=min, max=max, mean=mean)),
across(where(~is.factor(.) | is.character(.)),
list(n_values = ~length(unique(.)),
unique_values = ~as.character(unique(.))))) %>%
glimpse()
Вывод:
Rows: 3
Columns: 14
$ Sepal.Length_min <dbl> 4.3, 4.3, 4.3
$ Sepal.Length_max <dbl> 7.9, 7.9, 7.9
$ Sepal.Length_mean <dbl> 5.843333, 5.843333, 5.843333
$ Sepal.Width_min <dbl> 2, 2, 2
$ Sepal.Width_max <dbl> 4.4, 4.4, 4.4
$ Sepal.Width_mean <dbl> 3.057333, 3.057333, 3.057333
$ Petal.Length_min <dbl> 1, 1, 1
$ Petal.Length_max <dbl> 6.9, 6.9, 6.9
$ Petal.Length_mean <dbl> 3.758, 3.758, 3.758
$ Petal.Width_min <dbl> 0.1, 0.1, 0.1
$ Petal.Width_max <dbl> 2.5, 2.5, 2.5
$ Petal.Width_mean <dbl> 1.199333, 1.199333, 1.199333
$ Species_n_values <int> 3, 3, 3
$ Species_unique_values <chr> "setosa", "versicolor", "virginica"
Примечание: я добавил glimpse()
, чтобы сделать вывод более читаемым, в этом нет необходимости.