Поиск…


замечания

Официальная виньетка «Эффективная перестройка с использованием data.tables» - лучшее введение в эту тему.

Многие задачи перестройки требуют перехода между длинными и широкими форматами:

  • Широкие данные - это данные с каждым столбцом, представляющим отдельную переменную, а строки, представляющие отдельные наблюдения
  • Длинные данные - это данные с идентификатором формы | переменная | значение, где каждая строка, представляющая пару переменных наблюдения

расплав и литье с данными.table

data.table предлагает широкий спектр возможностей для изменения ваших данных как эффективно, так и легко

Например, при изменении формы от long to wide вы можете передавать несколько переменных в value.var и в параметры fun.aggregate одновременно

library(data.table) #v>=1.9.6
DT <- data.table(mtcars)

Длинные

dcast(DT, gear ~ cyl, value.var = c("disp", "hp"), fun = list(mean, sum))
   gear disp_mean_4 disp_mean_6 disp_mean_8 hp_mean_4 hp_mean_6 hp_mean_8 disp_sum_4 disp_sum_6 disp_sum_8 hp_sum_4 hp_sum_6 hp_sum_8
1:    3     120.100       241.5    357.6167        97     107.5  194.1667      120.1      483.0     4291.4       97      215     2330
2:    4     102.625       163.8         NaN        76     116.5       NaN      821.0      655.2        0.0      608      466        0
3:    5     107.700       145.0    326.0000       102     175.0  299.5000      215.4      145.0      652.0      204      175      599

Это установит gear как индексную колонку, тогда как mean и sum будут рассчитаны для disp и hp для каждой комбинации gear и cyl . В случае, если некоторые комбинации не существуют, вы можете указать дополнительные параметры, такие как na.rm = TRUE (которые будут переданы в mean и sum функции) или указать встроенный аргумент fill . Вы также можете добавлять поля, оставлять недостающие комбинации и подмножество данных. См. Больше в ?data.table::dcast


Широкий и длинный

При перестройке с широким и длинным вы можете передавать столбцы в параметр measure.vars используя регулярные выражения, например

print(melt(DT, c("cyl", "gear"), measure = patterns("^d", "e")), n = 10)
    cyl gear variable value1 value2
 1:   6    4        1 160.00  16.46
 2:   6    4        1 160.00  17.02
 3:   4    4        1 108.00  18.61
 4:   6    3        1 258.00  19.44
 5:   8    3        1 360.00  17.02
---                                
60:   4    5        2   3.77   5.00
61:   8    5        2   4.22   5.00
62:   6    5        2   3.62   5.00
63:   8    5        2   3.54   5.00
64:   4    4        2   4.11   4.00

Это будет melt данные по cyl и gear в качестве столбцов индекса, в то время как все значения для переменных , которые начинаются с d ( disp & drat ) будет присутствовать в value1 и значения для переменных , которые содержат букву e в них ( qsec и gear ) будут присутствовать в столбце value2 .

Вы также можете переименовать все имена столбцов в результате при указании аргументов variable.name и value.name или решить, хотите ли вы, чтобы столбцы character были автоматически преобразованы в factor s или нет при определении аргументов variable.factor и value.factor . См. Больше в ?data.table::melt

Изменить форму с помощью `data.table`

data.table расширяет функции reshape2 melt & dcast

( Ссылка: эффективная перестройка с использованием data.tables )

library(data.table)

## generate some data
dt <- data.table(
  name = rep(c("firstName", "secondName"), each=4),
  numbers = rep(1:4, 2),
  value = rnorm(8)
)
dt
#          name numbers      value
# 1:  firstName       1 -0.8551881
# 2:  firstName       2 -1.0561946
# 3:  firstName       3  0.2671833
# 4:  firstName       4  1.0662379
# 5: secondName       1 -0.4771341
# 6: secondName       2  1.2830651
# 7: secondName       3 -0.6989682
# 8: secondName       4 -0.6592184

Длинные

dcast(data = dt, 
      formula = name ~ numbers, 
      value.var = "value")

#          name          1          2         3         4
# 1:  firstName  0.1836433 -0.8356286 1.5952808 0.3295078
# 2: secondName -0.8204684  0.4874291 0.7383247 0.5757814

В нескольких столбцах (с data.table таблицы 1.9.6)

## add an extra column
dt[, value2 := value * 2]

## cast multiple value columns
dcast(data = dt, 
      formula = name ~ numbers, 
      value.var = c("value", "value2"))

#          name    value_1    value_2   value_3   value_4   value2_1   value2_2 value2_3  value2_4
# 1:  firstName  0.1836433 -0.8356286 1.5952808 0.3295078  0.3672866 -1.6712572 3.190562 0.6590155
# 2: secondName -0.8204684  0.4874291 0.7383247 0.5757814 -1.6409368  0.9748581 1.476649 1.1515627

Широкий и длинный

## use a wide data.table
dt <- fread("name          1          2         3         4
firstName  0.1836433 -0.8356286 1.5952808 0.3295078
secondName -0.8204684  0.4874291 0.7383247 0.5757814", header = T)
dt
#          name          1          2         3         4
# 1:  firstName  0.1836433 -0.8356286 1.5952808 0.3295078
# 2: secondName -0.8204684  0.4874291 0.7383247 0.5757814

## melt to long, specifying the id column, and the name of the columns 
## in the resulting long data.table
melt(dt, 
     id.vars = "name", 
     variable.name = "numbers",
     value.name = "myValue")
#          name  numbers    myValue
# 1:  firstName        1  0.1836433
# 2: secondName        1 -0.8204684
# 3:  firstName        2 -0.8356286
# 4: secondName        2  0.4874291
# 5:  firstName        3  1.5952808
# 6: secondName        3  0.7383247
# 7:  firstName        4  0.3295078
# 8: secondName        4  0.5757814

Переход от широкого до длинного формата с использованием расплава

Плавление: основы

Плавление используется для преобразования данных с широкоформатного формата.

Начиная с широкого набора данных:

DT = data.table(ID = letters[1:3], Age = 20:22, OB_A = 1:3, OB_B = 4:6, OB_C = 7:9)

Мы можем расплавить наши данные, используя функцию melt в таблице данных. Это возвращает другую таблицу данных в длинном формате:

melt(DT, id.vars = c("ID","Age"))
1:  a  20     OB_A     1
2:  b  21     OB_A     2
3:  c  22     OB_A     3
4:  a  20     OB_B     4
5:  b  21     OB_B     5
6:  c  22     OB_B     6
7:  a  20     OB_C     7
8:  b  21     OB_C     8
9:  c  22     OB_C     9

class(melt(DT, id.vars = c("ID","Age")))
# "data.table" "data.frame"

Любые столбцы, не заданные в параметре id.vars считаются переменными. В качестве альтернативы мы можем установить их явно с measure.vars аргумента measure.vars :

melt(DT, measure.vars = c("OB_A","OB_B","OB_C"))
   ID Age variable value
1:  a  20     OB_A     1
2:  b  21     OB_A     2
3:  c  22     OB_A     3
4:  a  20     OB_B     4
5:  b  21     OB_B     5
6:  c  22     OB_B     6
7:  a  20     OB_C     7
8:  b  21     OB_C     8
9:  c  22     OB_C     9

В этом случае любые столбцы, не установленные в measure.vars считаются идентификаторами.

Если мы установим оба явно, он вернет только выбранные столбцы:

melt(DT, id.vars = "ID", measure.vars = c("OB_C"))
   ID variable value
1:  a     OB_C     7
2:  b     OB_C     8
3:  c     OB_C     9

Именование переменных и значений в результате

Мы можем манипулировать именами столбцов возвращаемой таблицы с помощью variable.name и value.name

melt(DT,
     id.vars = c("ID"), 
     measure.vars = c("OB_C"), 
     variable.name = "Test", 
     value.name = "Result"
     )
   ID Test Result
1:  a OB_C      7
2:  b OB_C      8
3:  c OB_C      9

Настройка типов для переменных измерения в результате

По умолчанию, таяние data.table преобразует все measure.vars в факторы:

M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"))
class(M_DT[, variable])
# "factor"

Чтобы вместо этого указать символ, используйте аргумент variable.factor :

M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"), variable.factor = FALSE)
class(M_DT[, variable])
# "character"

Значения, как правило, наследуются от типа данных исходного столбца:

class(DT[, value])
# "integer"
class(M_DT[, value])
# "integer"

Если есть конфликт, типы данных будут принуждаться. Например:

M_DT <- melt(DT,id.vars = c("Age"), measure.vars = c("ID","OB_C"))
class(M_DT[, value])
# "character"

При плавлении любые фактор-переменные будут принуждаться к типу символа:

DT[, OB_C := factor(OB_C)]
M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"))
class(M_DT)
# "character"

Чтобы избежать этого и сохранить начальное типирование, используйте аргумент value.factor :

M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"), value.factor = TRUE)
class(M_DT)
# "factor"

Обработка отсутствующих значений

По умолчанию любые значения NA сохраняются в расплавленных данных

DT = data.table(ID = letters[1:3], Age = 20:22, OB_A = 1:3, OB_B = 4:6, OB_C = c(7:8,NA))
melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"))
   ID variable value
1:  a     OB_C     7
2:  b     OB_C     8
3:  c     OB_C    NA

Если они должны быть удалены из ваших данных, установите na.rm = TRUE

melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"), na.rm = TRUE)
   ID variable value
1:  a     OB_C     7
2:  b     OB_C     8

Переход от длинного к широкому формату с использованием dcast

Кастинг: Основы

Кастинг используется для преобразования данных из длинного в широкий формат.

Начиная с длинного набора данных:

DT = data.table(ID = rep(letters[1:3],3), Age = rep(20:22,3), Test = rep(c("OB_A","OB_B","OB_C"), each = 3), Result = 1:9)

Мы можем отливать наши данные , используя dcast функции в data.table. Это возвращает другую таблицу данных в широком формате:

dcast(DT, formula = ID ~ Test, value.var = "Result")
   ID OB_A OB_B OB_C
1:  a    1    4    7
2:  b    2    5    8
3:  c    3    6    9

class(dcast(DT, formula = ID ~ Test, value.var = "Result"))
[1] "data.table" "data.frame"

Значение ценности

Аргумент value.var необходим для правильного приведения - если не предусмотрено, dcast сделает предположение на основе ваших данных.

dcast(DT, formula = ID ~ Test, value.var = "Result")
   ID OB_A OB_B OB_C
1:  a    1    4    7
2:  b    2    5    8
3:  c    3    6    9

   ID OB_A OB_B OB_C
1:  a   20   20   20
2:  b   21   21   21
3:  c   22   22   22

В value.var можно value.var несколько value.var s

dcast(DT, formula = ID ~ Test, value.var = list("Result","Age"))
   ID Result_OB_A Result_OB_B Result_OB_C Age_OB_A Age_OB_B Age_OB_C
1:  a           1           4           7       20       20       20
2:  b           2           5           8       21       21       21
3:  c           3           6           9       22       22       22

формула

Кастинг контролируется с помощью аргумента формулы в dcast . Это имеет вид ROWS ~ COLUMNS

dcast(DT, formula = ID ~ Test, value.var = "Result")
   ID OB_A OB_B OB_C
1:  a    1    4    7
2:  b    2    5    8
3:  c    3    6    9

dcast(DT, formula = Test ~ ID, value.var = "Result")
   Test a b c
1: OB_A 1 2 3
2: OB_B 4 5 6
3: OB_C 7 8 9

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

dcast(DT, formula = ID + Age ~ Test, value.var = "Result")
   ID Age OB_A OB_B OB_C
1:  a  20    1    4    7
2:  b  21    2    5    8
3:  c  22    3    6    9

dcast(DT, formula = ID ~ Age + Test, value.var = "Result")
   ID 20_OB_A 20_OB_B 20_OB_C 21_OB_A 21_OB_B 21_OB_C 22_OB_A 22_OB_B 22_OB_C
1:  a       1       4       7      NA      NA      NA      NA      NA      NA
2:  b      NA      NA      NA       2       5       8      NA      NA      NA
3:  c      NA      NA      NA      NA      NA      NA       3       6       9

#order is important

dcast(DT, formula = ID ~ Test + Age, value.var = "Result")
   ID OB_A_20 OB_A_21 OB_A_22 OB_B_20 OB_B_21 OB_B_22 OB_C_20 OB_C_21 OB_C_22
1:  a       1      NA      NA       4      NA      NA       7      NA      NA
2:  b      NA       2      NA      NA       5      NA      NA       8      NA
3:  c      NA      NA       3      NA      NA       6      NA      NA       9

Кастинг часто может создавать ячейки, где в данных не наблюдается наблюдения. По умолчанию это обозначается NA , как указано выше. Мы можем переопределить это с помощью аргумента fill= .

dcast(DT, formula = ID ~ Test + Age, value.var = "Result", fill = 0)
   ID OB_A_20 OB_A_21 OB_A_22 OB_B_20 OB_B_21 OB_B_22 OB_C_20 OB_C_21 OB_C_22
1:  a       1       0       0       4       0       0       7       0       0
2:  b       0       2       0       0       5       0       0       8       0
3:  c       0       0       3       0       0       6       0       0       9

Вы также можете использовать две специальные переменные в объекте формулы

  • . не представляет никаких других переменных
  • ... представляет все остальные переменные
dcast(DT, formula = Age ~ ., value.var = "Result")
   Age .
1:  20 3
2:  21 3
3:  22 3

dcast(DT, formula = ID + Age ~ ..., value.var = "Result")
   ID Age OB_A OB_B OB_C
1:  a  20    1    4    7
2:  b  21    2    5    8
3:  c  22    3    6    9

Совокупность нашего значения.

Мы также можем приводить и агрегировать значения за один шаг. В этом случае у нас есть три наблюдения на каждом из пересечений Age и ID. Чтобы установить то, что мы хотим, мы используем аргумент fun.aggregate :

#length
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = length)
   ID 20 21 22
1:  a  3  0  0
2:  b  0  3  0
3:  c  0  0  3

#sum
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = sum)
   ID 20 21 22
1:  a 12  0  0
2:  b  0 15  0
3:  c  0  0 18

#concatenate
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = function(x){paste(x,collapse = "_")})
ID    20    21    22
1:  a 1_4_7            
2:  b       2_5_8      
3:  c             3_6_9

Мы также можем передать список для fun.aggregate чтобы использовать несколько функций

dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = list(sum,length))
   ID Result_sum_20 Result_sum_21 Result_sum_22 Result_length_20 Result_length_21 Result_length_22
1:  a            12             0             0                3                0                0
2:  b             0            15             0                0                3                0
3:  c             0             0            18                0                0                3

Если мы передаем более одной функции и более одного значения, мы можем вычислить все комбинации, передав вектор value.vars

dcast(DT, formula = ID ~ Age, value.var = c("Result","Test"), fun.aggregate = list(function(x){paste0(x,collapse = "_")},length))
   ID Result_function_20 Result_function_21 Result_function_22 Test_function_20 Test_function_21 Test_function_22 Result_length_20 Result_length_21
1:  a              1_4_7                                         OB_A_OB_B_OB_C                                                  3                0
2:  b                                 2_5_8                                       OB_A_OB_B_OB_C                                 0                3
3:  c                                                    3_6_9                                     OB_A_OB_B_OB_C                0                0
   Result_length_22 Test_length_20 Test_length_21 Test_length_22
1:                0              3              0              0
2:                0              0              3              0
3:                3              0              0              3

где каждая пара вычисляется в value1_formula1, value1_formula2, ... , valueN_formula(N-1), valueN_formulaN .

В качестве альтернативы мы можем оценивать наши значения и функции взаимно однозначно, передавая «value.var» в виде списка:

dcast(DT, formula = ID ~ Age, value.var = list("Result","Test"), fun.aggregate = list(function(x){paste0(x,collapse = "_")},length))
   ID Result_function_20 Result_function_21 Result_function_22 Test_length_20 Test_length_21 Test_length_22
1:  a              1_4_7                                                    3              0              0
2:  b                                 2_5_8                                 0              3              0
3:  c                                                    3_6_9              0              0              3

Именование столбцов в результате

По умолчанию компоненты имени столбца разделяются символом подчеркивания _ . Это можно вручную переопределить с помощью аргумента sep= :

dcast(DT, formula = Test ~ ID + Age, value.var = "Result")
Test a_20 b_21 c_22
1: OB_A    1    2    3
2: OB_B    4    5    6
3: OB_C    7    8    9

dcast(DT, formula = Test ~ ID + Age, value.var = "Result", sep = ",")
   Test a,20 b,21 c,22
1: OB_A    1    2    3
2: OB_B    4    5    6
3: OB_C    7    8    9

Это будет fun.aggregate любые fun.aggregate или value.var мы используем:

dcast(DT, formula = Test ~ ID + Age, value.var = "Result", fun.aggregate = c(sum,length), sep = ",")
   Test Result,sum,a,20 Result,sum,b,21 Result,sum,c,22 Result,length,a,20 Result,length,b,21 Result,length,c,22
1: OB_A               1               2               3                  1                  1                  1
2: OB_B               4               5               6                  1                  1                  1
3: OB_C               7               8               9                  1                  1                  1

Укладка нескольких таблиц с помощью rbindlist

Общий рефрен в R идет по этим линиям:

У вас не должно быть кучи связанных таблиц с такими именами, как DT1 , DT2 , ..., DT11 . Итеративное чтение и назначение объектов по имени беспорядочно. Решение представляет собой список таблиц данных!

Такой список выглядит

set.seed(1)
DT_list = lapply(setNames(1:3, paste0("D", 1:3)), function(i)
  data.table(id = 1:2, v = sample(letters, 2)))

$D1
   id v
1:  1 g
2:  2 j

$D2
   id v
1:  1 o
2:  2 w

$D3
   id v
1:  1 f
2:  2 w

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

DT = rbindlist(DT_list, id="src")

   src id v
1:  D1  1 g
2:  D1  2 j
3:  D2  1 o
4:  D2  2 w
5:  D3  1 f
6:  D3  2 w

Этот формат дает больше смысла с синтаксисом data.table, где операции «по группам» являются общими и понятными.

Для более глубокого взгляда ответ Грегора может быть хорошим началом. ?rbindlist , ?rbindlist . Есть отдельный пример, охватывающий чтение в кучу таблиц из CSV, а затем их укладку .



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow