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

如何用Python为超大numpy memmap数组绘制箱线图与直方图?

解决超大numpy memmap数组绘制箱线图的内存不足问题

针对379亿条uint8类型的memmap数组绘制箱线图时的内存溢出问题,核心思路是避免加载全量数据,只计算箱线图所需的关键统计量(最小值、Q1、中位数、Q3、最大值),再手动绘制箱线图。以下是几种可行的实现方法:

方法1:基于值频率统计的精确计算(针对uint8最优)

因为你的数据是uint8类型,取值范围固定为0-255,仅256个可能值,可通过分块统计每个值的出现次数,从频率分布推导统计量,内存占用极小:

  1. 初始化计数数组并加载memmap:

    import numpy as np
    
    count = np.zeros(256, dtype=np.uint64)  # 用uint64避免计数溢出
    data = np.memmap('your_data_file', dtype=np.uint8, mode='r', shape=(37906895000,))
    
  2. 分块遍历数组,累加数值计数:

    block_size = 10**8  # 每次读取1亿条,可根据内存调整大小
    for i in range(0, len(data), block_size):
        block = data[i:i+block_size]
        count += np.bincount(block, minlength=256)
    
  3. 从计数数组计算箱线图统计量:

    total = count.sum()
    cumulative = count.cumsum()
    
    # 计算最小值、最大值
    min_val = np.argmax(count > 0)
    max_val = 255 - np.argmax(count[::-1] > 0)
    
    # 计算Q1、中位数、Q3对应的位置及数值
    q1_pos = total * 0.25
    median_pos = total * 0.5
    q3_pos = total * 0.75
    
    q1_val = np.argmax(cumulative >= q1_pos)
    median_val = np.argmax(cumulative >= median_pos)
    q3_val = np.argmax(cumulative >= q3_pos)
    
  4. 手动绘制箱线图:

    import matplotlib.pyplot as plt
    
    stats = [min_val, q1_val, median_val, q3_val, max_val]
    box = plt.boxplot([stats], patch_artist=True)
    plt.title('Camera Sensor Data Boxplot')
    plt.show()
    

方法2:分块近似计算分位数(通用任意数据类型)

如果处理其他类型的超大数组,可通过分块计算每个子块的统计量,再合并得到整体近似统计量:

  1. 分块计算子块统计量:

    import numpy as np
    
    data = np.memmap('your_data_file', dtype=np.uint8, mode='r', shape=(37906895000,))
    block_size = 10**8
    block_stats = []
    
    for i in range(0, len(data), block_size):
        block = data[i:i+block_size]
        qs = np.percentile(block, [0, 25, 50, 75, 100])
        block_stats.append(qs)
    
  2. 合并子块统计量得到整体结果:

    block_stats = np.array(block_stats)
    overall_stats = np.percentile(block_stats, [0, 25, 50, 75, 100], axis=0)
    
  3. 绘制箱线图:

    import matplotlib.pyplot as plt
    
    plt.boxplot([overall_stats.tolist()])
    plt.title('Approximate Camera Sensor Data Boxplot')
    plt.show()
    

分块越小精度越高,可根据需求调整block_size。

方法3:用Dask自动处理分块(适合复杂分析场景)

如果后续有更多超大数组分析需求,可使用Dask库自动管理分块和内存:

  1. 安装Dask:pip install dask[array]

  2. 加载数据并计算统计量:

    import dask.array as da
    import matplotlib.pyplot as plt
    
    dask_data = da.from_array(
        np.memmap('your_data_file', dtype=np.uint8, mode='r', shape=(37906895000,)),
        chunks=10**8
    )
    qs = da.percentile(dask_data, [0, 25, 50, 75, 100]).compute()
    
  3. 绘制箱线图:

    plt.boxplot([qs.tolist()])
    plt.title('Camera Sensor Data Boxplot (Dask)')
    plt.show()
    

Dask会后台自动分块计算,无需手动处理分块逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:02:46