Python 如何统计大数据量的嵌套列表中各点的区间覆盖次数?

具体比如:
[[15, 65], [30, 80], [36, 86], [45, 95], [45, 95]]  一个大列表中嵌套了好多小列表,如何统计区间内的每个点被覆盖了几次呢? 比如如果只看 [15, 65], [30, 80]这两个,30-65 这些点就被覆盖了两次

注:因为数据量大,所以当我用两层循环来做的时候内存溢出。。。无奈不知道怎么搞,还请各位大神帮忙,先行谢过!
Python 如何统计大数据量的嵌套列表中各点的区间覆盖次数?


37 回复

数据的取值区间是多少?


import numpy as np
from collections import defaultdict

def count_interval_coverage(points, intervals):
    """
    统计每个点在所有区间中的覆盖次数
    
    参数:
        points: list of float, 需要统计的点坐标
        intervals: list of tuple, 区间列表,每个元组为(start, end)
    
    返回:
        dict: 每个点及其对应的覆盖次数
    """
    # 将点转换为numpy数组便于向量化操作
    points_array = np.array(points)
    counts = np.zeros(len(points_array), dtype=int)
    
    # 对每个区间进行向量化统计
    for start, end in intervals:
        # 使用向量化操作判断每个点是否在区间内
        mask = (points_array >= start) & (points_array <= end)
        counts += mask.astype(int)
    
    # 将结果转换为字典
    return {point: count for point, count in zip(points, counts)}

# 使用示例
if __name__ == "__main__":
    # 示例数据
    points = [1.0, 2.5, 3.0, 4.5, 5.0, 6.5, 7.0]
    intervals = [(1.0, 3.0), (2.0, 4.0), (3.0, 5.0), (4.0, 6.0)]
    
    # 统计覆盖次数
    result = count_interval_coverage(points, intervals)
    
    # 输出结果
    print("点坐标及其覆盖次数:")
    for point, count in result.items():
        print(f"点 {point}: 被 {count} 个区间覆盖")

这个方案的核心思路是使用numpy进行向量化计算,避免了对每个点都进行循环判断。算法复杂度为O(n*m),其中n是点数,m是区间数,但向量化操作能显著提升大数据量下的性能。

对于嵌套列表的情况,如果数据结构是[[x1, y1], [x2, y2], ...],可以这样处理:

def count_nested_points_coverage(nested_points, intervals):
    """
    处理嵌套点列表的区间覆盖统计
    
    参数:
        nested_points: list of list, 嵌套点列表,如[[x1, y1], [x2, y2], ...]
        intervals: list of tuple, 区间列表,每个元组为(start, end)
    
    返回:
        dict: 每个点及其对应的覆盖次数
    """
    # 展平嵌套列表
    all_points = []
    for sublist in nested_points:
        all_points.extend(sublist)
    
    # 使用相同的统计函数
    return count_interval_coverage(all_points, intervals)

如果数据量特别大(百万级以上),可以考虑使用pandas或并行计算进一步优化。

总结:用numpy向量化计算最直接高效。

你好,每一条区间都是 50,最小点是 15, 最大点是 249238172

内存溢出和循环关系不大吧。
既然每个区间差值都是 50,一层循环就够了。

请问一层循环怎么统计呢?

for。。。
if。。。
count+=1

怎么两层就溢出了。

# 造一个结果集
res = [1] * 50

# 然后一层循环, 往上面盖被子
for item in iter(big_list):
for i in range(item[0], item[1]+1):
a[i] += 1

return a

这样应该不会溢出吧

线段树

pandas, query. numpy apply.

我跟 想法一样。

In [3]: count = [0] * 249238172

In [4]: import sys

In [5]: sys.getsizeof(count)
Out[5]: 1993905440

In [6]: 1993905440 / 1024 / 1024
Out[6]: 1901.5364074707031

如果没算错的话需要 2G

  1. 把区间端点映射到有限区间内
    2. 差分前缀扫一遍
    3. 后续操作就看需求了

老铁注意看是两层 list 嵌套,真要这么简单我就不问了。。。 不过还是谢谢哈哈

我一开始就是这么做的,电脑也是这么崩的 (手动笑哭)

一个求巧的方法就是不要用 python 自带的数据结构
转成用 numpy 存…

首先:矩阵类运算用 numpy,其次:数据爆内存了就别放内存,db or nosql db 都是很好的选择,最后,我觉得矩阵运算一下不会爆啊?你 po 下实现代码

把所有数值进行排序。然后遍历,遇到是左边的数则+1,右边的数则-1 即可。复杂度 nlogn

非常感谢大神~

如果每个区间都是确定的上下界差值 50,也就意味着每段的中点就可以表示这个区间。

那么[10, 60]就可以表示为 35,把所有 [x, y] 都转换为 ((x+y)/2) <即单个数字> 并对其按从小到大做排序,这样排出来的集合称为 L。

统计某个点,如 z 被覆盖的次数,就是在 L 中找到大于等于 z-25 且小于等于 z+25 的数字的个数。

数据量能在内存里放得下的话,就直接内存里排序好了,内存里放不下就放进数据库,查询起来也很简单,比如查询 40 被覆盖的数量:

SQL<br>select count(*) from numbers where numbers.value&lt;=65 and numbers.value&gt;=15;<br>

#!/usr/bin/env python
# -- coding: utf-8 --

import numpy as np

MAX = 100

counter_array = np.zeros(MAX)

print(counter_array)

source_list = [[15, 65], [30, 80], [36, 86], [45, 95], [45, 95]]

for index_range in source_list: counter_array[np.arange(*index_range)] += 1

print(counter_array)

[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 1.
1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 2. 2. 2. 2. 2. 2.
3. 3. 3. 3. 3. 3. 3. 3. 3. 5. 5. 5. 5. 5. 5. 5. 5. 5.
5. 5. 5. 5. 5. 5. 5. 5. 5. 5. 5. 4. 4. 4. 4. 4. 4. 4.
4. 4. 4. 4. 4. 4. 4. 4. 3. 3. 3. 3. 3. 3. 2. 2. 2. 2.
2. 2. 2. 2. 2. 0. 0. 0. 0. 0.]

由于 Python 自带的 List 默认内存拓展策略,你可能手动设定 capacity 会内存占用更少。

不过如果是我,没有其他性能需求,一般会比较懒,直接放 PostgreSQL 一把梭了。

厉害了,多谢~

牛掰了,多谢

谢谢啦~

好思路,多谢~

好的,谢谢啦~

哈哈嗯

把数据处理交给数据库是好方法。👍

我知道是两层嵌套,是你想复杂了

你现在的情况应该是量太大,导致爆内存了,可以参考前面楼层说的用数据库去处理

没毛病哈哈

大量数据扔到 pc 机内存去处理肯定是不合适的,所以说你要么就放库里,要么就用服务器吧😂😂😂。我有的时候处理数据就用的单位的空转的服务器,速度杠杠的,美滋滋

回到顶部