如何将识别非ASCII字符的for循环改写为apply系列函数
优化非ASCII字符列的定位代码(从嵌套循环到apply系列)
我有一个包含多个数据表的大型列表,每张表有多个变量,需要定位各表中包含非ASCII字符的列。原嵌套循环代码运行耗时极长,且存在逻辑问题,希望改成apply系列函数提升效率。
示例数据
dat1 <- structure(list(NR = c("DBD-0006", "DBD-0057", "DBD-0095", "GHP-0169", "GHP-0237", "NNB-0243", "NNB-0303", "NNB-0306", "NNB-0359", "NNB-0364"), DATE = c("13-07-2011", "15-12-2010", "09-03-2011", "14-09-2011", "30-06-2010", "16-05-2016", "04-07-2012", "11-07-2012", "05-12-2012", "12-12-2012"), CODE= c("1", "1", "1", "1", "1", "1", "1", "1", "1", "1"), DATE2 = c("18-07-2011", "15-12-2010", "09-03-2011", "14-09-2011", "05-01-2012", "11-05-2016", "05-07-2012", "11-07-2012", "06-12-2012", "12-12-2012"), type = c("YY.90.01", "50.19", "50.37", "50.37", "50.37", "YY.90.00é", # 添加非ASCII字符用于测试 "50.37", "YY.50.01", "YY.82.01", "YY.50.02"), center = c("DBD", "DBD", "DBD", "GHP", "GHP", "NNB", "NNB", "NNB", "NNB", "NNB")), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame")) dat2 <- dat3 <- dat1 tables <- list(df1 = dat1, df2 = dat2, df3 = dat3)
原循环代码(存在逻辑和效率问题)
nonUTF8<- list() for (table in names(tables)) { ##this gives the table names for (item in names(tables[[table]])){ #this gives the variables within each table nonUTF8[[table]] <- tables[[table]] [,(grepl("[^\\x01-\\x7F]", tables[[table]]))] }}
问题分析
- 逻辑错误:
grepl("[^\\x01-\\x7F]", tables[[table]])会对整个数据框的每个元素做判断,返回和数据框同维度的布尔矩阵,直接用来索引列会导致错误;同时内层循环每次都会覆盖nonUTF8[[table]],最终只保留最后一次循环的结果。 - 效率低下:嵌套循环逐表逐列遍历,没有利用R的向量化特性,处理大型数据时速度慢。
优化方案(apply系列函数)
用lapply遍历整个数据表列表,对每个表用sapply判断哪些列存在非ASCII字符,再筛选这些列:
# 定义函数:筛选数据框中包含非ASCII字符的列 filter_non_ascii_cols <- function(df) { # 对每列检查是否存在至少一个非ASCII字符 has_non_ascii <- sapply(df, function(col) { # 仅对字符型列检查,避免因子或数值型列报错 if (!is.character(col)) { return(FALSE) } any(grepl("[^\\x01-\\x7F]", col, perl = TRUE)) }) # 返回筛选后的列,drop=FALSE确保单列时仍返回数据框格式 df[, has_non_ascii, drop = FALSE] } # 应用到整个tables列表 nonUTF8 <- lapply(tables, filter_non_ascii_cols)
代码说明
lapply(tables, filter_non_ascii_cols):批量处理列表中的每个数据表,返回结构一致的结果列表,充分利用向量化操作提升效率。sapply(df, function(col) {...}):对数据框的每一列执行检查,返回布尔向量标记哪些列符合条件。- 添加
is.character(col)判断:避免对非字符型列(比如数值、因子)执行正则匹配,减少不必要的计算和报错。 perl = TRUE:启用Perl正则表达式引擎,提升非ASCII字符的匹配效率。
测试验证
运行上述代码后,nonUTF8中的每个数据表只会保留包含非ASCII字符的列(比如示例中的type列),结果正确且运行效率远高于原嵌套循环。
内容的提问来源于stack exchange,提问作者Rara
相关产品推荐
相关产品推荐

