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

大型年度犯罪数据库宽表转长表:R代码性能优化求助

问题描述

我需要把一个横向排列的大型年度犯罪数据库转换成纵向DataFrame。这个数据库前5列是描述信息,后面的列对应月度数据,数据按年份堆叠。我的目标是把特定州、特定犯罪类型的所有年度数据整理成纵向列。
由于部分数据行不完整,我必须加判断语句,不然得手动逐个解决问题才能运行代码。

用户原代码

## I added these base modifications to the df
df_15<-read.csv("Incidencia_municipal_2015_2022.csv", fileEncoding = "latin1")
df_15<-df_15%>%select(-colnames(df_15)[c(4,6)])%>%filter(Año<2022)%>%unite(col="Entidad", colnames(df_15)[c(3,5)])%>%unite(col="Tipo",colnames(df_15)[7:9])
df_15$Tipo<-sub(" ", "-", df_15$Tipo)
df_15$Entidad<-sub(" ", "-", df_15$Entidad) 
## 

tn<-unique(df_15$Tipo)
glos2<-data.frame(seq(1:98),tn)
ts<-rep(seq(1:98), times=16219)
df_15$Tipo<-ts
sn<-unique(df_15$Entidad)
cnt<-0
na<-c()

for(m in 1:length(sn)){
  if(m==1){
    abs<-matrix(,nrow = 84,ncol=242844)
    nmsx<-seq(1:242844)
  }
  
  for (i in 1:length(tn)) {
      agsx<-filter(df_15, Entidad==sn[m], Tipo==i)%>%select(colnames(df_15)[5:16])
      agsx<-c(as.matrix(agsx))
      t<-(m-1)*length(tn)+i
      if(length(agsx)==nrow(abs)){
        abs[,t]<-agsx } else{ 
          cnt<-cnt+1
          na[cnt]<-m
        } 
      
      nmsx[t]<-paste(m,i, sep="_")
    }
  
  
  if(m==2466){
    data_2015m<-as_tibble(abs)
    colnames(data_2015m)<-nmsx
  }
  
}

高效优化方案

你的代码性能瓶颈在于两层嵌套的for循环——每次循环都要对整个数据集做过滤,而且矩阵的动态赋值效率极低。R的优势是向量式操作,用tidyr和dplyr的专用函数可以彻底替代循环,速度提升几个数量级,同时代码更简洁易维护。

优化后代码

library(dplyr)
library(tidyr)

# 1. 读取并预处理数据
df_15 <- read.csv("Incidencia_municipal_2015_2022.csv", fileEncoding = "latin1") %>%
  # 移除指定列,直接用列索引
  select(-c(4, 6)) %>%
  filter(Año < 2022) %>%
  # 合并列并直接用连字符分隔,避免后续sub替换
  unite(Entidad, c(3, 5), sep = "-") %>%
  unite(Tipo, c(7, 9), sep = "-")

# 2. 将宽表转成长表:把所有月度数据列转为行记录
long_df <- df_15 %>%
  pivot_longer(
    cols = 5:16, # 对应原代码中选择的月度数据列范围
    names_to = "Mes",
    values_to = "Incidencia"
  ) %>%
  # 生成唯一时间标识,保证后续排序的时间顺序正确
  mutate(Fecha = paste(Año, Mes, sep = "-")) %>%
  arrange(Entidad, Tipo, Fecha)

# 3. 转为目标格式:每个(Entidad, Tipo)组合作为一列,时间作为行
final_df <- long_df %>%
  select(Fecha, Entidad, Tipo, Incidencia) %>%
  pivot_wider(
    names_from = c(Entidad, Tipo),
    values_from = Incidencia,
    # 自动填充缺失值,无需手动判断
    values_fill = NA
  )

性能提升原因

  • 避免循环冗余操作:pivot_longer和pivot_wider都是基于优化的C++底层实现,比纯R循环的效率高几个数量级。
  • 向量式处理:所有数据转换都是一次性批量完成,不需要逐次过滤和赋值。
  • 自动处理缺失:pivot_wider会自动为不完整的行填充NA,省去了手动写判断语句的麻烦。

额外优化建议

  • 读取大型CSV时,用data.table::fread替代read.csv,读取速度会显著提升。
  • 如果月度列的命名有规律(比如Ene_2015),可以用cols = matches("^[A-Za-z]{3}_\\d{4}")来精准匹配,避免依赖列索引。

内容的提问来源于stack exchange,提问作者emithemex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 11:10:43