R 以一种奇怪的方式应用dcast

R 以一种奇怪的方式应用dcast,r,reshape2,dcast,R,Reshape2,Dcast,我想根据“lead”变量来分离变量。x3在以下情况下: set.seed(2) df = data.frame(x1 = sample(4), x2 = sample(4), x3 = sample(letters[1:2], size = 4, replace = TRUE)) df # x1 x2 x3 # 1 1 4 a # 2 3 3 b # 3 2 1 b # 4 4 2 a # Desired output # x3 x1.a x2.a x1.b x2.

我想根据“lead”变量来分离变量。x3在以下情况下:

set.seed(2)
df = data.frame(x1 = sample(4), x2 = sample(4), x3 = sample(letters[1:2], size = 4, replace = TRUE))
df
#   x1 x2 x3
# 1  1  4  a
# 2  3  3  b
# 3  2  1  b
# 4  4  2  a

# Desired output
# x3 x1.a x2.a x1.b x2.b
#  a    1    4   NA   NA
#  b   NA   NA    3    3
#  b   NA   NA    2    1
#  a    4    2   NA   NA
我从某种程度上感觉到,这可以通过
重塑2::dcast()
实现,但我只能让它对总共两个变量起作用:

reshape2::dcast(df[,2:3], seq_along(x3) ~ x3, value.var = "x2")[, -1]
#    a  b
# 1  2 NA
# 2 NA  1
# 3 NA  3
# 4  4 NA
但这可能只是完全滥用了dcast。这个问题有没有优雅的解决方案,不需要拆分和合并
df


编辑:有些人提到这样做是一个可怕的想法,我可能不应该做这样的事情。让我详细说明一下这什么时候有意义


想象一下,
x3
是一个特定算法的开关。在这种情况下,
a
b
是选项。此外,
x1
x2
是两种算法都可以采用的参数。不幸的是,对于
x1
x2
,这两种算法在相同的参数设置下的行为确实不同,因此将它们作为不同的特性来处理是有意义的,以考虑它们的无腐蚀性。

这里有一个解决方案,使用
X3
创建虚拟交互项。通过使用
dplyr
数据,可能可以将所有这些代码放在一行中。表
如下:

temp <- model.matrix( ~ (x1+x2):x3-1, df)
temp[model.matrix( ~ (I(x1+1)+I(x2+1)):x3-1, df) == temp] <- NA
data.frame(df$x3, temp)
####  df.x3 x1.x3a x1.x3b x3a.x2 x3b.x2
####      a      1     NA      4     NA
####      b     NA      3     NA      3
####      b     NA      2     NA      1
####      a      4     NA      2     NA

temp这可以通过使用
melt
dcast
来实现,如果您再添加一列并执行中间
melt

library(reshape2)
library(magrittr)

set.seed(2)
df = data.frame(x1 = sample(4), x2 = sample(4), x3 = sample(letters[1:2], size = 4, replace = TRUE))

df$row <- 1:nrow(df)

melt(df, 
     id.vars = c("row", "x3"), 
     measure.vars = c("x1", "x2")) %>%
  dcast(row ~ x3 + variable, 
        value.var = "value")
library(重塑2)
图书馆(magrittr)
种子(2)
df=数据帧(x1=样本(4),x2=样本(4),x3=样本(字母[1:2],大小=4,替换=真))
df$行%
dcast(第x3行+变量,
value.var=“value”)

但是,它的运行速度比agenis的解决方案慢2-3倍,即使我将数据帧的大小推高到10000行。(8毫秒对16毫秒)

我自己想出了一个基本解决方案:

cat.var = "x3"
cont.vars = setdiff(colnames(df), cat.var)
categories = unique(df[[cat.var]])
res = lapply(categories, function(x) {
  this.df = df[, cont.vars, drop = FALSE]
  this.df[df[[cat.var]] != x,] = NA
  setNames(this.df, paste0(x,".",colnames(this.df)))
})
res = do.call(cbind, c(list(df[, cat.var, drop=FALSE]), res))
res

#   x3 a.x1 a.x2 b.x1 b.x2
# 1  a    1    4   NA   NA
# 2  b   NA   NA    3    3
# 3  b   NA   NA    2    1
# 4  a    4    2   NA   NA

您可以使用
tidyr

library(tidyr);library(dplyr)
df <- df %>% mutate(rows=rownames(.)) %>% 
gather(., key="vars", value= "val", -x3,-rows) %>%
    mutate(vars= paste(x3,vars, sep=".")) %>%  
spread(., key = vars, value = val) %>%
select(-rows)
library(tidyr);图书馆(dplyr)
df%变异(行=行名(.))%>%
聚集(,key=“vars”,value=“val”,-x3,-行)%>%
变异(变量=粘贴(x3,变量,sep=“.”)%>%
价差(,键=VAR,值=val)%>%
选择(-行)

它将数据集收集成长格式,将x3变量分开,然后在创建所需的变量头之后,再次传播数据。

好的,有
合并(df[df$x3==“a”,],df[df$x3==“b”,],by=“x3”,all=TRUE)
,但很自然,没有优雅的方式来获得如此混乱的输出。@agenis,现在已经解决了。@Frank,如果我现在不知道
x3
的离散值,这会变得混乱。只需一句话:如果你想得到更多的“关注”,你可能应该把问题的标题改得更具体一些;下次可能会省下一笔赏金!;-)行和列顺序重要吗?行变量的使用很好,我的时钟速度大约是@agenis解决方案的3倍,是我的5倍。做得好。我喜欢你的模型。矩阵方法。我想知道这是否更清楚(尽管速度较慢):
m@user20650感谢您的输入,这确实是一个不错的替代解决方案。你可以把它贴出来作为答案。我想知道我们是否可以将其简化为单线井,您也可以使用
model.matrix(~0+x3,df)^NA
,而不是显式地将零设置为NA。所以在一行
data.frame(df$x3,apply(model.matrix(~0+x3,df)^NA,2,“*”,df[-3])
,但实际上不能称为一行,因为它是多个计算。这个解决方案唯一困扰我的是,对于我现在只知道分类列名称的通用输入来说,它有点混乱,因为我必须从字符串生成公式。@jakobr好的,请随意修改您的问题,这样我就可以考虑这个规范,;-)有趣的解决方案,但您必须注意,它会对行进行重新排序,并按“x3”对行进行排序。如果行顺序很重要,您可以在select语句之前添加
arrange(rows)%%>%
。但它仍然不是最快的。