对大量数据使用 python 个生成器

Using python generators with lots of data

我有一个包含 25 万个项目的数据集,这些项目在添加到 list/generator 之前需要满足特定条件。为了加快处理速度,我想使用生成器,但我不确定是否使用生成过滤样本的函数来过滤数据,或者我是否应该 return 过滤样本到生成器对象等. 我希望最终对象只包含满足过滤条件的样本,但默认情况下 python 将 return/yield 一个 NoneType 对象。我已经包含示例过滤器函数、数据(真正的问题使用字符串,但为了简单起见,我使用来自随机正态分布的浮点数),以及我打算如何处理下面的数据。

在这种情况下我应该如何有效地使用生成器?为此目的甚至 logical/efficient 使用生成器吗?我知道我可以检查 return 函数中的元素是否为 None 以将其从容器中排除 (list/generator),但是我如何使用生成的函数执行此操作价值观?

# For random data
import numpy as np

# Functions
def filter_and_yield(item_in_data):
    if item_in_data > 0.0:
        yield item_in_data

def filter_and_return(item_in_data):
    if item_in_data > 0.0:
        return item_in_data

# Arbitrary data
num_samples = 250 * 10**3
data = np.random.normal(size=(num_samples,))

# Should I use this: generator with generator elements?
filtered_data_as_gen_with_gen_elements = (filter_and_yield(item) for item in data)

# Should I use this: list with generator elements?
filtered_data_as_lst_with_gen_elements = [filter_and_yield(item) for item in data]

# Should I use this: generator with non-generator elements?
filtered_data_as_gen_with_non_gen_elements = (
    filter_and_return(item) for item in data if filter_and_return(item) is not None)

# Should I use this: list with non-generator elements?
filtered_data_as_lst_with_non_gen_elements = [
    filter_and_return(item) for item in data if filter_and_return(item) is not None]

# Saving the data as csv -- note, `filtered_data` is NOT defined 
# but is a place holder for whatever correct way of filtering the data is
df = pd.DataFrame({'filtered_data': filtered_data})
df.to_csv('./filtered_data.csv')

简短的回答是 none 这些是最好的。 Numpy 和 pandas 包括大量 C 和 Fortan 代码,这些代码适用于存储在连续数组中的硬件级数据类型。 Python 对象,即使是像 intfloat 这样的低级别对象也相对笨重。它们包括标准的 python 对象头并​​分配在堆上。甚至像 > 这样的简单操作也需要调用其中一种方法。

最好尽可能使用 numpy/pandas 函数和运算符。这些包已经重载了标准 python 运算符以在一次调用中处理整组数据。

df = pd.DataFrame({'filtered_data': data[data > 0.0]})

此处,data > 0.0 创建了一个新的 true/false numpy 数组用于比较。 data[...] 创建了一个新数组,其中仅包含 data 的值,这些值也是正确的。

其他说明

filter_and_yield 是一个生成器,它将迭代 0 或 1 个值。 Python 把它变成了一个发电机,因为它有一个 yield。当它 returns None 时, python 将其变成 StopIteration 异常。该生成器的消费者将看不到 None.

(filter_and_yield(item) for item in data) 是 returns 个生成器。如果你使用它,你最终会得到生成器的数据框列。

[filter_and_yield(item) for item in data] 是一个生成器列表(因为 filter_and_yield 是一个生成器)。当 pandas 创建一个列时,它需要知道列的大小。因此它将生成器扩展为列表,就像您在此处所做的那样。你可以为 pandas 做这个,这并不重要。除了 pandas 完成后会删除该列表,从而减少内存使用量。

(filter_and_return(item) for item in data if filter_and_return(item) is not None) 这个可以用,但是很慢。 data 保存硬件级别的整数数组。 for item in data 必须将这些整数中的每一个转换为 python 级整数,而 nfilter_and_return(item) 是一个相对昂贵的函数调用。这可以重写为 (value for value in (filter_and_return(item) for item in data) if value is not None) 以将函数调用次数减半。

[filter_and_return(item) for item in data if filter_and_return(item) is not None] 如上所述。可以这样做,但是完成后删除以节省内存。