У меня есть следующий фрейм данных (с тысячами столбцов):

df<- structure(c(1, 2, 2, 1, 2, 2, 2, 1, 3, 3, 2, 2), 
              .Dim = 4:3, .Dimnames = list(c("a", "b", "c", "d"), 
               c("t1", "t2", "t3")))

Какой эффективный способ получить среднее значение для каждых двух рядов?

Результат хочу:

     t1 t2 t3
a    1  2  3
b    2  2  3
a_b  1.5 2 3
c    2  2  2
d    1  1  2
c_d  1.5 1.5 2
1
MAPK 2 Май 2019 в 22:48

5 ответов

Лучший ответ

Разделить на 2 строки, затем получить среднее значение для каждого столбца, и rbind, и снова rbind все.

do.call(rbind,
        lapply(seq(1, nrow(df), 2), function(i){
          x <- df[ i:(i + 1), , drop = FALSE]
          res <- rbind(x, colSums(x)/2)
          rownames(res)[ nrow(res) ] <- paste(rownames(x), collapse = "_")
          res
        }))

#      t1  t2 t3
# a   1.0 2.0  3
# b   2.0 2.0  3
# a_b 1.5 2.0  3
# c   2.0 2.0  2
# d   1.0 1.0  2
# c_d 1.5 1.5  2
4
zx8754 2 Май 2019 в 20:36

Одна dplyr возможность может быть:

df %>%
 data.frame() %>%
 rownames_to_column() %>%
 mutate_if(is.factor, as.numeric) %>%
 group_by(group = gl(n()/2, 2)) %>%
 group_map(~ bind_rows(.x, tibble(rowname = paste(.x$rowname, collapse = "_"), 
                                  t1 = mean(.x$t1),
                                  t2 = mean(.x$t2),
                                  t3 = mean(.x$t3)))) %>%
 ungroup() %>%
 select(-group)

  rowname    t1    t2    t3
  <chr>   <dbl> <dbl> <dbl>
1 a         1     2       2
2 b         2     2       2
3 a_b       1.5   2       2
4 c         2     2       1
5 d         1     1       1
6 c_d       1.5   1.5     1

Первые три строки могут быть опущены, если вы создадите их заранее как data.frame, с именами в виде столбца и с факторами в качестве числовых переменных. Затем он сначала создает группирующие переменные с помощью gl(). Во-вторых, он вычисляет средние значения, создает имя как комбинацию двух элементов в группе и связывает его с исходными данными. Наконец, он разгруппируется и удаляет избыточную переменную.

2
tmfmnk 2 Май 2019 в 20:22

Еще один dplyr подход.
Обновление . Если вам действительно нужны имена строк (a, b, a_b и т. д.), посмотрите после моего исходного решения масштабируемое, но более запутанное, версия.

Исходный

df <- df %>% as_tibble()
n <- nrow(df)/2
orig <- df %>% mutate(grp = sort(rep(1:2, n)))
means <- orig %>% group_by(grp) %>% summarise_all(mean)

bind_rows(orig, means) %>% arrange(grp) %>% select(-grp)

Выход:

# A tibble: 6 x 3
     t1    t2    t3
  <dbl> <dbl> <dbl>
1   1     2       3
2   2     2       3
3   1.5   2       3
4   2     2       2
5   1     1       2
6   1.5   1.5     2

Обновлено с именами строк

rnames <- row.names(df)
df <- df %>% as_tibble() 

n <- (nrow(df)/2)

orig <- df %>% 
  mutate(grp = sort(rep(1:n, n)), rn = rnames)

means <- orig %>% 
  group_by(grp) %>% 
  mutate(rn = paste0(rn, collapse="_")) %>%
  ungroup() %>%
  group_by(rn) %>%
  summarise_if(is.numeric, mean)

bind_rows(orig, means) %>% arrange(grp) %>% select(-grp)

Выход:

     t1    t2    t3 rn   
  <dbl> <dbl> <dbl> <chr>
1   1     2       3 a    
2   2     2       3 b    
3   1.5   2       3 a_b  
4   2     2       2 c    
5   1     1       2 d    
6   1.5   1.5     2 c_d  
1
andrew_reece 2 Май 2019 в 20:54

Одна из возможностей - использовать пакет dplyr. Обратите внимание, что данные, которые я использую, немного отличаются от данных, которые вы используете: в ваших данных цифры на самом деле являются символьными значениями.

df <- structure(c(1, 2, 2, 1, 2, 2, 2, 1, 3, 3, 2, 2), 
               .Dim = 4:3, .Dimnames = list(c("a", "b", "c", "d"), 
                                            c("t1", "t2", "t3")))

Сначала я создаю сводку (которая содержит средства).

    library(dplyr)
    df_summary <- df %>% as_tibble(rownames = "names") %>% 
      group_by(ceiling(1:n() / 2)) %>% 
      summarise(names = paste(names, collapse = "_"),
                t1 = mean(t1),
                t2 = mean(t2),
                t3 = mean(t3)) %>% 
      select(-1)
    # A tibble: 2 x 4
      names    t1    t2    t3
      <chr> <dbl> <dbl> <dbl>
    1 a_b     1.5   2       3
    2 c_d     1.5   1.5     2

Затем я объединяю сводные данные с исходными данными:

 df_summary %>% bind_rows(df %>% as_tibble(rownames = "names")) %>% 
  slice(3, 4, 1, 5, 6, 2)
# A tibble: 6 x 4
  names    t1    t2    t3
  <chr> <dbl> <dbl> <dbl>
1 a       1     2       3
2 b       2     2       3
3 a_b     1.5   2       3
4 c       2     2       2
5 d       1     1       2
6 c_d     1.5   1.5     2
0
Cettt 2 Май 2019 в 20:12

base R решение, которое работает с любым количеством столбцов

M <- matrix(unlist(c(df)), ncol = 2, byrow = TRUE)
M <- cbind(M, rowMeans(M))
M <- matrix(c(t(M)),ncol = ncol(df), byrow = FALSE)

# add row names and column names 
row.names <- matrix(rownames(df), ncol = 2 ,byrow = TRUE)
rownames(M) <- c(t(cbind(row.names, apply(row.names,1, paste, collapse = "_"))))
colnames(M) <- colnames(df)


#        t1   t2   t3
#  a    1.0  2.0    3
#  b    2.0  2.0    3
#  a_b  1.5  2.0    3
#  c    2.0  2.0    2
#  d    1.0  1.0    2
#  c_d  1.5  1.5    2
1
Daniel 2 Май 2019 в 20:44