在 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
我有一个包含大约 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
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