41

我创建了一个元组生成器,它从文件中提取信息,仅过滤感兴趣的记录并将其转换为生成器返回的元组。

我尝试从以下位置创建一个 DataFrame:

import pandas as pd
df = pd.DataFrame.from_records(tuple_generator, columns = tuple_fields_name_list)

但抛出一个错误:

... 
C:\Anaconda\envs\py33\lib\site-packages\pandas\core\frame.py in from_records(cls, data, index, exclude, columns, coerce_float, nrows)
   1046                 values.append(row)
   1047                 i += 1
-> 1048                 if i >= nrows:
   1049                     break
   1050 

TypeError: unorderable types: int() >= NoneType()

我设法让它在列表中使用生成器,但使用了两倍内存:

df = pd.DataFrame.from_records(list(tuple_generator), columns = tuple_fields_name_list)

我要加载的文件很大,内存消耗很重要。最后一次尝试我的电脑花了两个小时试图增加虚拟内存:(

问题:任何人都知道直接从记录生成器创建 DataFrame 的方法,而无需事先将其转换为列表?

注意:我在 Windows 上将 python 3.3 和 pandas 0.12 与 Anaconda 一起使用。

更新:

读取文件不是问题,我的元组生成器做得很好,它逐行扫描混合记录的文本压缩文件,仅将所需数据转换为正确的类型,然后生成元组生成器形式的字段。一些数字,它在大约一分钟内扫描了 130MB gzip 文件上的 2111412 条记录,未压缩约 6.5GB,并且使用的内存很少。

Pandas 0.12 不允许生成器,开发版允许但将所有生成器放在一个列表中,然后转换为框架。它效率不高,但必须在内部处理熊猫。同时我必须考虑购买更多的内存。

4

5 回答 5

26

从 0.19 版(可能更早)开始,您当然可以从元组生成器构造一个。pandas.DataFrame()不要使用.from_records(); 只需使用构造函数,例如:

import pandas as pd
someGenerator = ( (x, chr(x)) for x in range(48,127) )
someDf = pd.DataFrame(someGenerator)

产生:

type(someDf) #pandas.core.frame.DataFrame

someDf.dtypes
#0     int64
#1    object
#dtype: object

someDf.tail(10)
#      0  1
#69  117  u
#70  118  v
#71  119  w
#72  120  x
#73  121  y
#74  122  z
#75  123  {
#76  124  |
#77  125  }
#78  126  ~
于 2017-04-27T15:04:35.567 回答
20

您不能使用 0.12 版本的 pandas 从生成器创建 DataFrame。您可以将自己更新到开发版本(从 gi​​thub 获取并编译它 - 这在 Windows 上有点痛苦,但我更喜欢这个选项)。

或者你可以,因为你说你正在过滤这些行,首先过滤它们,将它们写入文件,然后使用read_csv或其他方式加载它们......

如果你想变得超级复杂,你可以创建一个类似对象的文件,它会返回以下行:

def gen():
    lines = [
        'col1,col2\n',
        'foo,bar\n',
        'foo,baz\n',
        'bar,baz\n'
    ]
    for line in lines:
        yield line

class Reader(object):
    def __init__(self, g):
        self.g = g
    def read(self, n=0):
        try:
            return next(self.g)
        except StopIteration:
            return ''

然后使用read_csv

>>> pd.read_csv(Reader(gen()))
  col1 col2
0  foo  bar
1  foo  baz
2  bar  baz
于 2013-09-20T12:09:30.263 回答
7

为了使其具有内存效率,请分块读取。像这样,从上面使用 Viktor 的 Reader 类。

df = pd.concat(list(pd.read_csv(Reader(gen()),chunksize=10000)),axis=1)
于 2013-09-20T13:10:09.450 回答
2

您还可以使用类似(Python 在 2.7.5 中测试)

from itertools import izip

def dataframe_from_row_iterator(row_iterator, colnames):
    col_iterator = izip(*row_iterator)
    return pd.DataFrame({cn: cv for (cn, cv) in izip(colnames, col_iterator)})

您还可以调整它以将行附加到 DataFrame。

-- 编辑,12 月 4 日:s/row/rows 在最后一行

于 2013-10-29T18:26:58.320 回答
2

如果生成器就像一个列表DataFrames,你只需要创建一个新DataFrame的列表连接元素:

result = pd.concat(list)

最近我遇到了同样的问题。

于 2018-03-24T16:09:31.263 回答