在 R 中从宽到长重塑数据框

reshape dataframe from wide to long in R

我有一个包含大约 300 列的数据框。这些列已分组。这是示例:

id  name fixed_2020 fixed_2019 fixed_2018 fixed_2017 fixed_2016 current_2020  current_2019 current_2018 current_2017 current_2016
 1     A       2300       2100       2600       2600       1900         3000          3100         3200         3300         3400

我在数据框中总共有大约 20000 行。我想在 R 中从宽到长重塑这个数据框。我尝试使用函数 melt:

fixed <- melt(mydata, id.vars = c('id', 'name'), measure.vars = 3:7, variable.name = 'year', value.name = 'fixed')

然后我使用 gsub 获取年份列

fixed$year <- as.character(gsub("[^0-9-]", "", debtors$year))

这是我想要的:

id   name  year  fixed  current
 1   A     2020  2030    3000
 2   A     2019  2100    3100
 3   A     2018  2600    3200
 4   A     2017  2600    3300
 5   A     2016  1900    3400

虽然它确实给了我想要的东西,但当我有超过 300 列时,这个过程很耗时。由于我的数据框是根据变量和年份(每个变量 10 年)分组的,我想知道是否有其他函数可以更有效地做到这一点。

提前致谢!

您可以使用 pivot_longer() 来自 tidyr:

library(dplyr)
library(tidyr)

df %>%
  pivot_longer(contains("_"), names_to = c(".value", "year"), names_sep = "_") %>%
  group_by(name) %>%
  mutate(id = 1:n()) %>%
  ungroup()

# # A tibble: 5 x 5
#      id name  year  fixed current
#   <int> <chr> <chr> <int>   <int>
# 1     1 A     2020   2300    3000
# 2     2 A     2019   2100    3100
# 3     3 A     2018   2600    3200
# 4     4 A     2017   2600    3300
# 5     5 A     2016   1900    3400

数据
df <- structure(list(id = 1L, name = "A", fixed_2020 = 2300L, fixed_2019 = 2100L, 
    fixed_2018 = 2600L, fixed_2017 = 2600L, fixed_2016 = 1900L,
    current_2020 = 3000L, current_2019 = 3100L, current_2018 = 3200L,
    current_2017 = 3300L, current_2016 = 3400L), class = "data.frame", row.names = c(NA, -1L))

使用data.table:

library(data.table)
setDT(mydata)
result <- melt(mydata, id=c('id', 'name'), 
                 measure.vars = patterns(fixed='fixed_', current='current_'), 
                 variable.name = 'year')
years <- as.numeric(gsub('.+_(\d+)', '\1', grep('fixed', names(mydata), value = TRUE)))
result[, year:=years[year]]
result[, id:=seq(.N), by=.(name)]
result
##    id name year fixed current
## 1:  1    A 2020  2300    3000
## 2:  2    A 2019  2100    3100
## 3:  3    A 2018  2600    3200
## 4:  4    A 2017  2600    3300
## 5:  5    A 2016  1900    3400

这应该很快,但是你的 data-set 不是很大 tbh。

请注意,这假定固定列和当前列的顺序相同,并且与相同的年份相关联。因此,如果有一个 fixed_2020 作为第一个 fixed_* 列,那么还有一个 current_2020 作为第一个 current_* 列,依此类推。否则,year 列将正确关联到 fixed 而不是 current

使用 reshape

的基础 R 选项
transform(
    reshape(
        df,
        direction = "long",
        idvar = c("id", "name"),
        sep = "_",
        varying = -c(1:2)
    ),
    id = seq_along(id)
)

给予

         id name time fixed current
1.A.2020  1    A 2020  2300    3000
1.A.2019  2    A 2019  2100    3100
1.A.2018  3    A 2018  2600    3200
1.A.2017  4    A 2017  2600    3300
1.A.2016  5    A 2016  1900    3400