14

Вопрос по r – Основа обертывания R изменяет форму для удобства использования

Это общепризнанная истина, что базовая команда изменения формы R является быстрой и мощной, но имеет жалкий синтаксис. Поэтому я написал краткую обертку вокруг нее, которую я добавлю в следующий выпускtaRifx пакет. Однако прежде чем я это сделаю, ...

Для нас, не изменяющих форму пользователей, не могли бы вы прокомментировать разницу между этим расплавлением / переформатированием?

от Carl Witthoft

@CarlWitthoft Посмотреть этот вопрос (<a href="http://stackoverflow.com/questions/10161807/reshape-in-the-middle/" title="reshape in the middle">stackoverflow.com/questions/10161807/reshape-in-the-middle</a> ) для примера разницы - у reshape2 нет стандартного пути перехода от "wide" на «длинный», даже когда он создал «широкий» data.frame. Заметьте, что я не говорю это, чтобы критиковать reshape2, но только для того, чтобы указать, что reshape () очень удобна для конкретного (и общего) преобразования данных.

от Ari B. Friedman

@CarlWitthoft Это просто различие в метафоре.<code>melt</code>/<code>cast</code> очень мощные (вы можете использовать их для репликации изменить форму:<a href="http://stackoverflow.com/questions/10049602/reshaping-several-variables-wide-with-cast/10052790#10052790" title="reshaping several variables wide with cast">stackoverflow.com/questions/10049602/&#x2026;</a>), но иногда все, что вы хотите сделать, это взять прямоугольный набор данных от широкого до длинного. Эти примеры из Stata могут помочь проиллюстрировать:<a href="http://www.ats.ucla.edu/stat/stata/modules/reshapew.htm" rel="nofollow noreferrer">ats.ucla.edu/stat/stata/modules/reshapew.htm</a>

от Ari B. Friedman

4 ответа

3

Я также хотел бы видеть возможность упорядочить выходные данные, поскольку это одна из вещей, которые мне не нравятся в отношении изменения формы в базе R. В качестве примера, давайте использоватьМодуль обучения Stata: изменение данных от широкого к длинномус которым вы уже знакомы. Примером, на который я смотрю, является «рост и вес детей в возрасте 1 года и 2 года»; пример.

Вот что я обычно делаю сreshape():

# library(foreign)
kidshtwt = read.dta("http://www.ats.ucla.edu/stat/stata/modules/kidshtwt.dta")
kidshtwt.l = reshape(kidshtwt, direction="long", idvar=1:2, 
                     varying=3:6, sep="", timevar="age")
# The reshaped data is correct, just not in the order I want it
# so I always have to do another step like this
kidshtwt.l = kidshtwt.l[order(kidshtwt.l$famid, kidshtwt.l$birth),]

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

Я также предлагаю, по крайней мере, иметь возможность сделать то же самое с окончательным порядком столбцов для изменения формы изlong вwide.

Example function for column ordering

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

col.name.sort = function(data, patterns) {
  a = names(data)
  b = length(patterns)

  subs = vector("list", b)

  for (i in 1:b) {
    subs[[i]] = sort(grep(patterns[i], a, value=T))
    }
  x = unlist(subs)
  data[ , x ]
}

Это может быть использовано следующим образом. Представьте, что мы сохранили вывод вашегоreshapeasy long вwide Пример в качестве фрейма данных с именемaи мы хотели, чтобы он был упорядочен по запросу «surveyNum», «caremgmt» (1-3), "предыдущая" (1-3), «pio»; (1-3) и "цена" (1-3), мы могли бы использовать:

col.name.sort(a, c("sur", "car", "pre", "pio", "pri"))
2

Некоторые начальные мысли:

Я всегда думал, что команды направления "широкие" и "длинный" были немного нечеткими. Они означают, что вы хотите преобразовать данные в этот формат или данные уже в этом формате? Это то, что вам нужно учиться или искать. Вы можете избежать этой проблемы, разделив функцииreshapeToWide а такжеreshapeToLong, В качестве бонуса, подпись каждой функции имеет на один аргумент меньше.


Я не думаю, что вы хотели включить строку

varying <- which(!(colnames(x.wide) %in% "surveyNum"))

так как это относится к конкретному набору данных.


я предпочитаюdata вx для первого аргумента, поскольку он дает понять, что входные данные должны быть фреймом данных.


Обычно лучше иметь аргументы без значений по умолчанию. Такvars должен прийти послеid а такжеvary.


Можете ли вы выбрать значения по умолчанию дляid а такжеvary? reshape::melt по умолчанию используются факторные и символьные столбцы для идентификаторов и числовые столбцы для переменных.

2

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

  if (is.numeric(id) == 1) {
    id = colnames(data)[id]
  } else if (is.numeric(id) == 0) {
    id = id
  }

  if (is.numeric(vary) == 1) {
    vary = colnames(data)[vary]
  } else if (is.numeric(vary) == 0) {
    vary = vary
  }

Затем, следуя вашим примерам, вы можете использовать следующие сокращения:

reshapeasy(x.wide, direction="long", id=1, sep="_", vary="id")
reshapeasy(x.long, direction="wide", id=6, vary=1)

(Я знаю, что это может не быть хорошей практикой, поскольку код может быть менее читаемым или менее понятным для кого-то позже, но это часто случается.)

2

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

> reshapeasy( x.wide, "long", NULL, id="surveyNum", vary="id", sep="_" )
Error in gsub(paste("[", paste(omit, collapse = "", sep = ""), "]$", sep = ""),  : 
  invalid regular expression '[]$', reason 'Missing ']''

УдалениеNULL исправляет проблему. Что заставляет меня спросить, какова цель этогоNULL?

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

Смотри, например, следующее из базыreshpae():

> head(reshape(x.wide, direction="long", idvar=1, varying=2:13, sep="_"))
    surveyNum time pio caremgmt prev price
1.1         1    1   2        2    1     2
2.1         2    1   2        1    2     1
3.1         3    1   1        1    2     2
4.1         4    1   2        2    1     5
5.1         5    1   1        1    1     3
6.1         6    1   1        2    2     4

Если я знаком с этим и вижу, что ваша функция заботится о "различии" для меня, я мог бы попробовать:

> head(reshapeasy( x.wide, "long", id="surveyNum", sep="_" ))
Error in `row.names<-.data.frame`(`*tmp*`, value = paste(d[, idvar], times[1L],  : 
  duplicate 'row.names' are not allowed
In addition: Warning message:
non-unique value when setting 'row.names': ‘1.1’

Но это не очень полезная ошибка. Возможно, включение вашего сообщения об ошибке может быть полезным для вашей последней функции.

Разрешение пользователю устанавливать различныеNULLКак вы сделали в своей нынешней версии функции, мне это тоже не кажется разумным. Это дает вывод, как это:

> head(reshapeasy( x.wide, "long", id="surveyNum", NULL, sep="_" ))
    surveyNum pio caremgmt prev price
1.1         1   2        2    1     2
2.1         2   2        1    2     1
3.1         3   1        1    2     2
4.1         4   2        2    1     5
5.1         5   1        1    1     3
6.1         6   1        2    2     4

Проблема с этим выводом состоит в том, что если мне нужно изменить форму назад, я не смогу сделать это легко. Таким образом, я думаю, что сохранение измененной опции по умолчанию для генерацииtime переменная, но позволяющая пользователю переопределить это может быть полезной функцией.

Похожие вопросы