Как изменить форму данных из длинного в широкий формат?


у меня возникли проблемы с перестановкой следующего фрейма данных:

set.seed(45)
dat1 <- data.frame(
    name = rep(c("firstName", "secondName"), each=4),
    numbers = rep(1:4, 2),
    value = rnorm(8)
    )

dat1
       name  numbers      value
1  firstName       1  0.3407997
2  firstName       2 -0.7033403
3  firstName       3 -0.3795377
4  firstName       4 -0.7460474
5 secondName       1 -0.8981073
6 secondName       2 -0.3347941
7 secondName       3 -0.5013782
8 secondName       4 -0.1745357

Я хочу изменить его так, чтобы каждая уникальная переменная "имя" была именем строки, с "значениями" в качестве наблюдений вдоль этой строки и "числами" в качестве colnames. Примерно так:

     name          1          2          3         4
1  firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
5 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

Я посмотрел на melt и cast и несколько других вещей, но никто, кажется, чтобы сделать работу.

9 187

9 ответов:

используя reshape функция:

reshape(dat1, idvar = "name", timevar = "numbers", direction = "wide")

новый (2014 года) tidyr пакет также делает это просто, с gather()/spread() будучи термины для melt/cast.

library(tidyr)
spread(dat1, key = numbers, value = value)

С github,

tidyr - это рефрейминг reshape2 конструировал сопроводить аккуратную структуру данных, и работать рука об руку с magrittr и dplyr построить твердый трубопровод для анализа данных.

как reshape2 меньше, чем перекраивать, tidyr не менее reshape2. Он разработан специально для очистки данных, а не общей перестройки, что reshape2 делает, или общее агрегирование, которое изменило форму. В частности, встроенные методы работают только для фреймов данных, и tidyr не предоставляет никаких полей или агрегации.

вы можете сделать это с помощью

другой вариант, если производительность является проблемой, чтобы использовать data.table расширение reshape2 ' s melt & dcast функции

(ссылка: эффективное изменение формы с использованием данных.таблицы)

library(data.table)

setDT(dat1)
dcast(dat1, 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

и, по данным.таблица v1.9. 6 мы можем привести на несколько столбцов

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

## cast multiple value columns
dcast(dat1, 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

используя Ваш пример фрейма данных, мы могли бы:

xtabs(value ~ name + numbers, data = dat1)

другие два варианта:

базовый пакет:

df <- unstack(dat1, form = value ~ numbers)
rownames(df) <- unique(dat1$name)
df

sqldf пакет:

library(sqldf)
sqldf('SELECT name,
      MAX(CASE WHEN numbers = 1 THEN value ELSE NULL END) x1, 
      MAX(CASE WHEN numbers = 2 THEN value ELSE NULL END) x2,
      MAX(CASE WHEN numbers = 3 THEN value ELSE NULL END) x3,
      MAX(CASE WHEN numbers = 4 THEN value ELSE NULL END) x4
      FROM dat1
      GROUP BY name')

использование базы R aggregate функция:

aggregate(value ~ name, dat1, I)

# name           value.1  value.2  value.3  value.4
#1 firstName      0.4145  -0.4747   0.0659   -0.5024
#2 secondName    -0.8259   0.1669  -0.8962    0.1681

есть очень мощный новый пакет от genius data scientists в Win-Vector (люди, которые сделали vtreat,seplyr и replyr) позвонил cdata. Он реализует принципы "скоординированных данных", описанные в документ в этой блоге. Идея заключается в том, что независимо от того, как вы организуете свои данные, должно быть возможно идентифицировать отдельные точки данных с помощью системы "координат данных". Вот отрывок из недавнего поста в блоге Джона Гора:

вся система основана на двух примитивах или операторах cdata::moveValuesToRowsD() и cdata:: moveValuesToColumnsD(). Эти операторы поворота, ООН-поворотные, одна-горячая кодирования, транспонировать, двигаясь несколько строк и столбцов, а также многие другие преобразования, как простые специальные случаи.

легко написать много различных операций с точки зрения примитивы cdata. Эти операторы могут работать-в памяти или на больших данных масштаб (с базами данных и Apache Spark; для больших данных используйте cdata:: moveValuesToRowsN () и cdata:: moveValuesToColumnsN() варианты.) Преобразования управляются управляющей таблицей, которая сама по себе является диаграммой (или картиной) преобразования.

сначала мы построим таблицу управления (см. блоге для деталей), а затем выполните перемещение данных из строк в столбцы.

library(cdata)
# first build the control table
pivotControlTable <- buildPivotControlTableD(table = dat1, # reference to dataset
                        columnToTakeKeysFrom = 'numbers', # this will become column headers
                        columnToTakeValuesFrom = 'value', # this contains data
                        sep="_")                          # optional for making column names

# perform the move of data to columns
dat_wide <- moveValuesToColumnsD(tallTable =  dat1, # reference to dataset
                    keyColumns = c('name'),         # this(these) column(s) should stay untouched 
                    controlTable = pivotControlTable# control table above
                    ) 
dat_wide

#>         name  numbers_1  numbers_2  numbers_3  numbers_4
#> 1  firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
#> 2 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

базовый reshape функция работает отлично:

df <- data.frame(
  year   = c(rep(2000, 12), rep(2001, 12)),
  month  = rep(1:12, 2),
  values = rnorm(24)
)
df_wide <- reshape(df, idvar="year", timevar="month", v.names="values", direction="wide", sep="_")
df_wide

здесь

  • idvar это столбец классов, который разделяет строки
  • timevar это столбец классов, чтобы бросить широкий
  • v.names столбец, содержащий числовые значения
  • direction указывает широкий или длинный формат
  • необязательный элемент - это! Элемент timevar и v.names часть очень легко. Выход этой функции более предсказуем, чем некоторые другие, поскольку все явно определено.