Przekształcanie danych.ramka od szerokiego do długiego formatu
Mam pewien problem, aby przekształcić mój data.frame
z szerokiego stołu do długiego stołu.
W tej chwili wygląda to tak:
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
Teraz lubię przekształcić to data.frame
w długie data.frame
.
Coś takiego:
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
Szukałem i próbowałem już z melt()
i reshape()
funkcji
jak niektórzy sugerowali podobne pytania.
Jednak do tej pory mam tylko niechlujne wyniki.
Jeśli jest to możliwe chciałbym to zrobić za pomocą funkcji reshape()
ponieważ
wygląda trochę milsza w obsłudze.
5 answers
reshape()
trzeba się przyzwyczaić, tak jak melt
/cast
. Oto rozwiązanie z reshape, zakładając, że ramka danych nazywa się d
:
reshape(d, direction = "long", varying = list(names(d)[3:7]), v.names = "Value",
idvar = c("Code","Country"), timevar = "Year", times = 1950:1954)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 10:41:29
Trzy alternatywne rozwiązania:
1: z reshape2
library(reshape2)
long <- melt(wide, id.vars = c("Code", "Country"))
Dając:
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
Niektóre alternatywne notacje dające ten sam wynik:
# 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: z data.table
Możesz użyć tej samej funkcji melt
jak w pakiecie reshape2
(który jest rozszerzoną i ulepszoną implementacją). melt
from data.table
ma również więcej parametrów niż melt
-funkcja z reshape2
. Możesz na przykład również podać nazwę zmienna-kolumna:
library(data.table)
long <- melt(setDT(wide), id.vars = c("Code","Country"), variable.name = "year")
Niektóre alternatywne zapisy:
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: z tidyr
library(tidyr)
long <- wide %>% gather(year, value, -c(Code, Country))
Niektóre alternatywne zapisy:
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`)
Jeśli chcesz wykluczyć NA
wartości, możesz dodać na.rm = TRUE
do melt
, a także do gather
funkcji.
Innym problemem z danymi jest to, że wartości będą odczytywane przez R jako wartości znakowe (w wyniku ,
w liczbach). Można to naprawić za pomocą gsub
i as.numeric
:
long$value <- as.numeric(gsub(",", "", long$value))
Lub bezpośrednio z data.table
lub 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)))
Dane:
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-22 14:46:31
Using reshape package:
#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"]))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-09 10:20:12
Ponieważ ta odpowiedź jest oznaczona r-faq , uznałem, że przydałoby się udostępnić inną alternatywę z bazy R: stack
.
Zauważ jednak, że stack
nie działa z factor
s-działa tylko wtedy, gdy is.vector
jest TRUE
, a z dokumentacji is.vector
wynika, że:
is.vector
zwracaTRUE
Jeśli x jest wektorem określonego trybu, nie posiadającym atrybutów innych niż nazwy . ZwracaFALSE
w przeciwnym razie.
Używam przykładowych danych z odpowiedzi @Jaap , gdzie wartości w kolumnach roku to factor
s.
Oto podejście 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-09 05:52:57
Oto kolejny przykład pokazujący użycie gather
z tidyr
. Możesz wybrać kolumny do gather
albo usuwając je pojedynczo (tak jak to robię tutaj), albo włączając w to lata, które chcesz jawnie.
Zauważ, że aby obsłużyć przecinki (i X dodane, Jeśli check.names = FALSE
nie jest ustawione), używam również mutacji dplyr
z parse_number
z readr
do konwersji wartości tekstowych z powrotem na liczby. Wszystkie są częścią tidyverse
i dlatego mogą być ładowane razem z library(tidyverse)
wide %>%
gather(Year, Value, -Code, -Country) %>%
mutate(Year = parse_number(Year)
, Value = parse_number(Value))
Zwraca:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-04 19:20:29