从逗号分隔的字符串列表高效创建多维数组,需要使用.split(',')。

4
我正在尝试将一个简单的计算,目前在一个for循环中,推入一个numpy数组。在这种情况下,它是对一个字符串列表进行的计算,形式如下:

strings = ['12,34','56,78'...]

我需要:
  1. 通过逗号分隔符拆分字符串并生成两个整数,例如
    strings = [[12, 34],[56, 78]...]

  2. 过滤嵌套列表,仅保留那些符合某些任意条件的成员,例如子列表中的两个数字都在特定范围内。

我正试图熟悉numpy库,但我无法利用提高的计算速度,而不增加处理初始列表的开销。例如,我的直觉是在创建数组之前在Python中执行split()int()转换,但这比简单的for循环更昂贵。
除此之外,我似乎无法将各种需要使用numpy操作的数组拼接起来,以从初始列表中创建的数组中完成此操作。是否有合理的方法来做这件事,或者对于仅使用一次的数组之类的东西,这是一个不可挽回的事情?
注意:这里有一个较旧的答案here,建议在Python中进行字符串操作,但它没有比较运行时间,也可能已经过时。
我的尝试比较:
import random
import datetime as dt
import numpy as np

raw_locs = [str(random.randint(1,100)) + ',' + str(random.randint(1,100)) 
            for x in xrange(100000)]

if __name__ =='__main__':

    # Python approach
    start1 = dt.datetime.now()
    results = []
    for point in raw_locs:
        lon, lat = point.split(",")
        lat = int(lat)
        lon = int(lon)
        if 0 <= lon <= 50 and 50 <= lat <= 100:
            results.append(point)
    end1 = dt.datetime.now()

    # Python list comprehension prior to numpy array
    start2 = dt.datetime.now()
    converted_list = [map(int, item.split(',')) for item in raw_locs]
    end2 = dt.datetime.now()

    # List comprehension + numpy array creation
    start3 = dt.datetime.now()
    arr = np.array([map(int, item.split(',')) for item in raw_locs])
    end3 = dt.datetime.now()

    start4 = dt.datetime.now()   
    results2 = arr[((0 <= arr[:,0]) & (arr[:,0] <= 50) 
                    & (50 <= arr[:,1]) & (arr[:,1] <= 100))]
    end4 = dt.datetime.now()

    # Print results
    print "Pure python for whole solution took:                {}".format(end1 - start1)
    print "Just python list comprehension prior to array took: {}".format(end2 - start2)
    print "Comprehension + array creation took:                {}".format(end3 - start3)
    print "Numpy actual calculation took:                      {}".format(end4 - start4)
    print "Total numpy time:                                   {}".format(end4 - start3)

1
我相信你可能遇到了 XY 问题。你是真的只是为了避免使用 for 循环而将其转换为字符串表示吗?还是格式已经给定了?对于 numpy 来说,字符串列表不是一个非常方便的起点。将它们用逗号连接起来并解析可能会更快。 - Andras Deak -- Слава Україні
@AndrasDeak 你说得很有可能是对的。实际上,这个问题是几个小时前在这里另一个问题的启发。有人试图处理数万亿个这样的项目,而我经常进行类似的操作,所以我很好奇是否可以克服数组创建开销,在这些情况下这真的很重要(通过行分析,if检查占运行时间的约26%,因此可能快几个数量级)。 - roganjosh
此外,仅凭挂钟时间来判断可能不是最好的指标,timeit 可能更有用。让我看看它在我的端上显示了什么。 - Andras Deak -- Слава Україні
1个回答

4
虽然我认为如果您使用类似于timeit模块之类的东西,您的时间会更精确,但我认为最大的问题是您正在解析字符串列表。Numpy的内置方法适用于任何一种情况。请注意,在您的numpy情况下,np.array()的输入是一个带有其他内容的列表推导式。
这是我的建议:使用逗号将字符串列表连接成单个逗号分隔的字符串,使用numpy.fromstring解析它,然后重新调整结果以具有两列:
arr = np.fromstring(','.join(raw_locs),sep=',').reshape(-1,2)

在我的笔记本电脑上加上以上内容的时间:

Pure python for whole solution took:                0:00:00.128965
Just python list comprehension prior to array took: 0:00:00.156092
Comprehension + array creation took:                0:00:00.186023
Join + fromstring took:                             0:00:00.035040
Numpy actual calculation took:                      0:00:00.001355
Total numpy time:                                   0:00:00.222454

请注意,默认情况下上述代码将创建一个numpy.float64数据类型的数组,即使您的输入是整数。如果您想保持数组的整数值,可以手动传递dtype=np.int64关键字参数给fromstring函数。

1
我主要使用了datetime,这样我就可以将组件部分分解为一个简单的MCVE。这是一个非常巧妙的解决方案,可以将字符串操作从Python中分离出来,这也是我在搜索时一直遇到的方法。我会等待看看是否还有其他人有意见,但我认为这是我们能得到的最好的解决方案。 - roganjosh
1
@roganjosh 我完全可以等待其他可能的答案,您不必将我的答案标记为已接受 :) - Andras Deak -- Слава Україні

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