将dataframe从宽转换为长格式
我有一些麻烦将我的data.frame
从宽表转换为长表。 目前看起来像这样:
wide <- 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)
这产生的数据框架wide
如下所示:
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
例如:
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
截至2016年,选项包括reshape2::melt()
,以及tidyr::gather()
和data.table::melt()
解决scheme以及旧的reshape::reshape()
函数。 然而,到目前为止,我只得到混乱的结果,试图使用这些多个相似,但不同的function。
如果可能的话,我想用reshape()
函数来完成它,因为它看起来好一些,但是使用其他软件包的例子/理由是值得赞赏的。
reshape()
需要一段时间才能习惯,就像melt
/ cast
。 这里是一个重塑的解决scheme,假设你的数据框架ID为d
:
reshape(d, direction="long", varying=list(names(d)[3:7]), v.names="Value", idvar=c("Code","Country"), timevar="Year", times=1950:1954)
三种替代scheme:
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
您可以使用与reshape2
包(这是一个扩展和改进的实现)相同的melt
函数。 来自data.table
的melt
还有更多参数,即melt
从reshape2
。 你可以例如指定variables列的名称:
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, 3:7) wide %>% gather(year, value, `1950`:`1954`)
如果你想排除NA
值,你可以添加na.rm = TRUE
melt
以及gather
function。
数据的另一个问题是这些值将被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)
干得好:
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"]))
这是另外一个例子,显示了从tidyr
gather
的使用。 您可以通过单独删除它们来select要gather
的列(正如我在此处所做的那样),或者通过包括明确指定的年份来gather
这些列。
请注意,要处理逗号(如果check.names = FALSE
没有设置,则添加X),我还使用dplyr
的mutate和parse_number
的readr
将文本值转换为数字。 这些都是tidyverse
一部分,所以可以与library(tidyverse)
一起加载
wide %>% gather(Year, Value, -Code, -Country) %>% mutate(Year = parse_number(Year) , Value = parse_number(Value))
返回:
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