Julia中for循环内DataFrame股票数据切片失效 单独运行正常且疑似修改原数据集
故障核心原因
- 第一处致命问题是循环条件里使用了带感叹号的
unique!。Julia中带!后缀的函数遵循原地修改约定,unique!(fh_5.symbol)会直接把原本长度为680余万行的股票代码列,替换成长度仅为数千个去重后股票代码的短向量,彻底破坏原数据集的结构匹配性。
这完全匹配观察到的三个现象:- 单独运行GOOG切片代码正常:操作发生在
unique!修改原数据集之前,此时symbol列仍为完整的全量逐行值,生成的布尔索引长度和DataFrame行数完全匹配,可正常执行切片。 - 循环内切片时报
BoundsError:进入循环后首先执行unique!,原symbol列被篡改缩短,后续基于该列生成的布尔索引长度远小于DataFrame总行数,触发索引越界访问。 - 循环中断后原有可正常运行的切片代码失效:原数据集的symbol列已被原地篡改,不再是逐行对应的股票代码值,必须重新读取CSV才能恢复原结构。
- 单独运行GOOG切片代码正常:操作发生在
- 第二处效率缺陷是逐次
leftjoin的实现逻辑:即使修正了unique!的问题,对数千只股票逐个执行左连接的操作方式,会产生大量内存拷贝和重复索引计算,运行效率极低。
修复方案
基础逻辑修正
- 替换
unique!为无修改副作用的unique,生成独立的去重股票代码列表,全程不改动原始fh_5数据集。 - 切片时使用
@view生成数据视图,避免全量数据拷贝带来的内存开销。 - 修正变量初始化逻辑,避免无意义的变量复用造成的作用域混乱。
修复后的可运行代码:
using DataFrames using CSV using Dates # 读取原始全量股票数据 fh_5 = CSV.read("D:\\Julia_Dataframe\\JuliaCon2020-DataFrames-Tutorial\\fh_5yrs.csv", DataFrame) # 生成全量连续日期索引 min_date = minimum(fh_5[!, "date"]) max_date = maximum(fh_5[!, "date"]) date_seq = collect(Dates.Date(min_date):Dates.Day(1):Dates.Date(max_date)) date_range = DataFrame(dates = date_seq) # 遍历所有股票代码,无原地修改副作用 for s in unique(fh_5.symbol) # 生成股票数据视图,减少内存拷贝 stock_slice = @view fh_5[fh_5.symbol .== s, ["date", "close"]] # 按日期对齐左连接 date_range = leftjoin(date_range, stock_slice, on = "dates" => "date") # 将收盘价列重命名为对应股票代码 rename!(date_range, :close => s) end
效率优化方案
生成股票收盘价宽面板的最高效方式是直接使用unstack函数,无需逐次循环连接,可将运行速度提升1~2个数量级:
# 一步生成日期为行、股票代码为列、收盘价为值的宽表面板 close_panel = unstack( select(fh_5, [:date, :symbol, :close]), :date, :symbol, :close )
注:使用
unstack生成的面板会自动覆盖所有出现过的交易日期,如需和连续自然日序列对齐,可将close_panel和之前生成的全日期索引表做一次左连接即可。
内容的提问来源于stack exchange,提问作者Harneet.Lamba
相关产品推荐
相关产品推荐

