使用 R 将一列提取为行,保留其他列
Extract one column as rows with R, preserving other columns
我有:
我有一个如下所示的数据框:
sequence foo model output real
1 3 a 12 12
1 3 b 29 12
1 3 c 10 12
1 3 d 38 12
1 3 e 10 12
2 3 a 38 15
2 3 b 10 15
2 3 c 29 15
2 3 d 56 15
2 3 e 10 15
创建者:
d.test = data.frame(
sequence = c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2),
foo = c(3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
model = c("a", "b", "c", "d", "e", "a", "b", "c", "d", "e"),
output = c(12, 29, 10, 38, 10, 38, 10, 29, 56, 10),
real = c(12, 12, 12, 12, 12, 15, 15, 15, 15, 15)
)
模型为每个给定的 sequence
预测一个 output
,但 real
输出也沿着每个序列记录。
我需要的:
我想转换数据,使 real
变成 "model" 本身,即:
sequence foo model output
1 3 a 12
1 3 b 29
1 3 c 10
1 3 d 38
1 3 e 10
1 3 real 12
2 3 a 38
2 3 b 10
2 3 c 29
2 3 d 56
2 3 e 10
2 3 real 15
我怎样才能使用 dplyr
、tidyr
和他们的表兄弟来实现这一点?
请注意,对于“不错”的解决方案,您不必:
- 手动输入列索引
- 手动指定所有不感兴趣的列,如
foo
我试过的:
我尝试了以下方法,但感觉很笨拙:
unique(
melt(d.test,
id.vars = c("sequence", "foo"),
measure.vars = c("real"),
variable.name = "model",
value.name = "output"
)
)
现在我必须从原始数据框中删除 real
列并附加我刚才所做的行。这不是一个很好的解决方案,因为除了 foo
列之外,我可能还想保留更多的列,然后我必须将它们指定为 id.vars
.
我会使用 data.table:
library(data.table)
setDT(d.test)
d.test[,
rbind(.SD, .SD[1L][, `:=`(model = "real", output = real[1L])])
, by=sequence][, real := NULL][]
如果我不得不使用'verse:
d.real = d.test %>% distinct(sequence) %>%
mutate(model = "real", output = real) %>% select(-real)
d = d.test %>% select(-real)
然后堆叠它们:
bind_rows(d, d.real)
如果顺序很重要,请添加 %>% arrange(sequence)
。
评论。OP中的问题源于数据不整洁。如果您不明白我的意思,阅读 Hadley's paper on the subject 可能会有帮助。
这是你想要的吗?
x <- unique(
melt(d.test,
id.vars = c("sequence", "foo"),
measure.vars = c("real"),
variable.name = "model",
value.name = "output" ))
d.test$real<-NULL
names(x) <- names(d.test)
rbind(d.test, x)
另一种方法是:
temp = unique(d.test[,-c(3,4)])
temp$model = "real"
colnames(temp)[3] = "output"
d.test$real = NULL
d.test = rbind(d.test,temp)
这个returns:
> d.test
sequence foo model output
1 1 3 a 12
2 1 3 b 29
3 1 3 c 10
4 1 3 d 38
5 1 3 e 10
6 2 3 a 38
7 2 3 b 10
8 2 3 c 29
9 2 3 d 56
10 2 3 e 10
11 1 3 real 12
61 2 3 real 15
编辑:
如果你想避免对模型和输出的列索引进行硬编码,请执行:
temp = unique(d.test[,!grepl("(model|output)",colnames(d.test))])
和
colnames(temp)[which(colnames(temp)=="real")] = "output"
另一种可能的 dplyr 解决方案:
> library(dplyr)
>
>
> d.real <- d.test %>% group_by(sequence) %>%
select(foo=unique(foo),output = unique(real)) %>%
unique() %>% mutate(model='real') %>% as.data.frame() %>% rbind(d.test[,1:4])
%>% arrange(sequence,model)
Adding missing grouping variables: `sequence` #ignore it
>
> knitr::kable(d.real)
| sequence| foo| output|model |
|--------:|---:|------:|:-----|
| 1| 3| 12|a |
| 1| 3| 29|b |
| 1| 3| 10|c |
| 1| 3| 38|d |
| 1| 3| 10|e |
| 1| 3| 12|real |
| 2| 3| 38|a |
| 2| 3| 10|b |
| 2| 3| 29|c |
| 2| 3| 56|d |
| 2| 3| 10|e |
| 2| 3| 15|real |
诀窍是加宽已经很长的数据,然后将其转换回长格式,确保在整形中包含 real
列。
library(dplyr)
library(tidyr)
d.test %>%
spread(model, output) %>%
gather(model, output, -sequence, -foo) %>%
arrange(sequence, model)
#> sequence foo model output
#> 1 1 3 a 12
#> 2 1 3 b 29
#> 3 1 3 c 10
#> 4 1 3 d 38
#> 5 1 3 e 10
#> 6 1 3 real 12
#> 7 2 3 a 38
#> 8 2 3 b 10
#> 9 2 3 c 29
#> 10 2 3 d 56
#> 11 2 3 e 10
#> 12 2 3 real 15
spread
是tidyr函数,用于加宽长数据。它采用一个数据框、一列键的名称(变量名称)和一列值的名称,并将键分布在多个列中。这是将 model
-output
对分散到几列后数据的样子。
# Convert to wide-format so there is one real per row
d.test.wide <- d.test %>%
spread(model, output)
d.test.wide
#> sequence foo real a b c d e
#> 1 1 3 12 12 29 10 38 10
#> 2 2 3 15 38 10 29 56 10
gather
是熔化数据的 tidyr 函数。我们使用 dplyr 的 column-selection 语法,我们告诉它收集除标识符 sequence
和 foo
之外的所有列,将键存储在 model
列中,并将output
列中的值。
我们还可以显式 select 要收集的列:d.test.wide %>% gather(model, output, real, a:e)
。剩余的未selected 列将用作标识符。
我有:
我有一个如下所示的数据框:
sequence foo model output real
1 3 a 12 12
1 3 b 29 12
1 3 c 10 12
1 3 d 38 12
1 3 e 10 12
2 3 a 38 15
2 3 b 10 15
2 3 c 29 15
2 3 d 56 15
2 3 e 10 15
创建者:
d.test = data.frame(
sequence = c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2),
foo = c(3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
model = c("a", "b", "c", "d", "e", "a", "b", "c", "d", "e"),
output = c(12, 29, 10, 38, 10, 38, 10, 29, 56, 10),
real = c(12, 12, 12, 12, 12, 15, 15, 15, 15, 15)
)
模型为每个给定的 sequence
预测一个 output
,但 real
输出也沿着每个序列记录。
我需要的:
我想转换数据,使 real
变成 "model" 本身,即:
sequence foo model output
1 3 a 12
1 3 b 29
1 3 c 10
1 3 d 38
1 3 e 10
1 3 real 12
2 3 a 38
2 3 b 10
2 3 c 29
2 3 d 56
2 3 e 10
2 3 real 15
我怎样才能使用 dplyr
、tidyr
和他们的表兄弟来实现这一点?
请注意,对于“不错”的解决方案,您不必:
- 手动输入列索引
- 手动指定所有不感兴趣的列,如
foo
我试过的:
我尝试了以下方法,但感觉很笨拙:
unique(
melt(d.test,
id.vars = c("sequence", "foo"),
measure.vars = c("real"),
variable.name = "model",
value.name = "output"
)
)
现在我必须从原始数据框中删除 real
列并附加我刚才所做的行。这不是一个很好的解决方案,因为除了 foo
列之外,我可能还想保留更多的列,然后我必须将它们指定为 id.vars
.
我会使用 data.table:
library(data.table)
setDT(d.test)
d.test[,
rbind(.SD, .SD[1L][, `:=`(model = "real", output = real[1L])])
, by=sequence][, real := NULL][]
如果我不得不使用'verse:
d.real = d.test %>% distinct(sequence) %>%
mutate(model = "real", output = real) %>% select(-real)
d = d.test %>% select(-real)
然后堆叠它们:
bind_rows(d, d.real)
如果顺序很重要,请添加 %>% arrange(sequence)
。
评论。OP中的问题源于数据不整洁。如果您不明白我的意思,阅读 Hadley's paper on the subject 可能会有帮助。
这是你想要的吗?
x <- unique(
melt(d.test,
id.vars = c("sequence", "foo"),
measure.vars = c("real"),
variable.name = "model",
value.name = "output" ))
d.test$real<-NULL
names(x) <- names(d.test)
rbind(d.test, x)
另一种方法是:
temp = unique(d.test[,-c(3,4)])
temp$model = "real"
colnames(temp)[3] = "output"
d.test$real = NULL
d.test = rbind(d.test,temp)
这个returns:
> d.test
sequence foo model output
1 1 3 a 12
2 1 3 b 29
3 1 3 c 10
4 1 3 d 38
5 1 3 e 10
6 2 3 a 38
7 2 3 b 10
8 2 3 c 29
9 2 3 d 56
10 2 3 e 10
11 1 3 real 12
61 2 3 real 15
编辑: 如果你想避免对模型和输出的列索引进行硬编码,请执行:
temp = unique(d.test[,!grepl("(model|output)",colnames(d.test))])
和
colnames(temp)[which(colnames(temp)=="real")] = "output"
另一种可能的 dplyr 解决方案:
> library(dplyr)
>
>
> d.real <- d.test %>% group_by(sequence) %>%
select(foo=unique(foo),output = unique(real)) %>%
unique() %>% mutate(model='real') %>% as.data.frame() %>% rbind(d.test[,1:4])
%>% arrange(sequence,model)
Adding missing grouping variables: `sequence` #ignore it
>
> knitr::kable(d.real)
| sequence| foo| output|model |
|--------:|---:|------:|:-----|
| 1| 3| 12|a |
| 1| 3| 29|b |
| 1| 3| 10|c |
| 1| 3| 38|d |
| 1| 3| 10|e |
| 1| 3| 12|real |
| 2| 3| 38|a |
| 2| 3| 10|b |
| 2| 3| 29|c |
| 2| 3| 56|d |
| 2| 3| 10|e |
| 2| 3| 15|real |
诀窍是加宽已经很长的数据,然后将其转换回长格式,确保在整形中包含 real
列。
library(dplyr)
library(tidyr)
d.test %>%
spread(model, output) %>%
gather(model, output, -sequence, -foo) %>%
arrange(sequence, model)
#> sequence foo model output
#> 1 1 3 a 12
#> 2 1 3 b 29
#> 3 1 3 c 10
#> 4 1 3 d 38
#> 5 1 3 e 10
#> 6 1 3 real 12
#> 7 2 3 a 38
#> 8 2 3 b 10
#> 9 2 3 c 29
#> 10 2 3 d 56
#> 11 2 3 e 10
#> 12 2 3 real 15
spread
是tidyr函数,用于加宽长数据。它采用一个数据框、一列键的名称(变量名称)和一列值的名称,并将键分布在多个列中。这是将 model
-output
对分散到几列后数据的样子。
# Convert to wide-format so there is one real per row
d.test.wide <- d.test %>%
spread(model, output)
d.test.wide
#> sequence foo real a b c d e
#> 1 1 3 12 12 29 10 38 10
#> 2 2 3 15 38 10 29 56 10
gather
是熔化数据的 tidyr 函数。我们使用 dplyr 的 column-selection 语法,我们告诉它收集除标识符 sequence
和 foo
之外的所有列,将键存储在 model
列中,并将output
列中的值。
我们还可以显式 select 要收集的列:d.test.wide %>% gather(model, output, real, a:e)
。剩余的未selected 列将用作标识符。