我知道应避免使用R for循环,而应使用矢量化操作。
我希望使用for
循环解决此问题,然后尝试使用apply
系列,然后再使用Rcpp。
我加载了一个包含一列密码(字母数字)的数据集。
一旦加载(样本,速度),我想基于某些条件创建具有值(0,1)的新列" contains_lower_chars"," contains_numbers"等等。
这是我尝试做的,但它不起作用 - 这意味着我创建的每个列都具有相同的值。
library(tidyverse)
set.seed(123)
# load dataset from url, skip the first 16 rows
df <- read.csv('http://datashaping.com/passwords.txt', header = F, skip = 16) %>%
sample_frac(.001) %>%
rename(password = V1)
patterns = c("[a-z]","[A-Z]","[0-9]+")
df$has_lower <- 0
df$has_upper <- 0
df$has_numeric <- 0
for(i in 1:nrow(df)){
for(j in patterns){
n <- ifelse(grepl(j, df$password[i]),1,0)
}
df$has_lower[i] <- n
df$has_upper[i] <- n
df$has_numeric[i] <- n
}
我想到的输出是:
password has_lower has_upper has_numeric
Bigmaccas 1 1 0
0127515559 0 0 1
dbqky73p 1 0 1
答案 0 :(得分:1)
如果我们只是命名你的模式向量,我们可以简化一些事情。例如
patterns = c(has_lower="[a-z]",
has_upper="[A-Z]",
has_numeric="[0-9]+")
for(pattern in names(patterns)) {
df[, pattern] = as.numeric(grepl(patterns[pattern], df$password))
}
基本上我们只是循环遍历每个名称,抓取与该名称对应的正则表达式,然后进行匹配并添加列。
答案 1 :(得分:0)
首先你需要在j循环中更新has.lower has.upper和has.numeric,否则你的word1 = ['word7', 'word11', 'word11']
word2 = ['word8', 'word7']
word3 = ['word9']
word4 = ['word10']
对于这3个案例保持不变。为此,您需要能够遍历列的名称has.lower has.upper和has.numeric:
n
使用names <- c("has_lower","has_upper","has_numeric")
for(i in 1:nrow(df)){
for(j in 1:length(patterns)){
df[i,(names[j])] <- as.numeric(grepl(j, df$password[i]))
}
}
的更快,更好,更紧凑的替代方案以及apply
已经过矢量化的事实:
grepl
注意(与您的问题无关):
我建议您使用df[, c("has_lower","has_upper","has_numeric"):=lapply(patterns, function(x) grepl(x,df$password))]
函数来读取数据集,因为它非常大。
fread
答案 2 :(得分:0)
数据框首先是一个列表。
所以,你可以这样做:
df[c("has_lower", "has_upper", "has_numeric")] <-
lapply(patterns, function(pattern) grepl(pattern, df$password) + 0)
使用+ 0L
代替+ 0
你想要的是整数而不是双打(我建议不做任何事情并保持逻辑)。