Ik heb wat problemen om mijn data.frame
te converteren van een brede tabel naar een lange tabel.
Op dit moment ziet het er zo uit:
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
Nu wil ik dit data.frame
omzetten in een lang data.frame
.
Zoiets als dit:
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
Ik heb de functies melt()
en reshape()
bekeken en al geprobeerd te gebruiken
zoals sommige mensen suggereerden in soortgelijke vragen.
Tot nu toe krijg ik echter alleen maar rommelige resultaten.
Als het mogelijk is, zou ik het willen doen met de functie reshape()
aangezien
het ziet er een beetje fijner uit om te hanteren.
Antwoord 1, autoriteit 100%
reshape()
duurt even om aan te wennen, net zoals melt
/cast
. Hier is een oplossing met reshape, ervan uitgaande dat uw dataframe d
heet:
reshape(d,
direction = "long",
varying = list(names(d)[3:7]),
v.names = "Value",
idvar = c("Code", "Country"),
timevar = "Year",
times = 1950:1954)
Antwoord 2, Autoriteit 166%
Drie alternatieve oplossingen:
1) met gegevens. Tabel :
U kunt dezelfde melt
gebruiken zoals in de reshape2
pakket (die een verlengde en versterker is; verbeterde implementatie). melt
van data.table
heeft ook meer parameters die de melt
-functie van reshape2
. U kunt bijvoorbeeld ook de naam van de variabele kolom opgeven:
library(data.table)
long <- melt(setDT(wide), id.vars = c("Code","Country"), variable.name = "year")
wat geeft:
> long Code Country year 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
Sommige alternatieve notaties:
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")
2) met Tatyr :
library(tidyr)
long <- wide %>% gather(year, value, -c(Code, Country))
Sommige alternatieve notaties:
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`)
3) Met Reshape2 :
library(reshape2)
long <- melt(wide, id.vars = c("Code", "Country"))
Enkele alternatieve notaties die hetzelfde resultaat geven:
# 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))
Opmerkingen:
- Reshape2 is met pensioen. Alleen wijzigingen die nodig zijn om het op CRAN te houden, worden gemaakt. (bron )
- Als u
NA
-waarden wilt uitsluiten, kunt una.rm = TRUE
toevoegen aan demelt
evenals degather
functies.
Een ander probleem met de gegevens is dat de waarden worden gelezen door R als karakterwaarden (als gevolg van de ,
in de cijfers). U kunt dat repareren met gsub
EN as.numeric
:
long$value <- as.numeric(gsub(",", "", long$value))
of rechtstreeks met data.table
of 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)))
gegevens:
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)
Antwoord 3, Autoriteit 32%
Gebruik Reshape pakket:
#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"]))
Antwoord 4, Autoriteit 27%
Met tidyr_1.0.0
, een andere optie is pivot_longer
library(tidyr)
pivot_longer(df1, -c(Code, Country), values_to = "Value", names_to = "Year")
# A tibble: 10 x 4
# Code Country Year Value
# <fct> <fct> <chr> <fct>
# 1 AFG Afghanistan 1950 20,249
# 2 AFG Afghanistan 1951 21,352
# 3 AFG Afghanistan 1952 22,532
# 4 AFG Afghanistan 1953 23,557
# 5 AFG Afghanistan 1954 24,555
# 6 ALB Albania 1950 8,097
# 7 ALB Albania 1951 8,986
# 8 ALB Albania 1952 10,058
# 9 ALB Albania 1953 11,123
#10 ALB Albania 1954 12,246
gegevens
df1 <- structure(list(Code = structure(1:2, .Label = c("AFG", "ALB"), class = "factor"),
Country = structure(1:2, .Label = c("Afghanistan", "Albania"
), class = "factor"), `1950` = structure(1:2, .Label = c("20,249",
"8,097"), class = "factor"), `1951` = structure(1:2, .Label = c("21,352",
"8,986"), class = "factor"), `1952` = structure(2:1, .Label = c("10,058",
"22,532"), class = "factor"), `1953` = structure(2:1, .Label = c("11,123",
"23,557"), class = "factor"), `1954` = structure(2:1, .Label = c("12,246",
"24,555"), class = "factor")), class = "data.frame", row.names = c(NA,
-2L))
Antwoord 5, autoriteit 22%
Aangezien dit antwoord is getagd met r- faq, ik dacht dat het nuttig zou zijn om een ander alternatief van basis R te delen: stack
.
Houd er echter rekening mee dat stack
niet werkt met factor
s–het werkt alleen als is.vector
TRUE
, en uit de documentatie voor is.vector
, vinden we dat:
is.vector
retourneertTRUE
als x een vector is van de gespecificeerde modus zonder attributen anders dan namen. Het geeft andersFALSE
terug.
Ik gebruik de voorbeeldgegevens uit het antwoord van @Jaap, waarbij de waarden in de jaarkolommen factor
s.
Dit is de stack
-aanpak:
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
Antwoord 6, autoriteit 9%
Hier is nog een voorbeeld dat het gebruik van gather
van tidyr
laat zien. Je kunt de kolommen selecteren om te gather
door ze afzonderlijk te verwijderen (zoals ik hier doe), of door de jaren die je wilt expliciet op te nemen.
Merk op dat, om de komma’s te verwerken (en X’s toegevoegd als check.names = FALSE
niet is ingesteld), ik ook dplyr
‘s muteer met parse_number
van readr
om de tekstwaarden terug naar getallen te converteren. Deze maken allemaal deel uit van de tidyverse
en kunnen dus samen met library(tidyverse)
worden geladen
wide %>%
gather(Year, Value, -Code, -Country) %>%
mutate(Year = parse_number(Year)
, Value = parse_number(Value))
Retouren:
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
Antwoord 7, autoriteit 4%
Hier is een sqldf-oplossing:
sqldf("Select Code, Country, '1950' As Year, `1950` As Value From wide
Union All
Select Code, Country, '1951' As Year, `1951` As Value From wide
Union All
Select Code, Country, '1952' As Year, `1952` As Value From wide
Union All
Select Code, Country, '1953' As Year, `1953` As Value From wide
Union All
Select Code, Country, '1954' As Year, `1954` As Value From wide;")
Om de zoekopdracht uit te voeren zonder alles in te typen, kunt u het volgende gebruiken:
Met dank aan G. Grothendieckvoor de implementatie ervan.
ValCol <- tail(names(wide), -2)
s <- sprintf("Select Code, Country, '%s' As Year, `%s` As Value from wide", ValCol, ValCol)
mquery <- paste(s, collapse = "\n Union All\n")
cat(mquery) #just to show the query
#> Select Code, Country, '1950' As Year, `1950` As Value from wide
#> Union All
#> Select Code, Country, '1951' As Year, `1951` As Value from wide
#> Union All
#> Select Code, Country, '1952' As Year, `1952` As Value from wide
#> Union All
#> Select Code, Country, '1953' As Year, `1953` As Value from wide
#> Union All
#> Select Code, Country, '1954' As Year, `1954` As Value from wide
sqldf(mquery)
#> Code Country Year 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
Helaas denk ik niet dat PIVOT
en UNPIVOT
zou werken voor R
SQLite
. Als u uw zoekopdracht op een meer geavanceerde manier wilt opschrijven, kunt u ook deze berichten bekijken:
met sprintf
SQL-query’s opschrijven & nbsp; & nbsp; of & nbsp; & nbsp; pass variabelen naar sqldf
Antwoord 8
U kunt ook de cdata
-pakket gebruiken, dat het concept van (transformatie) bedientabel gebruikt:
# data
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)
library(cdata)
# build control table
drec <- data.frame(
Year=as.character(1950:1954),
Value=as.character(1950:1954),
stringsAsFactors=FALSE
)
drec <- cdata::rowrecs_to_blocks_spec(drec, recordKeys=c("Code", "Country"))
# apply control table
cdata::layout_by(drec, wide)
Ik ben momenteel dat pakket aan het verkennen en vind het vrij toegankelijk. Het is ontworpen voor veel gecompliceerdere transformaties en omvat de terugtransformatie. Er is een zelfstudiebeschikbaar.
Antwoord 9
je kunt ook veel voorbeelden zien in R cookbook
olddata_wide <- read.table(header=TRUE, text='
subject sex control cond1 cond2
1 M 7.9 12.3 10.7
2 F 6.3 10.6 11.1
3 F 9.5 13.1 13.8
4 M 11.5 13.4 12.9
')
# Make sure the subject column is a factor
olddata_wide$subject <- factor(olddata_wide$subject)
olddata_long <- read.table(header=TRUE, text='
subject sex condition measurement
1 M control 7.9
1 M cond1 12.3
1 M cond2 10.7
2 F control 6.3
2 F cond1 10.6
2 F cond2 11.1
3 F control 9.5
3 F cond1 13.1
3 F cond2 13.8
4 M control 11.5
4 M cond1 13.4
4 M cond2 12.9
')
# Make sure the subject column is a factor
olddata_long$subject <- factor(olddata_long$subject)