用于多个索引的循环

时间:2018-04-02 20:32:47

标签: r for-loop apply

我知道应避免使用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

3 个答案:

答案 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你想要的是整数而不是双打(我建议不做任何事情并保持逻辑)。