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

在Julia中高效合并65000个CSV文件并实现基础统计的优化方案咨询

Efficiently Processing 65,000 CSV Files for Statistical Analysis in Julia

Great question—dealing with tens of thousands of CSV files in Julia can feel like fighting a memory hog when you try to cram everything into one giant DataFrame. Let’s break down the best strategies to handle this efficiently, depending on exactly what kind of stats you need to run:


1. Skip Full Merging Entirely: Calculate Stats Per File First

This is the most efficient approach for basic statistics (means, medians, sums, min/max). Instead of merging all data, compute the stats you need for each individual file, then aggregate those results. You’ll never hold more than one small file in memory at a time.

Example Code

using CSV, DataFrames, Statistics

csv_dir_tmax = cd(readdir, "C:/Users/andrew.bannerman/Desktop/Julia/scripts/GHCN data/ghcnd_all_csv/tmax")

# Initialize a DataFrame to store per-file statistics
file_stats = DataFrame(
    filename = String[],
    row_count = Int[],
    tmax_mean = Float64[],
    tmax_median = Float64[],
    tmax_min = Float64[],
    tmax_max = Float64[]
)

for (idx, fname) in enumerate(csv_dir_tmax)
    println("Processing file $idx: $fname")
    file_path = joinpath("C:/Users/andrew.bannerman/Desktop/Julia/scripts/GHCN data/ghcnd_all_csv/tmax", fname)
    df = CSV.read(file_path, DataFrame)
    
    # Compute stats for this file and add to our results
    push!(file_stats, (
        fname,
        nrow(df),
        mean(df.TMAX),
        median(df.TMAX),
        minimum(df.TMAX),
        maximum(df.TMAX)
    ))
end

# Example: Calculate a weighted overall mean across all files
overall_tmax_mean = sum(file_stats.tmax_mean .* file_stats.row_count) / sum(file_stats.row_count)

Why This Works

  • Memory usage stays tiny: Each file is processed, stats are extracted, then the original file data is garbage-collected immediately.
  • Speed is maximized: No time wasted copying large chunks of data between DataFrames.

2. Incremental Aggregation for Cross-File Groups

If you need stats grouped by a shared column (like Date across all files), don’t merge everything first. Instead, update running totals for each group as you process each file.

Example Code (Date-Based Stats)

using CSV, DataFrames

csv_dir_tmax = cd(readdir, "C:/Users/andrew.bannerman/Desktop/Julia/scripts/GHCN data/ghcnd_all_csv/tmax")

# Use a dictionary to track running totals per date: key=Date, value=(sum_TMAX, count_TMAX)
date_totals = Dict{Date, Tuple{Float64, Int}}()

for (idx, fname) in enumerate(csv_dir_tmax)
    println("Processing file $idx: $fname")
    file_path = joinpath("C:/Users/andrew.bannerman/Desktop/Julia/scripts/GHCN data/ghcnd_all_csv/tmax", fname)
    df = CSV.read(file_path, DataFrame)
    
    for row in eachrow(df)
        dt = row.Date
        tmax_val = row.TMAX
        
        if haskey(date_totals, dt)
            current_sum, current_count = date_totals[dt]
            date_totals[dt] = (current_sum + tmax_val, current_count + 1)
        else
            date_totals[dt] = (tmax_val, 1)
        end
    end
end

# Convert the dictionary to a DataFrame for final analysis
date_stats = DataFrame(
    Date = collect(keys(date_totals)),
    total_TMAX = [val[1] for val in values(date_totals)],
    sample_count = [val[2] for val in values(date_totals)]
)

date_stats.TMAX_mean = date_stats.total_TMAX ./ date_stats.sample_count

Why This Works

  • Memory usage depends on the number of unique groups (e.g., unique dates), not the total number of rows across all files.
  • You avoid loading and merging millions of rows into a single DataFrame.

3. Your Chunking Idea: Make It Stat-First, Not Merge-First

If you must work with chunks (e.g., for more complex analyses that can’t be done per-file), modify your approach to compute stats on each chunk before moving to the next. This way, you never store full chunks of raw data long-term.

Example Code

using CSV, DataFrames, Statistics

csv_dir_tmax = cd(readdir, "C:/Users/andrew.bannerman/Desktop/Julia/scripts/GHCN data/ghcnd_all_csv/tmax")
chunk_size = 20000  # Adjust based on your available memory

# Track overall stats across all chunks
overall_sum = 0.0
overall_count = 0

for chunk_start in 1:chunk_size:length(csv_dir_tmax)
    chunk_end = min(chunk_start + chunk_size - 1, length(csv_dir_tmax))
    println("Processing chunk: files $chunk_start to $chunk_end")
    
    # Compute stats for this chunk
    chunk_sum = 0.0
    chunk_count = 0
    for fname in csv_dir_tmax[chunk_start:chunk_end]
        file_path = joinpath("C:/Users/andrew.bannerman/Desktop/Julia/scripts/GHCN data/ghcnd_all_csv/tmax", fname)
        df = CSV.read(file_path, DataFrame)
        chunk_sum += sum(df.TMAX)
        chunk_count += nrow(df)
    end
    
    # Update overall stats
    overall_sum += chunk_sum
    overall_count += chunk_count
    
    # Optional: Save chunk stats to CSV for record-keeping
    CSV.write("chunk_stats_$chunk_start.csv", DataFrame(chunk_sum=[chunk_sum], chunk_count=[chunk_count]))
end

# Calculate final overall statistics
overall_tmax_mean = overall_sum / overall_count

4. Pre-Initializing a DataFrame (If You Must Merge)

Your idea to pre-initialize a DataFrame is better than repeated vcat() calls—vcat() creates a new DataFrame every time, which wastes time copying data. Here’s how to implement it correctly:

Example Code

using CSV, DataFrames

csv_dir_tmax = cd(readdir, "C:/Users/andrew.bannerman/Desktop/Julia/scripts/GHCN data/ghcnd_all_csv/tmax")

# First pass: Calculate total number of rows across all files (fast, no full load)
total_rows = 0
for fname in csv_dir_tmax
    file_path = joinpath("C:/Users/andrew.bannerman/Desktop/Julia/scripts/GHCN data/ghcnd_all_csv/tmax", fname)
    total_rows += CSV.File(file_path; header=true) |> length
end

# Pre-initialize the final DataFrame with exact size and column types
tmax_all = DataFrame(
    Date = Vector{Date}(undef, total_rows),
    TMAX = Vector{Float64}(undef, total_rows)
)

# Second pass: Fill the pre-allocated DataFrame
current_row = 1
for (idx, fname) in enumerate(csv_dir_tmax)
    println("Processing file $idx: $fname")
    file_path = joinpath("C:/Users/andrew.bannerman/Desktop/Julia/scripts/GHCN data/ghcnd_all_csv/tmax", fname)
    df = CSV.read(file_path, DataFrame)
    num_rows = nrow(df)
    
    # Copy data directly into the pre-allocated slots
    tmax_all[current_row:current_row+num_rows-1, :] = df
    current_row += num_rows
end

Note

Only use this if your total dataset fits comfortably in memory. For 65k files, this is only feasible if each file is very small.


Final Recommendation

For basic statistical analysis, go with either per-file stats or incremental group aggregation. These methods eliminate the need to merge massive datasets entirely, which is the root cause of your slowdown and memory issues.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 03:37:33