R data.frame从变量中获取值,该变量由另一个变量选择,矢量化

时间:2016-02-08 19:03:51

标签: r dataframe vectorization

我有许多类似变量的数据,还有一个额外的变量,它指示我真正想要的那些类似变量中的一个。使用循环我可以查找正确的值,但数据很大,循环很慢,看起来这应该是可矢量化的。我只是没弄明白。

编辑:所选变量将在同一数据框中用作新变量,因此顺序很重要。下面给出的例子中没有显示许多其他变量。

示例数据集:

set.seed(0)
df <- data.frame(yr1 = sample(1000:1100, 8),
                 yr2 = sample(2000:2100, 8),
                 yr3 = sample(3000:3100, 8),
                 yr4 = sample(4000:4100, 8),
                 var = paste0("yr", sample(1:4, 8, replace = TRUE)))
# df
# 
#    yr1  yr2  yr3  yr4 var
# 1 1090 2066 3050 4012 yr3
# 2 1026 2062 3071 4026 yr2
# 3 1036 2006 3098 4038 yr1
# 4 1056 2020 3037 4001 yr4
# 5 1088 2017 3075 4037 yr3
# 6 1019 2065 3089 4083 yr4
# 7 1085 2036 3020 4032 yr1
# 8 1096 2072 3061 4045 yr3

这种循环方法可以解决这个问题,但是很慢而且很尴尬:

ycode <- character(nrow(df))
for(i in 1:nrow(df)) {
 ycode[i] <- df[i, df$var[i]]
}
df$ycode <- ycode

# df
#    yr1  yr2  yr3  yr4 var ycode
# 1 1090 2066 3050 4012 yr3  3050
# 2 1026 2062 3071 4026 yr2  2062
# 3 1036 2006 3098 4038 yr1  1036
# 4 1056 2020 3037 4001 yr4  4001
# 5 1088 2017 3075 4037 yr3  3075
# 6 1019 2065 3089 4083 yr4  4083
# 7 1085 2036 3020 4032 yr1  1085
# 8 1096 2072 3061 4045 yr3  3061 

似乎我应该能够对此进行矢量化,如下所示:

df$ycode <- df[, df$var]

但我发现结果令人惊讶:

#    yr1  yr2  yr3  yr4 var ycode.yr3 ycode.yr2 ycode.yr1 ycode.yr4 ycode.yr3.1 ycode.yr4.1 ycode.yr1.1 ycode.yr3.2
# 1 1090 2066 3050 4012 yr3      3050      2066      1090      4012        3050        4012        1090        3050
# 2 1026 2062 3071 4026 yr2      3071      2062      1026      4026        3071        4026        1026        3071
# 3 1036 2006 3098 4038 yr1      3098      2006      1036      4038        3098        4038        1036        3098
# 4 1056 2020 3037 4001 yr4      3037      2020      1056      4001        3037        4001        1056        3037
# 5 1088 2017 3075 4037 yr3      3075      2017      1088      4037        3075        4037        1088        3075
# 6 1019 2065 3089 4083 yr4      3089      2065      1019      4083        3089        4083        1019        3089
# 7 1085 2036 3020 4032 yr1      3020      2036      1085      4032        3020        4032        1085        3020
# 8 1096 2072 3061 4045 yr3      3061      2072      1096      4045        3061        4045        1096        3061

我也尝试了很多关于* apply的变化,但是这些变化都没有接近。一些尝试:

> apply(df, 1, function(x) x[x$var])
Error in x$var : $ operator is invalid for atomic vectors
> apply(df, 1, function(x) x[x[var]])
Error in x[var] : invalid subscript type 'closure'

有什么想法吗?非常感谢..

4 个答案:

答案 0 :(得分:1)

我们可以使用行/列索引。它应该比循环快。

 df[-ncol(df)][cbind(1:nrow(df),match(df$var,head(names(df),-1)))]
 #[1] 3050 2062 1036 4001 3075 4083 1085 3061

仅仅为了一些多样性,data.table解决方案(与上面的索引相比应该是慢的)。转换&#39; data.frame&#39;到&#39; data.table&#39; (setDT(df)),按行序列分组,我们get&#39; var&#39;的值转换为character课程后。

library(data.table)
setDT(df)[, ycode := get(as.character(var)) , 1:nrow(df)]
df
#    yr1  yr2  yr3  yr4 var ycode
#1: 1090 2066 3050 4012 yr3  3050
#2: 1026 2062 3071 4026 yr2  2062
#3: 1036 2006 3098 4038 yr1  1036
#4: 1056 2020 3037 4001 yr4  4001
#5: 1088 2017 3075 4037 yr3  3075
#6: 1019 2065 3089 4083 yr4  4083
#7: 1085 2036 3020 4032 yr1  1085
#8: 1096 2072 3061 4045 yr3  3061

答案 1 :(得分:0)

我喜欢dplyrtidyr的语法:

df$ID = 1:nrow(df)
library(dplyr)
library(tidyr)

df %>% 
    gather(year, value, yr1:yr4) %>% 
    filter(var == year) %>% 
    select(-year) %>%
    spread(year, value) %>%
    arrange(ID)

答案 2 :(得分:0)

我注意到@josliber在尝试使用Guzzle Goutte解决方案时看到(https://stackoverflow.com/a/30279903/4606130)的答案,看起来很快:

data.table

答案 3 :(得分:0)

另一个矢量化选项是使用嵌套的ifelse()。至少在我看来,与其他解决方案相比,它具有相对可读性的优点。但是当变量数量增加时,没有缩放的明显缺点。

ifelse(df$var == "yr1", df$yr1,
  ifelse(df$var == "yr2", df$yr2,
  ifelse(df$var == "yr3", df$yr3,
  ifelse(df$var == "yr4", df$yr4, NA))))

[1] 3050 2062 1036 4001 3075 4083 1085 3061