Я пытаюсь создать таблицу описательной статистики, получая для каждого столбца фрейма данных следующую статистику: среднее, стандартное отклонение, 10-й, 50-й и 90-й квантили. Затем я хочу транспонировать набор данных так, чтобы столбцы представляли собой разные статистические данные, а каждая строка была переменной в наборе данных.
Вот пример набора данных:
dt <- data.frame(id = 1:100,
Numeric_Column_1 = rnorm(100),
Numeric_Column_2 = rnorm(100),
Numeric_Column_3 = rnorm(100),
Numeric_Column_4 = rnorm(100),
Numeric_Column_5 = rnorm(100))
и код, который должен генерировать таблицу:
desc_table <- dt %>% select(-id) %>%
dplyr::summarise_all(.funs = list(mean=mean(.,na.rm=T),
sd=sd(.,na.rm=T),
P10=~quantile(., c(0.1), na.rm=T),
P50=~quantile(., c(0.5), na.rm=T),
P90=~quantile(., c(0.9), na.rm=T)),
na.rm=TRUE) %>%
pivot_longer(cols = everything()) %>%
separate(name,c("Variable", "Stat"),sep = "_") %>%
pivot_wider(names_from = "Stat", values_from = "value") %>%
mutate(mean = round(mean, 2), sd= round(sd, 2))
Однако я получаю следующую ошибку:
Error in is.data.frame(x): 'list' object cannot be coerced to type 'double' In addition: Warning message: In mean.default (., na.rm = T): argument is not numeric or logical: returning NA
Как я могу это исправить?
Попробуйте это, изменив свой код в соответствии с современной идиомой и изменив разделитель в вашей идиоме <colname><separator><statistic>
с "_"
на "."
, чтобы избежать конфликта с именами столбцов (которые могли быть источником вашей ошибки)...
dt %>%
dplyr::summarise(
across(
-id,
list(
mean = \(x) mean(x, na.rm = TRUE),
sd = \(x) sd(x, na.rm = TRUE),
P10 = \(x) quantile(x, 0.1, na.rm = TRUE),
P50 = \(x) quantile(x, 0.5, na.rm = TRUE),
P90 = \(x) quantile(x, 0.9, na.rm = TRUE)
),
.names = "{.col}.{.fn}"
)
) %>%
pivot_longer(
everything(),
names_sep = "\\.",
names_to = c("Variable", "Stat")
) %>%
pivot_wider(names_from = "Stat", values_from = "value") %>%
mutate(mean = round(mean, 2), sd= round(sd, 2))
# A tibble: 5 × 6
Variable mean sd P10 P50 P90
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Numeric_Column_1 -0.04 0.94 -1.20 -0.0872 1.11
2 Numeric_Column_2 -0.15 1.03 -1.46 -0.107 1.07
3 Numeric_Column_3 0.11 1.01 -1.53 0.229 1.14
4 Numeric_Column_4 0.09 1.05 -1.17 0.103 1.53
5 Numeric_Column_5 -0.02 1.02 -1.34 -0.0238 1.38
Использование .names
в вызове across
устраняет необходимость в шаге separate
.
Возможно, в конечном итоге будет лучше отказаться от последнего элемента трубы и заменить его на knitr::kable(digits = 2)
. Это обеспечивает внутреннюю точность сводки при ее форматировании по вашему запросу.
Также посетите эту страницу, где объясняется, почему вам следует использовать TRUE
и FALSE
, а не T
и F
.
Большое спасибо за код и дополнительную подсказку об ИСТИНЕ/ЛОЖЬ. Я буду использовать их с этого момента!
Вам следует использовать extract
вместо separate
для использования некоторых регулярных выражений и добавлять ~
к вызовам функций внутри across
:
dt %>%
select(-id) %>%
summarise(across(everything(), list(mean = ~mean(., na.rm = TRUE),
sd = ~sd(.,na.rm=TRUE),
P10 = ~quantile(., c(0.1), na.rm=TRUE),
P50 = ~quantile(., c(0.5), na.rm=TRUE),
P90 = ~quantile(., c(0.9), na.rm=TRUE)))) %>%
pivot_longer(cols = everything()) %>%
extract(name, into = c("Variable", "Stat"), regex = "^([A-Z].*_\\d+)_(.*)") %>%
pivot_wider(names_from = "Stat", values_from = "value") %>%
mutate(mean = round(mean, 2), sd= round(sd, 2))
# A tibble: 5 × 6
Variable mean sd P10 P50 P90
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Numeric_Column_1 0.09 0.96 -1.17 0.0428 1.42
2 Numeric_Column_2 0.04 1.05 -1.09 -0.0829 1.42
3 Numeric_Column_3 0.09 1.05 -1.33 0.168 1.42
4 Numeric_Column_4 0 1.04 -1.29 -0.118 1.48
5 Numeric_Column_5 0.09 1.02 -1.11 0.0578 1.19
library(dplyr)
library(tidyr)
set.seed(123)
dt <- data.frame(id = 1:100,
Numeric_Column_1 = rnorm(100),
Numeric_Column_2 = rnorm(100),
Numeric_Column_3 = rnorm(100),
Numeric_Column_4 = rnorm(100),
Numeric_Column_5 = rnorm(100))
my.summary <- \(x) list(mean=mean(x,na.rm=T),
sd=sd(x,na.rm=T),
P10=quantile(x, c(0.1), na.rm=T),
P50=quantile(x, c(0.5), na.rm=T),
P90=quantile(x, c(0.9), na.rm=T))
dt %>%
pivot_longer(-id) %>%
summarise(stat = list(my.summary(value)), .by = name) %>%
unnest_wider(stat)
#> # A tibble: 5 × 6
#> name mean sd P10 P50 P90
#> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Numeric_Column_1 0.0904 0.913 -1.07 0.0618 1.26
#> 2 Numeric_Column_2 -0.108 0.967 -1.29 -0.226 1.06
#> 3 Numeric_Column_3 0.120 0.950 -1.03 0.0359 1.55
#> 4 Numeric_Column_4 -0.0362 1.04 -1.34 -0.00351 1.24
#> 5 Numeric_Column_5 0.106 0.989 -1.18 0.165 1.30
Created on 2024-04-22 with reprex v2.0.2
Во-первых, обратите внимание, что глаголы с ограниченной областью действия (те, которые оканчиваются на
_if
,_at
или_all
) были заменены использованиемpick()
илиacross()
. Дополнительную информацию см. в онлайн-документе. В отсутствие результатов, которые вы ожидаете на основе входных данных теста, трудно дать вам более точный совет. Но есть много-много вопросов по SO, которые покажут вам, как получить нужные вам сводки. У вас проблема с этой частью проблемы или с форматированием?