Новая матрица, содержащая конкретные данные

#r #sapply

#r #sapply

Вопрос:

Пример данных

 data=data.frame("group"=c(rep(0:1,10)),
                "value1" = c(1:10),
                "value2" = seq(11:20),
                "value3" = as.factor(rep(1:3,length=10)))
  

Цель
введите описание изображения здесь

У меня есть фрейм данных «data» с целью создания нового фрейма данных, как показано на рисунке. ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ, ЧТО ЗНАЧЕНИЕ 3 ЯВЛЯЕТСЯ ФАКТОРНОЙ ПЕРЕМЕННОЙ. Итак, я хотел бы сообщить n и процент. Для каждой группы, как на картинке.

Я знаю, что нужно оценивать минимальные и максимальные значения отдельно следующим образом

 value1_min0 = min(data$value1)[data$group==1]
value1_max0 = max(data$value1)[data$group==1]
value1_min1 = min(data$value1)[data$group==0]
value1_max1 = max(data$value1)[data$group==0]
  

Но есть ли лучший способ сделать это более эффективно?

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

1. Вы хотите для всех значений или только для значения 1?

2. Все значения в образцах данных для обеих групп, как на рисунке. @NelsonGon спасибо

Ответ №1:

База R

Используйте aggregate для числовых переменных и table / prop.table для коэффициента.

 ag <- aggregate(cbind(value1, value2) ~ group, data, 
  function(x) c(min = min(x), max = max(x)))
tab12 <- as.data.frame.matrix(setNames(as.data.frame(t(ag[-1])), 
  ag[[1]]))

counts <- table(data$group)

tab3 <- prop.table(table(group = data$value3, value3 = data$group), 2)
rownames(tab3) <- paste("value3", rownames(tab3), sep = " = ")

rbind(tab12, n = counts, as.data.frame.matrix(tab3))
  

дает следующее

               0    1
value1.min  1.0  2.0
value1.max  9.0 10.0
value2.min  1.0  2.0
value2.max  9.0 10.0
n          10.0 10.0
value3 = 1  0.4  0.4
value3 = 2  0.2  0.4
value3 = 3  0.4  0.2
  

sqldf

Эта альтернатива немного утомительна, но она проста:

 library(sqldf)

res <- sqldf('select
  [group],  
  min(value1) [value1.min],
  max(value1) [value1.max],
  min(value2) [value2.min],
  max(value2) [value2.max],
  count(*) n,
  avg(value3 = 1) [value3 == 1],
  avg(value3 = 2) [value3 == 2],
  avg(value3 = 3) [value3 == 3]
  from data
  group by [group]')
setNames(as.data.frame(t(res[-1])), res$group)
  

предоставление:

                0    1
value1.min   1.0  2.0
value1.max   9.0 10.0
value2.min   1.0  2.0
value2.max   9.0 10.0
n           10.0 10.0
value3 == 1  0.4  0.4
value3 == 2  0.2  0.4
value3 == 3  0.4  0.2
  

skimr

Используя пакет skimr, мы можем сделать это:

 library(dplyr)
library(skimr)
library(tidyr)

# L <- list("fraction = 1" = function(x) mean(x == 1),
#           "fraction = 2" = function(x) mean(x == 2),
#           "fraction = 3" = function(x) mean(x == 3))
levs <- levels(data$value3)
L <- lapply(levs, function(lv) function(x) mean(x == lv))
names(L) <- paste("fraction =", levs)

skim_with(integer = list(min = min, max = max), 
 factor = c(L, n = length), append = FALSE)

data %>% 
  group_by(group) %>%
  skim %>%
  ungroup %>%
  select(group, variable, stat, value) %>%
  spread(group, value)
  

дает следующее:

 # A tibble: 8 x 4
  variable stat          `0`   `1`
  <chr>    <chr>       <dbl> <dbl>
1 value1   max           9    10  
2 value1   min           1     2  
3 value2   max           9    10  
4 value2   min           1     2  
5 value3   fracion = 1   0.4   0.4
6 value3   fracion = 2   0.2   0.4
7 value3   fracion = 3   0.4   0.2
8 value3   n            10    10  
  

Обновить

Пересмотренное базовое решение; добавлены решения sqldf и skimr. Улучшенное решение skimr.

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

1. большое спасибо, но на самом деле value3 является факторной переменной, поэтому возможно ли вместо min max сделать n и% для каждой из категорий, в том числе, если отсутствуют значения?

2. полностью переработано

Ответ №2:

Используя dplyr (>=0.8.0 синтаксис):

 library(dplyr)
df %>% 
  group_by(group) %>% 
  summarise_all(list(~min(.),~max(.)))
  

Результат:

 # A tibble: 2 x 7
  group value1_min value2_min value3_min value1_max value2_max value3_max
  <int>      <dbl>      <dbl>      <dbl>      <dbl>      <dbl>      <dbl>
1     0          1          1          1          9          9          3
2     1          2          2          1         10         10          3
  

Ответ №3:

Используя dplyr и tidyr :

 library(dplyr)
library(tidyr)

data %>%
  group_by(group) %>%
  summarize(value1_min = min(value1),
        value1_max = max(value1),
        value2_min = min(value2),
        value2_max = max(value2),
        value3_n = length(unique(value3)),
        value3_perc1 = length(sum(value3==1))/length(unique(value3)),
        value3_perc2 = length(sum(value3==2))/length(unique(value3)),
        value3_perc3 = length(sum(value3==3))/length(unique(value3))
        ) %>%
  gather(review, value, -group) %>%
  spread(group, value)
  

Результат:

 # A tibble: 7 x 3
  review         `0`    `1`
  <chr>        <dbl>  <dbl>
1 value1_max   9.00  10.0  
2 value1_min   1.00   2.00 
3 value2_max   9.00  10.0  
4 value2_min   1.00   2.00 
5 value3_n     3.00   3.00 
6 value3_perc1 0.333  0.333
7 value3_perc2 0.333  0.333
8 value3_perc3 0.333  0.333
  

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

1. Ошибка: var необходимо вычислить единственное число или имя столбца, а не целочисленный вектор