将 k 列重塑为 2 列,表示 k 变量值的顺序对
reshaping k columns to 2 columns representing sequential pairs of the values of the k variables
我有一个这样的数据框:
id y1 y2 y3 y4
--+--+--+--+--
a |12|13|14|
b |12|18| |
c |13| | |
d |13|14|15|16
我想以两列结尾的方式重塑。上面的例子将变成:
id from to
--+----+---
a |12 |13
a |13 |14
a |14 |
b |12 |18
b |18 |
c |13 |
d |13 |14
d |14 |15
d |15 |16
每个 id
每对年份值都有一个 'from' 和一个 'to'。
有谁知道一个简单的方法来做到这一点?我尝试使用 reshape2
。我也查看了 但我认为我的情况有所不同。
您可以使用 lapply
遍历成对的列并使用 rbind
合并它们:
do.call(rbind,
lapply(2:(length(df)-1),
function(x) setNames(df[!is.na(df[,x]),c(1,x,x+1)],
c("id", "from", "to"))))
id from to
1 a 12 13
2 b 12 18
3 c 13 NA
4 d 13 14
11 a 13 14
21 b 18 NA
41 d 14 15
12 a 14 NA
42 d 15 16
一个解决方案使用 dplyr
和 tidyr
。 dt2
是最终输出。
# Create example data frame
dt <- data.frame(id = c("a", "b", "c", "d"),
y1 = c(12, 12, 13, 13),
y2 = c(13, 18, NA, 14),
y3 = c(14, NA, NA, 15),
y4 = c(NA, NA, NA, 16),
stringsAsFactors = FALSE)
# Load packages
library(dplyr)
library(tidyr)
# Process the data
dt2 <- dt %>%
gather(STEP, from, -id) %>%
drop_na(from) %>%
arrange(id, STEP) %>%
group_by(id) %>%
mutate(to = lead(from)) %>%
select(-STEP)
在基数 R 中,stack
并将每组中的所有内容移回一行。使用@ycw 的示例数据,dt
:
tmp <- na.omit(cbind(dt[1], stack(dt[-1])[-2]))
names(tmp)[2] <- "from"
tmp$to <- with(tmp, ave(from, id, FUN=function(x) c(tail(x,-1),NA) ))
tmp[order(tmp$id),]
# id from to
#1 a 12 13
#5 a 13 14
#9 a 14 NA
#2 b 12 18
#6 b 18 NA
#3 c 13 NA
#4 d 13 14
#8 d 14 15
#12 d 15 16
#16 d 16 NA
在data.table
的世界里,同样的逻辑也适用。 melt
,然后shift
by=
id:
library(data.table)
dt <- as.data.table(dt)
melt(dt, id.vars="id", value.name="from")[
!is.na(from),-"variable"][, to := shift(from,1,type="lead"), by=id
][order(id)]
我有一个这样的数据框:
id y1 y2 y3 y4
--+--+--+--+--
a |12|13|14|
b |12|18| |
c |13| | |
d |13|14|15|16
我想以两列结尾的方式重塑。上面的例子将变成:
id from to
--+----+---
a |12 |13
a |13 |14
a |14 |
b |12 |18
b |18 |
c |13 |
d |13 |14
d |14 |15
d |15 |16
每个 id
每对年份值都有一个 'from' 和一个 'to'。
有谁知道一个简单的方法来做到这一点?我尝试使用 reshape2
。我也查看了
您可以使用 lapply
遍历成对的列并使用 rbind
合并它们:
do.call(rbind,
lapply(2:(length(df)-1),
function(x) setNames(df[!is.na(df[,x]),c(1,x,x+1)],
c("id", "from", "to"))))
id from to
1 a 12 13
2 b 12 18
3 c 13 NA
4 d 13 14
11 a 13 14
21 b 18 NA
41 d 14 15
12 a 14 NA
42 d 15 16
一个解决方案使用 dplyr
和 tidyr
。 dt2
是最终输出。
# Create example data frame
dt <- data.frame(id = c("a", "b", "c", "d"),
y1 = c(12, 12, 13, 13),
y2 = c(13, 18, NA, 14),
y3 = c(14, NA, NA, 15),
y4 = c(NA, NA, NA, 16),
stringsAsFactors = FALSE)
# Load packages
library(dplyr)
library(tidyr)
# Process the data
dt2 <- dt %>%
gather(STEP, from, -id) %>%
drop_na(from) %>%
arrange(id, STEP) %>%
group_by(id) %>%
mutate(to = lead(from)) %>%
select(-STEP)
在基数 R 中,stack
并将每组中的所有内容移回一行。使用@ycw 的示例数据,dt
:
tmp <- na.omit(cbind(dt[1], stack(dt[-1])[-2]))
names(tmp)[2] <- "from"
tmp$to <- with(tmp, ave(from, id, FUN=function(x) c(tail(x,-1),NA) ))
tmp[order(tmp$id),]
# id from to
#1 a 12 13
#5 a 13 14
#9 a 14 NA
#2 b 12 18
#6 b 18 NA
#3 c 13 NA
#4 d 13 14
#8 d 14 15
#12 d 15 16
#16 d 16 NA
在data.table
的世界里,同样的逻辑也适用。 melt
,然后shift
by=
id:
library(data.table)
dt <- as.data.table(dt)
melt(dt, id.vars="id", value.name="from")[
!is.na(from),-"variable"][, to := shift(from,1,type="lead"), by=id
][order(id)]