Python 如何统计大数据量的嵌套列表中各点的区间覆盖次数?
具体比如:
[[15, 65], [30, 80], [36, 86], [45, 95], [45, 95]] 一个大列表中嵌套了好多小列表,如何统计区间内的每个点被覆盖了几次呢? 比如如果只看 [15, 65], [30, 80]这两个,30-65 这些点就被覆盖了两次
注:因为数据量大,所以当我用两层循环来做的时候内存溢出。。。无奈不知道怎么搞,还请各位大神帮忙,先行谢过!
Python 如何统计大数据量的嵌套列表中各点的区间覆盖次数?
数据的取值区间是多少?
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.
bitmap
我跟 想法一样。
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
- 把区间端点映射到有限区间内
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<=65 and numbers.value>=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 机内存去处理肯定是不合适的,所以说你要么就放库里,要么就用服务器吧😂😂😂。我有的时候处理数据就用的单位的空转的服务器,速度杠杠的,美滋滋
nice~~


