2010-02-02 2 views
77

У меня есть некоторые проблемы с преобразованием моего data.frame из широкого стола в длинный стол. На данный момент это выглядит следующим образом:Переформатирование данных из кадра в длинный формат

Code Country  1950 1951 1952 1953 1954 
AFG Afghanistan 20,249 21,352 22,532 23,557 24,555 
ALB Albania  8,097 8,986 10,058 11,123 12,246 

Теперь я хотел бы превратить этот data.frame в длинную data.frame. Что-то вроде этого:

Code Country  Year Value 
AFG Afghanistan 1950 20,249 
AFG Afghanistan 1951 21,352 
AFG Afghanistan 1952 22,532 
AFG Afghanistan 1953 23,557 
AFG Afghanistan 1954 24,555 
ALB Albania  1950 8,097 
ALB Albania  1951 8,986 
ALB Albania  1952 10,058 
ALB Albania  1953 11,123 
ALB Albania  1954 12,246 

Я посмотрел и попробовал уже с melt() и reshape() функций как некоторые люди предлагали на подобные вопросы. Однако до сих пор я получаю грязные результаты.

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

+1

Не знаю, если это была проблема, но функции в пакете перекроить в расплаве и литья –

+0

И пакет Reshape был заменен reshape2. –

+2

И теперь reshape2 был заменен тидиром. – drhagen

ответ

54

reshape() занимает некоторое время, чтобы привыкнуть, так же, как melt/cast. Вот решение с перекроить, предполагается, что ваш кадр данных называется d:

reshape(d, direction = "long", varying = list(names(d)[3:7]), v.names = "Value", 
     idvar = c("Code","Country"), timevar = "Year", times = 1950:1954) 
27

Использование RESHAPE пакет:

#data 
x <- read.table(textConnection(
"Code Country  1950 1951 1952 1953 1954 
AFG Afghanistan 20,249 21,352 22,532 23,557 24,555 
ALB Albania  8,097 8,986 10,058 11,123 12,246"), header=TRUE) 

library(reshape) 

x2 <- melt(x, id = c("Code", "Country"), variable_name = "Year") 
x2[,"Year"] <- as.numeric(gsub("X", "" , x2[,"Year"])) 
64

три альтернативных решения:

1: С reshape2

library(reshape2) 
long <- melt(wide, id.vars = c("Code", "Country")) 

даяние:

Code  Country variable value 
1 AFG Afghanistan  1950 20,249 
2 ALB  Albania  1950 8,097 
3 AFG Afghanistan  1951 21,352 
4 ALB  Albania  1951 8,986 
5 AFG Afghanistan  1952 22,532 
6 ALB  Albania  1952 10,058 
7 AFG Afghanistan  1953 23,557 
8 ALB  Albania  1953 11,123 
9 AFG Afghanistan  1954 24,555 
10 ALB  Albania  1954 12,246 

Некоторые альтернативные обозначения, которые дают тот же результат:

# you can also define the id-variables by column number 
melt(wide, id.vars = 1:2) 

# as an alternative you can also specify the measure-variables 
# all other variables will then be used as id-variables 
melt(wide, measure.vars = 3:7) 
melt(wide, measure.vars = as.character(1950:1954)) 

2: С data.table

Вы можете использовать ту же функцию, что и melt в reshape2 пакета (который является расширенной & улучшенной реализации). melt от data.table имеет также больше параметров, которые melt от reshape2.Вы можете для exaple также указать имя переменной-столбца:

library(data.table) 
long <- melt(setDT(wide), id.vars=c("Code","Country"), variable.name="year") 

Некоторые альтернативные обозначения:

melt(setDT(wide), id.vars = 1:2, variable.name = "year") 
melt(setDT(wide), measure.vars = 3:7, variable.name = "year") 
melt(setDT(wide), measure.vars = as.character(1950:1954), variable.name = "year") 

3: С tidyr

library(tidyr) 
long <- wide %>% gather(year, value, -c(Code, Country)) 

некоторых альтернативных обозначений:

wide %>% gather(year, value, -Code, -Country) 
wide %>% gather(year, value, -1:-2) 
wide %>% gather(year, value, -(1:2)) 
wide %>% gather(year, value, -1, -2) 
wide %>% gather(year, value, 3:7) 
wide %>% gather(year, value, `1950`:`1954`) 

Если вы хотите исключить NA значения, вы можете добавить na.rm = TRUE к melt, а также gather функций.


Другая проблема с данными в том, что значения будут прочитаны R в качестве символьных значений (в результате , в числах). Вы можете исправить это с gsub и as.numeric:

long$value <- as.numeric(gsub(",", "", long$value)) 

или непосредственно с data.table или dplyr:

# data.table 
long <- melt(setDT(wide), 
      id.vars = c("Code","Country"), 
      variable.name = "year")[, value := as.numeric(gsub(",", "", value))] 

# tidyr and dplyr 
long <- wide %>% gather(year, value, -c(Code,Country)) %>% 
    mutate(value = as.numeric(gsub(",", "", value))) 

данных:

wide <- read.table(text="Code Country  1950 1951 1952 1953 1954 
AFG Afghanistan 20,249 21,352 22,532 23,557 24,555 
ALB Albania  8,097 8,986 10,058 11,123 12,246", header=TRUE, check.names=FALSE) 
+0

отличный ответ, еще одно крошечное напоминание: не помещайте в свой фрейм какие-либо переменные, кроме 'id' и 'time',' melt' не мог сказать, что вы хотите сделать в этом случае. –

+1

@JasonGoal Не могли бы вы рассказать об этом? Поскольку я интерпретирую ваш комментарий, это не должно быть проблемой. Просто укажите как 'id.vars', так и' measure.vars'. – Jaap

+0

, тогда это хорошо для меня, не знаю 'id.vars', а' measure.vars' можно указать в первом варианте, извините за беспорядок, его ошибка. –

1

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

Обратите внимание, что для обработки запятые (и X добавляется, если check.names = FALSE не установлен), я также использую dplyr «s мутировать с parse_number из readr для преобразования текстовых значений обратно к номерам. Это все часть tidyverse и поэтому могут быть загружены вместе с library(tidyverse)

wide %>% 
    gather(Year, Value, -Code, -Country) %>% 
    mutate(Year = parse_number(Year) 
     , Value = parse_number(Value)) 

Returns:

Code  Country Year Value 
1 AFG Afghanistan 1950 20249 
2 ALB  Albania 1950 8097 
3 AFG Afghanistan 1951 21352 
4 ALB  Albania 1951 8986 
5 AFG Afghanistan 1952 22532 
6 ALB  Albania 1952 10058 
7 AFG Afghanistan 1953 23557 
8 ALB  Albania 1953 11123 
9 AFG Afghanistan 1954 24555 
10 ALB  Albania 1954 12246 
3

Поскольку этот ответ помечается , я чувствовал, что это было бы полезно разделить другую альтернативу из основание R: stack.

Однако следует отметить, что stack не работает с factor с - это работает только тогда, когда is.vector является TRUE, и из документации is.vector, мы находим, что:

is.vector возвращает TRUE если х вектор указанного режима, не имеющий атрибутов кроме имен. В противном случае он возвращает FALSE.

Я использую выборочные данные from @Jaap's answer, где значения в год столбцы factor s.

Вот stack подход: (. И переделке)

cbind(wide[1:2], stack(lapply(wide[-c(1, 2)], as.character))) 
## Code  Country values ind 
## 1 AFG Afghanistan 20,249 1950 
## 2 ALB  Albania 8,097 1950 
## 3 AFG Afghanistan 21,352 1951 
## 4 ALB  Albania 8,986 1951 
## 5 AFG Afghanistan 22,532 1952 
## 6 ALB  Albania 10,058 1952 
## 7 AFG Afghanistan 23,557 1953 
## 8 ALB  Albania 11,123 1953 
## 9 AFG Afghanistan 24,555 1954 
## 10 ALB  Albania 12,246 1954