如何在r中实现广义的“切换方程”?

时间:2017-03-19 02:15:53

标签: r

我正试图在r中实现一个广义的“切换方程”(Gerber and Green 2012,第2章)。

我有一个分类变量Z,它有k> 2个值。

我有k列名Y_1,Y_2,... Y_k。

我想创建一个变量Y,从每列中选择“正确”的值。也就是说,如果Z为1,则将Y_1值放入Y中。

我有一个循环的解决方案,但它很烦人。用一个衬垫是否有超级甜蜜的方式来做到这一点?没有嵌套的ifelse,请等。

N <- 100

df <- data.frame(
  Z = sample(1:3, N, replace = TRUE),
  Y_1 = rnorm(N),
  Y_2 = rnorm(N),
  Y_3 = rnorm(N)
)

# an annoying solution
df <- within(df,{
  Y <- rep(NA, nrow(df))
  Y[Z == 1] <- Y_1[Z == 1]
  Y[Z == 2] <- Y_2[Z == 2]
  Y[Z == 3] <- Y_3[Z == 3]
})

head(df) 

产生:

  Z         Y_1        Y_2         Y_3           Y
1 3  0.89124772  1.4377700  0.05226285  0.05226285
2 1  0.89186873 -0.6984839 -0.86141525  0.89186873
3 1 -0.01315678  1.5193461  0.18290065 -0.01315678
4 3 -0.57857274 -1.4445197  2.03764943  2.03764943
5 3 -0.19793692 -0.1818225  1.10270877  1.10270877
6 2  1.48291431  2.7264541  0.70129357  2.72645413
编辑:我喜欢Weihuang Wong的方法df$Y <- sapply(split(df, 1:nrow(df)), function(x) x[, paste0("Y_", x$Z)]),部分原因是它不依赖于位置而是依赖于列名。到目前为止,所有提供的答案都使用了列位置....我有点担心sapply(split())很慢,但也许我疯了?

5 个答案:

答案 0 :(得分:2)

df$Y <- apply(df, 1, function(x) x[x[1]+1] )
head(df)
#  Z        Y_1        Y_2        Y_3          Y
#1 1 -0.8598997 -0.3180947  1.9374462 -0.8598997
#2 2 -0.2392902  0.2266245  0.2364991  0.2266245
#3 1 -0.8733609 -1.3892361  0.3351359 -0.8733609
#4 3 -0.6533548 -1.1042993 -0.2906852 -0.2906852
#5 1 -1.7424126 -0.2101860  0.1198945 -1.7424126
#6 2 -1.9746651 -0.4308746 -0.7849773 -0.4308746

答案 1 :(得分:2)

不完全是1行,但是

get_result <- function(dfrow){
  x <- unlist(dfrow[,1:4])
  Y <- x[x[1] + 1] 
}

library(purrr)
newdf <- by_row(df, get_result)

答案 2 :(得分:1)

这可以使用AVCaptureSessionPresetPhoto索引

以矢量化方式完成
username=user321@user.com&password=somepassword&grant_type=password

数据

row/column

答案 3 :(得分:0)

OP在这里。

我用手工解决了黄伟煌提出的“ind_split”解决方案。我也是通过“团体”来做的:

N <- 100000

df <- data.frame(
  Z = sample(1:3, N, replace = TRUE),
  Y_1 = rnorm(N),
  Y_2 = rnorm(N),
  Y_3 = rnorm(N)
)


ind_split <- 
system.time({
  df$Y <- sapply(split(df, 1:nrow(df)), function(x) x[, paste0("Y_", x$Z)])
  head(df)
})

revealer <- 
  function(list_element){
    col_name <- paste0("Y_", list_element[1, "Z"])
    list_element$Y <- list_element[,col_name]
    return(list_element)
  }

group_split <- 
system.time({
  split_list <- split(df, df$Z)
  df <- do.call(what = rbind, lapply(split_list, revealer))
  head(df)
})


by_hand <- 
system.time({
  # an annoying solution
  df <- within(df,{
    Y <- rep(NA, nrow(df))
    Y[Z == 1] <- Y_1[Z == 1]
    Y[Z == 2] <- Y_2[Z == 2]
    Y[Z == 3] <- Y_3[Z == 3]
  })
  head(df)
})


ind_split
group_split
by_hand

时间进入

> ind_split
   user  system elapsed 
  1.023   0.083   1.136 
> group_split
   user  system elapsed 
  0.011   0.002   0.013 
> by_hand
   user  system elapsed 
  0.001   0.000   0.001 

手工烦人的方法更快,这对我来说太疯狂了!按群体分割比个人分割要快。

答案 4 :(得分:0)

这里最后添加的内容是通过使用matchnames(基于另一个previously suggested by Akrun并由我自己修改的解决方案),根据Akrun的答案而建立的,但不使用职位编号: / p>

df$Y <- df[cbind(1:nrow(df), match(paste0('Y_', df$Z), names(df)))]