我有许多类似变量的数据,还有一个额外的变量,它指示我真正想要的那些类似变量中的一个。使用循环我可以查找正确的值,但数据很大,循环很慢,看起来这应该是可矢量化的。我只是没弄明白。
编辑:所选变量将在同一数据框中用作新变量,因此顺序很重要。下面给出的例子中没有显示许多其他变量。
示例数据集:
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'
有什么想法吗?非常感谢..
答案 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)
我喜欢dplyr
和tidyr
的语法:
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