You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将识别非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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 00:00:10