我的样本数据如下,
main_data = data.frame(var1 = c('abd_cde', 'BPCS', 'POIU', 'CDRD', 'UPqw', 'qwer')),
main_data
var1
1 abd_cde
2 BPCS
3 POIU
4 CDRD
5 UPqw
6 qwer
我有以下代码,我想检查一个变量中的某些条件并输出另一个变量。以下是我编写的代码,
main_data$var2 = 0
for (i in 1:nrow(main_data)) {
if(grepl("_", main_data$var1[i]) == TRUE){
main_data$var2[i] = "1"
}
else if((substr(main_data$var1[i], 1, 1) == 'B') | (substr(main_data$var1[i], 1, 1) == 'C') ){
main_data$var2[i] = "2"
}
else if((substr(main_data$var1[i], 1, 1) == 'P') | (substr(main_data$var1[i], 1, 1) == 'U') ){
main_data$var2[i] = "3"
}
}
要给出代码的要点,如果一个变量包含“_”,我想输出1,如果它以B或C开头,想输出2,如果它以P或U开头,想要输出3
但是这段代码需要花费大量时间才能运行,因为我有大约200万条记录要运行。有没有办法让我们有效率?
我理想的输出是,
var1 var2
1 abd_cde 1
2 BPCS 2
3 POIU 3
4 CDRD 2
5 UPqw 3
6 qwer 0
有人可以帮我这么做吗?
由于
答案 0 :(得分:3)
您可以将它组合成一个表达式(例如,使用多个let viewController: Exercise_Type_ViewController = self.storyboard?.instantiateViewControllerWithIdentifier("Exercise_type") as! Exercise_Type_ViewController
self.presentViewController(viewController, animated: true, completion: nil)
语句),但这很容易阅读,并且应该比循环更快:
ifelse
如果您只想测试以单个字母开头的字符串,> x <- c("foo_bar", "x_y", "Bxx", "Cxx", "Pzz", "Uzz")
> x[grepl('_', x)] <- 1
> x[grepl('^[BC]', x)] <- 2
> x[grepl('^[PU]', x)] <- 3
> x
[1] "1" "1" "2" "2" "3"
函数也可以正常工作。
答案 1 :(得分:3)
如果你需要速度,Rcpp是一个选择。使用Rcpp库和C ++标准库可以实现很多功能。例如,以下是我们如何使用std::strchr()
来查找下划线,一些数组索引,字符比较和三元链来实现您的需求:
library(Rcpp);
cppFunction(includes='#include <cstring>','
IntegerVector f1(CharacterVector x) {
IntegerVector res(x.size());
char c;
for (int i = 0; i < x.size(); ++i)
res[i] =
std::strchr(x[i],\'_\') ? 1 :
(c = x[i][0])==\'B\' || c==\'C\' ? 2 :
c==\'P\' || c==\'U\' ? 3 :
0
;
return res;
}
');
f1(main_data$var1);
## [1] 1 2 3 2 3 0
答案 2 :(得分:3)
dplyr
的最新版本(0.5.0)附带了一个新的case_when
函数,该函数无需使用令人讨厌的嵌套ifelse
结构。您可以使用startsWith
(HT @Psidom)或普通的grepl
来实现它:
library(dplyr)
# string functions don't like factors
main_data %>% mutate(var1 = as.character(var1)) %>%
# for each case (in order), if the left side is true, return the right side
mutate(var2 = case_when(grepl('_', .$var1, fixed = TRUE) ~ 1,
startsWith(.$var1, 'B') | startsWith(.$var1, 'C') ~ 2,
startsWith(.$var1, 'P') | startsWith(.$var1, 'U') ~ 3,
TRUE ~ 0))
# var1 var2
# 1 abd_cde 1
# 2 BPCS 2
# 3 POIU 3
# 4 CDRD 2
# 5 UPqw 3
# 6 qwer 0
# or with grepl (results are identical)
main_data %>% mutate(var1 = as.character(var1)) %>%
mutate(var2 = case_when(grepl('_', .$var1, fixed = TRUE) ~ 1,
grepl('^[BC]', .$var1) ~ 2,
grepl('^[PU]', .$var1) ~ 3,
TRUE ~ 0))
请注意.$var1
符号,这对于dplyr
来说很奇怪,但由于某种原因似乎是必要的。
它看起来也相当活泼; dplyr
尝试在C中运行很多,它似乎就在这里。只需在评论中对@ bgoldst的Rcpp和@ Psidom的data.table运行测试集(显然不太现实):
Unit: microseconds
expr min lq mean median uq max neval
startsWith 1285.372 1384.862 1593.404 1478.276 1689.269 6547.404 100
grepl 1260.778 1395.494 1575.984 1509.890 1752.506 2258.982 100
rcpp 3783.274 4101.735 4562.076 4361.927 4637.183 10818.012 100
data.table 913.635 1069.397 1180.042 1135.440 1290.791 1567.259 100
重新采样到100,000行(可能仍然没有代表性,取决于引擎盖下发生的事情),Rcpp可以预见地消失:
Unit: milliseconds
expr min lq mean median uq max neval
startsWith 21.288367 27.555653 30.904011 29.611775 34.269493 40.80770 100
grepl 57.025665 60.209641 63.748722 62.204733 66.900175 73.81332 100
rcpp 8.090686 8.545949 9.419899 8.764327 9.567707 24.65368 100
data.table 92.093603 100.449884 107.358620 104.229641 107.240123 240.52098 100
无论var1
是因素还是角色,时间都相似。
答案 3 :(得分:1)
这是在R中使用String函数的简单方法。这与Keith提到的类似。
main_data = data.frame(var1 = c('abd_cde', 'BPCS', 'POIU', 'CDRD', 'UPqw', 'qwer'))
main_data$var2<-ifelse(grepl("_",main_data$var1),1,ifelse(grepl("B.*|C.*",main_data$var1),2,ifelse(grepl("P.*|U.*",main_data$var1),3,0)))
在这里,我使用ifelse()遍历所有行并给出你想要的结果。