【问题标题】:Python increase performance of random.samplePython 提高 random.sample 的性能
【发布时间】:2013-01-26 11:30:50
【问题描述】:

我正在编写一个函数来随机选择存储在字典中的元素:

import random
from liblas import file as lasfile
from collections import defaultdict

def point_random_selection(list,k):
    try:
        sample_point = random.sample(list,k)
    except ValueError:
        sample_point = list
    return(sample_point)

def world2Pixel_Id(x,y,X_Min,Y_Max,xDist,yDist):
    col = int((x - X_Min)/xDist)
    row = int((Y_Max - y)/yDist)
    return("{0}_{1}".format(col,row))

def point_GridGroups(inFile,X_Min,Y_Max,xDist,yDist):
    Groups = defaultdict(list)
    for p in lasfile.File(inFile,None,'r'):
        id = world2Pixel_Id(p.x,p.y,X_Min,Y_Max,xDist,yDist)
        Groups[id].append(p)
    return(Groups)

其中 k 是要选择的元素的数量。组就是字典

file_out = lasfile.File("outPut",mode='w',header= h)
for m in Groups.iteritems():
   # select k point for each dictionary key 
   point_selected = point_random_selection(m[1],k)
   for l in xrange(len(point_selected)):
     # save the data 
     file_out.write(point_selected[l])
file_out.close()

我的问题是这种方法非常慢(大约 4 天左右的文件约为 800 Mb)

【问题讨论】:

  • random.sample() 速度已经过优化,但如果你向它投入非常大的输入,你就会遇到不同的问题。 Groups 中有什么内容? Groups 是否填充了 800 MB 文件中的数据点?
  • 亲爱的 Martijn 是的,Gropus 填充了 800 MB 文件中的数据点。如果 liblas 在 C++ 中,也可能瓶颈是 file_out.write(point_selected[l])
  • 你生成了多少数据,你在写什么等等。你是否分析了你的代码并确定它是random.sample()在这里很慢或者你只是猜?
  • 有一些方法可以从文件中随机抽取行样本,而无需将整个文件读入内存。见Python random N lines from large file (no duplicate lines)Python random lines from subfolders
  • 问题是我需要读取点文件 (x,y) 给出网格内空间位置函数的 ID(例如:1 mx 1 m)并随机提取一个点(o更多)对于每个网格。出于这个原因,我需要在整个点文件之前阅读。

标签: python performance optimization random dictionary


【解决方案1】:

您可以在阅读坐标时尝试更新您的示例。这至少使您不必在运行示例之前将所有内容存储在内存中。 这并不能保证让事情变得更快

以下内容基于BlkKnght's excellent answer 从文件输入中构建随机样本,而不保留所有行。这只是将其扩展为保留多个样本。

import random
from liblas import file as lasfile
from collections import defaultdict


def world2Pixel_Id(x, y, X_Min, Y_Max, xDist, yDist):
    col = int((x - X_Min) / xDist)
    row = int((Y_Max - y) / yDist)
    return (col, row)

def random_grouped_samples(infile, n, X_Min, Y_Max, xDist, yDist):
    """Select up to n points *per group* from infile"""

    groupcounts = defaultdict(int)
    samples = defaultdict(list)

    for p in lasfile.File(inFile, None, 'r'):
        id = world2Pixel_Id(p.x, p.y, X_Min, Y_Max, xDist, yDist)
        i = groupcounts[id]
        r = random.randint(0, i)

        if r < n:
            if i < n:
                samples[id].insert(r, p)  # add first n items in random order
            else:
                samples[id][r] = p  # at a decreasing rate, replace random items

        groupcounts[id] += 1

    return samples

上面的函数接受inFile和你的边界坐标,以及样本大小n,并返回每组最多有n个项目的分组样本,统一挑选。

因为你使用id作为组键,我把它简化为只计算col, row元组,没有必要把它变成一个字符串。

你可以将这些写到一个文件中:

file_out = lasfile.File("outPut",mode='w',header= h)

for group in samples.itervalues():
    for p in group:
        file_out.write(p)

file_out.close()

【讨论】:

  • 感谢 Martijn,你总是很棒!!!。我也在寻找一种在 Python 字典中随机选择和替换值的策略。我希望可以加速系统。你怎么看?
  • 我不明白你的意思。上面的代码将问题简化为为每个读取点选择一个随机数;如果事情仍然很慢,那么liblas 读/写代码就是瓶颈。不知道你能做些什么。
  • 示例:运行“for m in Groups.iteritems():” m ('3565_179', [, ]) 我希望随机选择一个元素并将其重新放入字典中。最后,我有一个新字典,其中每个键只有一个点。形成这本新字典,我希望保存文件
  • 但是你为什么从一个样本开始呢?还是您正在编写一个 second 文件,其中 one 从每个组中随机选择?在这种情况下,只需遍历所有组,并写出random.choice() 的结果。无需替换dict 中的列表。
  • 我正在测试您的解决方案:我总是收到此错误消息 Traceback(最近一次调用最后一次):文件“”,第 1 行,in File“” ,第 22 行,在 random_grouped_samples IndexError: list assignment index out of range
猜你喜欢
  • 2011-09-15
  • 2013-06-20
  • 1970-01-01
  • 2017-07-05
  • 1970-01-01
  • 2017-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多