Поворот строк в столбцы

Предположим (для упрощения) у меня есть таблица, содержащая некоторые данные управления и лечения:

Which, Color, Response, Count
Control, Red, 2, 10
Control, Blue, 3, 20
Treatment, Red, 1, 14
Treatment, Blue, 4, 21

Для каждого цвета я хочу одну строку с данными управления и обработки, то есть:

Color, Response.Control, Count.Control, Response.Treatment, Count.Treatment
Red, 2, 10, 1, 14
Blue, 3, 20, 4, 21

Я предполагаю, что одним из способов сделать это является использование внутреннего слияния для каждого подмножества управления/обработки (слияние в столбце "Цвет" ), но есть ли лучший способ? Я думал, что пакет reshape или функция стека могут каким-то образом сделать это, но я не уверен.

Ответ 1

Использование пакета reshape.

Во-первых, расплавьте данные data.frame:

x <- melt(df) 

Затем выполните следующие действия:

dcast(x, Color ~ Which + variable)

В зависимости от того, какая версия пакета reshape, с которым вы работаете, может быть cast() (изменить) или dcast() (reshape2)

Voila.

Ответ 2

Функция cast из пакета reshape (не путать с функцией reshape в базе R) может сделать это и многое другое. См. Здесь: http://had.co.nz/reshape/

Ответ 3

Чтобы добавить к вариантам (много лет спустя)....

Типичный подход в базе R будет включать функцию reshape (которая, как правило, непопулярна из-за множества аргументов, требующих времени для освоения). Это довольно эффективная функция для небольших наборов данных, но не всегда хорошо масштабируется.

reshape(mydf, direction = "wide", idvar = "Color", timevar = "Which")
#   Color Response.Control Count.Control Response.Treatment Count.Treatment
# 1   Red                2            10                  1              14
# 2  Blue                3            20                  4              21

Уже рассмотрены cast/dcast из "reshape" и "reshape2" (и теперь dcast.data.table из "data.table", особенно полезно, когда у вас есть большие наборы данных). Но также из Hadleyverse, там "tidyr", который прекрасно работает с пакетом "dplyr":

library(tidyr)
library(dplyr)
mydf %>%
  gather(var, val, Response:Count) %>%  ## make a long dataframe
  unite(RN, var, Which) %>%             ## combine the var and Which columns
  spread(RN, val)                       ## make the results wide
#   Color Count_Control Count_Treatment Response_Control Response_Treatment
# 1  Blue            20              21                3                  4
# 2   Red            10              14                2                  1

Также следует отметить, что в предстоящей версии "data.table" функция dcast.data.table должна иметь возможность обрабатывать это, не имея при этом первых melt ваших данных.

Реализация data.table dcast позволяет вам конвертировать несколько столбцов в широкий формат, не плавя сначала, а именно:

library(data.table)
dcast(as.data.table(mydf), Color ~ Which, value.var = c("Response", "Count"))
#    Color Response_Control Response_Treatment Count_Control Count_Treatment
# 1:  Blue                3                  4            20              21
# 2:   Red                2                  1            10              14

Ответ 4

Reshape действительно работает для поворота тощего кадра данных (например, от простого SQL-запроса) до широкой матрицы и очень гибкого, но медленного. Для больших объемов данных очень очень медленно. К счастью, если вы хотите только повернуть к фиксированной форме, довольно легко написать небольшую функцию C, чтобы быстро выполнить поворот.

В моем случае поворот тощего кадра данных с 3 столбцами и 672 338 строк занял 34 секунды с изменением, 25 секунд с моим R-кодом и 2,3 секунды с C. По иронии судьбы, реализация C, вероятно, была проще писать, чем моя ( настроенный на скорость). R-реализация.

Здесь основной код C для поворота чисел с плавающей запятой. Обратите внимание, что предполагается, что вы уже присвоили матрицу результатов с правильным размером в R перед вызовом кода C, что заставляет людей R-devel содрогаться от ужаса:

#include <R.h> 
#include <Rinternals.h> 
/* 
 * This mutates the result matrix in place.
 */
SEXP
dtk_pivot_skinny_to_wide(SEXP n_row  ,SEXP vi_1  ,SEXP vi_2  ,SEXP v_3  ,SEXP result)
{
   int ii, max_i;
   unsigned int pos;
   int nr = *INTEGER(n_row);
   int * aa = INTEGER(vi_1);
   int * bb = INTEGER(vi_2);
   double * cc = REAL(v_3);
   double * rr = REAL(result);
   max_i = length(vi_2);
   /*
    * R stores matrices by column.  Do ugly pointer-like arithmetic to
    * map the matrix to a flat vector.  We are translating this R code:
    *    for (ii in 1:length(vi.2))
    *       result[((n.row * (vi.2[ii] -1)) + vi.1[ii])] <- v.3[ii]
    */
   for (ii = 0; ii < max_i; ++ii) {
      pos = ((nr * (bb[ii] -1)) + aa[ii] -1);
      rr[pos] = cc[ii];
      /* printf("ii: %d \t value: %g \t result index:  %d \t new value: %g\n", ii, cc[ii], pos, rr[pos]); */
   }
   return(result);
}