Поворот строк в столбцы
Предположим (для упрощения) у меня есть таблица, содержащая некоторые данные управления и лечения:
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);
}