Python中计算数组偏移量的惯用方法

6
我正在尝试计算可变大小数组的起点和偏移量,并将它们存储在一个字典中。以下是我使用非Pythonic方式实现这个功能的代码。不确定是否应该使用map函数、lambda函数或列表推导式来使代码更Pythonic。
基本上,我需要根据总大小切割数组块,并将xstart、ystart、x_number_of_rows_to_read和y_number_of_columns_to_read存储在字典中。总大小是可变的。如果可以加载整个数组到内存并使用numpy索引,则一定会这样做。原点和偏移量用于将数组输入numpy中。
intervalx = xsize / xsegment #Get the size of the chunks
intervaly = ysize / ysegment #Get the size of the chunks

#Setup to segment the image storing the start values and key into a dictionary.
xstart = 0
ystart = 0
key = 0

d = defaultdict(list)

for y in xrange(0, ysize, intervaly):
    if y + (intervaly * 2) < ysize:
        numberofrows = intervaly
    else:
        numberofrows = ysize - y

    for x in xrange(0, xsize, intervalx):
        if x + (intervalx * 2) < xsize:
            numberofcolumns = intervalx

        else:
            numberofcolumns = xsize - x
        l = [x,y,numberofcolumns, numberofrows]
        d[key].append(l)
        key += 1
return d

我意识到xrange并不适合3的移植。


1
xrange很好 - 2to3可以毫不费力地处理它。 - mgilson
你考虑过使用 h5py 吗?它允许你使用 numpy 语法来处理数组,而无需将所有元素加载到内存中。 - jfs
我已经考虑过使用h5py和numpy.memmap,但是我不认为我可以应用它们。具体来说,该数组是一张图片,而不是原始数组,并且我正在使用GDAL将图像读取为numpy数组。我需要剥离头文件,然后处理数组,然后重新应用头文件。直接访问磁盘是否可能/更好? - Jzl5325
4个回答

7
这段代码看起来还不错,除了你使用的defaultdict。列表似乎是更好的数据结构,因为:
  • 你的键是连续的
  • 你在字典中存储的是一个只有另一个列表作为唯一元素的列表。

你可以做的一件事:

  • 使用三目运算符(我不确定这是否会有所改进,但代码行数会更少)

以下是经过我的建议修改过的代码。

intervalx = xsize / xsegment #Get the size of the chunks
intervaly = ysize / ysegment #Get the size of the chunks

#Setup to segment the image storing the start values and key into a dictionary.
xstart = 0
ystart = 0

output = []

for y in xrange(0, ysize, intervaly):
    numberofrows = intervaly if y + (intervaly * 2) < ysize else ysize -y
    for x in xrange(0, xsize, intervalx):
        numberofcolumns = intervalx if x + (intervalx * 2) < xsize else xsize -x
        lst = [x, y, numberofcolumns, numberofrows]
        output.append(lst)

        #If it doesn't make any difference to your program, the above 2 lines could read:
        #tple = (x, y, numberofcolumns, numberofrows)
        #output.append(tple)

        #This will be slightly more efficient 
        #(tuple creation is faster than list creation)
        #and less memory hungry.  In other words, if it doesn't need to be a list due
        #to other constraints (e.g. you append to it later), you should make it a tuple.

现在要获取您的数据,您可以使用offset_list=output[5]而不是offset_list=d[5][0]

谢谢,我没有考虑使用列表,但是它比使用字典更有意义,因为我不需要通过键来跟踪位置。 - Jzl5325
2
在这里,使用元组或者是命名元组(namedtuple)似乎更加合适,而不是使用子列表。 - jfs
如果在lst = [...]行中去掉[],你将得到一个元组。没有什么困难的。 - jfs
@mgilson 谢谢!我不知道元组会是更好的选择和/或更快的选择。我会做出改变。不幸的是,这些行已经很快了,但我将采取任何速度提升来抵消我使用GDAL时的IO问题。 - Jzl5325
@Jzl5325:使用元组的原因不是速度,而是它们传达的语义:元组具有结构,列表具有顺序。 - jfs
显示剩余4条评论

0

虽然这不会改变你的算法,但更符合Python风格的编写if/else语句的方式是:

numberofrows = intervaly if y + intervaly * 2 < ysize else ysize - y

用这个代替:

if y + (intervaly * 2) < ysize:
    numberofrows = intervaly
else:
    numberofrows = ysize - y

(对于另一个if/else语句同样适用)。


为什么这更符合Python的风格呢?它很难解析。三元条件应该谨慎使用。 - Henry Gomersall
我在维基百科上查看了三元运算符的文章,但并没有看到它在可读性或速度方面有所改进。在像Python这样的语言中,三元条件语句的目的是什么? - Jzl5325
由于“Pythonic”的定义在PEP8之外是主观的,所以这只是我所学到的。我个人认为它同样易读,在某些情况下甚至更易读,特别是在相似结构在同一块中出现多次的情况下。无论如何,各有所好。 - kamek
1
@Jzl5325 三元条件语句是在2.5版本中才被添加的,因此它显然不是核心功能。我认为它的价值在于当你有一个简单的布尔变量时:extinguisher = water if paper_fire else co2 - Henry Gomersall
@HenryGomersall 那确实很有道理,而且更易读。谢谢。 - Jzl5325

0

这是一个很长的一行代码:

d = [(x,y,min(x+xinterval,xsize)-x,min(y+yinterval,ysize)-y) for x in 
xrange(0,xsize,xinterval) for y in xrange(0,ysize,yinterval)]

0

是的,但请看我的原始帖子评论。 - Jzl5325

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接