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

R语言数据框循环优化:替换耗时for循环的高效方案

R语言大尺寸数据框匹配替换的性能优化方案

问题背景

处理20万行的datapmi数据框与400行的correccionpmis数据框,基于PMIGTDTipo列匹配后,将datapmi的PMI和Inspection_Procedure列替换为correccionpmis中的校正值。原for循环耗时约1分30秒,尝试sapply未解决性能问题,寻求高效优化方案。

原循环代码

for(j in (1:nrow(correccionpmis))){
   corr<-which(datapmi$PMIGTDTipo==correccionpmis$PMIGTDTipo[j])
   datapmi$PMI[corr]<-correccionpmis$PMIcorregido[j]
   datapmi$Inspection_Procedure[corr]<-correccionpmis$Tipocorregido[j]
}

尝试的sapply代码

mi_fun <- function(i) {
   corr<-which(datapmi$PMIGTDTipo==correccionpmis$PMIGTDTipo[i])
  datapmi$PMI[corr]<-correccionpmis$PMIcorregido[i]
  datapmi$Inspection_Procedure[corr]<-correccionpmis$Tipocorregido[i]
  print(difftime(Sys.time(),t0))
}

sapply(1:nrow(correccionpmis), mi_fun) 

数据结构

correccionpmis(前6行)

structure(list(Linea = c("LINEA NGVS", "FUNDICION", "LINEA NGVS", 
"LINEA NGVS", "RX DIGITAL", "FUNDICION"), PMI = c(" Aceptabilidad Geometría Interna del Vano 2 con P/NP", 
"(2) TEST ESCORIAS INICIAL", "Aceptabilidad de inclusiones", 
"Aceptabilidad Rechupe", "Adjuntar las placas en SAP (SI/NO)", 
"BACKUP CALIENTE TIEMPO HASTA 1450ºC (PRUEBA PIRO TC)"), GTD = c("Indicar Aceptabilidad Geometría Interna del Vano 2 con P/NP", 
"(2) Anotar Valor Dross Test (ANTES DE AFINADO)", "Indicar Aceptabilidad Inclusión", 
"Indicar Aceptabilidad Rechupe", "Adjuntar las placas en SAP (SI/NO)", 
"BACKUP CALIENTE *SI SE HACE PRUEBA Piro-Tc Tiempo desde inicio de fusión hasta que el caldo alcance los 1450ºC (en minutos)"
), Tipo = c("Boolean", "Single Numeric", "Boolean", "Boolean", 
"Single Numeric", "Single Numeric"), PMIcorregido = c("Aceptabilidad Geometría Interna del Vano 2 con P/NP", 
"(2) DROSS TEST INICIAL", "Aceptabilidad de Inclusión", "Aceptabilidad de Rechupe", 
"Adjuntar las placas en SAP (SI/NO)", "TIEMPO HASTA 1450ºC (PRUEBA PIRO TC)"
), Tipocorregido = c("Boolean", "Single Numeric", "Boolean", 
"Boolean", "Boolean", "Single Numeric"), PMIGTDTipo = c(" Aceptabilidad Geometría Interna del Vano 2 con P/NP Indicar Aceptabilidad Geometría Interna del Vano 2 con P/NP Boolean", 
"(2) TEST ESCORIAS INICIAL (2) Anotar Valor Dross Test (ANTES DE AFINADO) Single Numeric", 
"Aceptabilidad de inclusiones Indicar Aceptabilidad Inclusión Boolean", 
"Aceptabilidad Rechupe Indicar Aceptabilidad Rechupe Boolean", 
"Adjuntar las placas en SAP (SI/NO) Adjuntar las placas en SAP (SI/NO) Single Numeric", 
"BACKUP CALIENTE TIEMPO HASTA 1450ºC (PRUEBA PIRO TC) BACKUP CALIENTE *SI SE HACE PRUEBA Piro-Tc Tiempo desde inicio de fusión hasta que el caldo alcance los 1450ºC (en minutos) Single Numeric"
)), row.names = c(1L, 4L, 10L, 16L, 17L, 19L), class = "data.frame")

datapmi(前6行)

structure(list(Linea = c("PREPARACION DE MOLDE", "PREPARACION DE MOLDE", 
"PREPARACION DE MOLDE", "PREPARACION DE MOLDE", "PREPARACION DE MOLDE", 
"CERAMICAS"), Nodo = c("MOLDE_PREPARACION DE MOLDE", "MOLDE_PREPARACION DE MOLDE", 
"MOLDE_PREPARACION DE MOLDE", "MOLDE_PREPARACION DE MOLDE", "MOLDE_PREPARACION DE MOLDE", 
"MOLDE_CERAMICAS"), PuestoID = c("PP009C", "PP009C", "PP009C", 
"PP009C", "PP009C", "PP058C"), Puesto = c("Descerado + Quemado", 
"Descerado + Quemado", "Descerado + Quemado", "Descerado + Quemado", 
"Descerado + Quemado", "Baños ceramicos Agua 2 - R4"), PartNumber = c("11013340", 
"11013340", "11013340", "11013340", "11013340", "11013340"), 
    SerialNumber = c("16817", "16817", "16817", "16817", "16817", 
    "16895"), OrdenFab = c("226489169", "226489169", "226489169", 
    "226489169", "226489169", "226489725"), OP = c(600L, 600L, 
    600L, 600L, 600L, 500L), OF_OP = c("226489169_600", "226489169_600", 
    "226489169_600", "226489169_600", "226489169_600", "226489725_500"
    ), FechaFin_OP = structure(c(NA, NA, NA, NA, NA, 1591602784
    ), class = c("POSIXct", "POSIXt"), tzone = "UTC"), Status_OP = c("Partial", 
    "Partial", "Partial", "Partial", "Partial", "Complete"), 
    Zone = c("", "", "", "", "", ""), PMI = c("Presión Autoclave", 
    "Tiempo Presurización", "Videoscopio", "Hora Arranque Ciclo", 
    "Tiempo de despresurización", "Peso Molde"), GTD = c("Presión del autoclave tras 7 minutos", 
    "Tiempo hasta 6 bares", "Control videoscopio OK s/ficha de producto", 
    "Hora de ciclo", "Tiempo de despresurización", "Peso del Molde"
    ), Dimension_Type = c("", "", "", "", "", ""), Metodo_Medicion = c("Display microtol", 
    "Cronómetro", "Videoscopio", "Reloj", "Cronómetro", "Báscula"
    ), Frecuencia = c("100%", "100%", "100%", "100%", "100%", 
    "100%"), PMI_Descripcion = c("Presión Autoclave Presión del autoclave tras 7 minutos-Nominal:9.750000 Lim Sup:10.000000 Lim Inf:8.500000", 
    "Tiempo Presurización Tiempo hasta 6 bares-Nominal:4.000000 Lim Sup:4.400000 Lim Inf:0.000000", 
    "Videoscopio Control videoscopio OK s/ficha de producto", 
    "Hora Arranque Ciclo Hora de ciclo-Nominal:0.000000 Lim Sup:2400.000000 Lim Inf:0.000000", 
    "Tiempo de despresurización Tiempo de despresurización-Nominal:3.000000 Lim Sup:8.000000 Lim Inf:0.000000", 
    "Peso Molde Peso del Molde-Nominal:59.900000 Lim Sup:64.400000 Lim Inf:55.400000"
    ), PMI_Rango = c("9.750 (8.500-10.00)", "4.000 (0.000-4.400)", 
    "", "0.000 (0.000- 2400)", "3.000 (0.000-8.000)", "59.90 (55.40-64.40)"
    ), Inspection_Procedure = c("Single Numeric", "Single Numeric", 
    "Boolean", "Single Numeric", "Single Numeric", "Single Numeric"
    ), Criticidad = c("MINOR", "MINOR", "MINOR", "MINOR", "MINOR", 
    "MINOR"), LimInf = c(8.5, 0, 0, 0, 0, 55.4000015258789), 
    LimSup = c(10, 4.40000009536743, 0, 2400, 8, 64.4000015258789
    ), Nominal = c(9.75, 4, 0, 0, 3, 59.9000015258789), Es_Obligatoria = c("1", 
    "1", "1", "1", "1", "1"), Valor = c("9,5", "3,61", "1", "10", 
    "7", "63,6"), Estatus_PMI = c("Complete", "Complete", "Complete", 
    "Complete", "Complete", "Complete"), Usuario = c("82300", 
    "82300", "82300", "82300", "82300", "82127"), Comentarios = c("", 
    "", "", "", "", ""), Fecha_Registro = structure(c(1591269448, 
    1591269267, 1591269303, 1591269285, 1591269458, 1591595580
    ), class = c("POSIXct", "POSIXt"), tzone = "UTC"), Responsable = c("Operator", 
    "Operator", "Operator", "Operator", "Operator", "Operator"
    ), NCP_ID = c("NCP_2020_9881", "NCP_2020_9881", "NCP_2020_9881", 
    "NCP_2020_9881", "NCP_2020_9881", NA), GrupoDefecto = c("Genérico", 
    "Genérico", "Genérico", "Genérico", "Genérico", NA), Defecto = c("Incorrecto", 
    "Incorrecto", "Incorrecto", "Incorrecto", "Incorrecto", NA
    ), NCP_status = c("APROBADO", "APROBADO", "APROBADO", "APROBADO", 
    "APROBADO", NA), año = structure(c(1577836800, 1577836800, 
    1577836800, 1577836800, 1577836800, 1577836800), class = c("POSIXct", 
    "POSIXt"), tzone = "UTC"), cuatri = structure(c(1585699200, 
    1585699200, 1585699200, 1585699200, 1585699200, 1585699200
    ), class = c("POSIXct", "POSIXt"), tzone = "UTC"), mes = structure(c(1590969600, 
    1590969600, 1590969600, 1590969600, 1590969600, 1590969600
    ), class = c("POSIXct", "POSIXt"), tzone = "UTC"), semana = structure(c(1590969600, 
    1590969600, 1590969600, 1590969600, 1590969600, 1591574400
    ), class = c("POSIXct", "POSIXt"), tzone = "UTC"), dia = structure(c(1591228800, 
    1591228800, 1591228800, 1591228800, 1591228800, 1591574400
    ), class = c("POSIXct", "POSIXt"), tzone = "UTC"), PMIGTDTipo = c("Presión Autoclave Presión del autoclave tras 7 minutos Single Numeric", 
    "Tiempo Presurización Tiempo hasta 6 bares Single Numeric", 
    "Videoscopio Control videoscopio OK s/ficha de producto Boolean", 
    "Hora Arranque Ciclo Hora de ciclo Single Numeric", "Tiempo de despresurización Tiempo de despresurización Single Numeric", 
    "Peso Molde Peso del Molde Single Numeric")), row.names = c(NA, 
6L), class = "data.frame")

优化方案

原方法效率低的原因

原循环和sapply本质都是逐行迭代,每次迭代都要遍历20万行数据查找匹配项,400次迭代总计进行8000万次比较操作,时间复杂度极高。而基于索引的连接操作可以一次性完成匹配,效率提升显著。

方案1:使用dplyr进行左连接替换

library(dplyr)

# 提取校正数据中需要的匹配列和替换列
correccion_clean <- correccionpmis %>%
  select(PMIGTDTipo, PMIcorregido, Tipocorregido)

# 左连接并替换目标列,无匹配项则保留原数据
datapmi_optimized <- datapmi %>%
  left_join(correccion_clean, by = "PMIGTDTipo") %>%
  mutate(
    PMI = coalesce(PMIcorregido, PMI),
    Inspection_Procedure = coalesce(Tipocorregido, Inspection_Procedure)
  ) %>%
  select(-PMIcorregido, -Tipocorregido)

方案2:使用data.table进行原地更新(性能最优)

data.table针对大数据操作做了深度优化,支持原地修改,内存占用更低,速度更快:

library(data.table)

# 转换为data.table格式
setDT(datapmi)
setDT(correccionpmis)

# 基于PMIGTDTipo匹配,直接更新原数据框的目标列
datapmi[correccionpmis, 
        `:=`(PMI = i.PMIcorregido, Inspection_Procedure = i.Tipocorregido),
        on = .(PMIGTDTipo)]

注意事项

  • 如果correccionpmis中存在重复的PMIGTDTipo值,建议先去重:correccionpmis <- correccionpmis %>% distinct(PMIGTDTipo, .keep_all = TRUE)(dplyr)或`corre
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 12:45:34