Создать pandas DataFrame из генератора?

Я создал генератор кортежей, который извлекает информацию из файла, фильтруя только интересующие записи и преобразуя их в кортеж, который возвращает генератор.

Я пытаюсь создать 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 из генератора записей напрямую, без предварительного преобразования его в список?

Примечание. Я использую python 3.3 и pandas 0.12 с Anaconda в Windows.

Update:

Это не проблема чтения файла, мой генератор кортежей делает это хорошо, он сканирует текстовый сжатый файл смешанных записей по строкам и преобразует только нужные данные в правильные типы, затем он дает поля в генераторе кортежей форма. Некоторые номера, он сканирует 2111412 записей в файле размером 130 МБ, около 6.5 ГБ без сжатия, примерно через минуту и ​​с небольшой памятью.

Pandas 0.12 не позволяет генераторам, версия dev позволяет это, но поместить весь генератор в список, а затем преобразовать в кадр. Это неэффективно, но это что-то, что нужно делать внутри pandas. Тем временем я должен думать о покупке еще немного памяти.

Ответ 1

Вы не можете создать DataFrame из генератора с версией <0,4 → 0.12. Вы можете либо обновить себя до версии разработки (получить ее из github и скомпилировать ее, что немного больно для окон, но я бы предпочел эту опцию).

Или вы можете, так как вы сказали, что вы фильтруете строки, сначала фильтруйте их, записывайте в файл и загружайте их с помощью 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

Ответ 2

Чтобы получить эффективную память, читайте куски. Что-то вроде этого, используя класс Виктора Ридера сверху.

df = pd.concat(list(pd.read_csv(Reader(gen()),chunksize=10000)),axis=1)

Ответ 3

Вы, безусловно, можете построить pandas.DataFrame() из генератора кортежей, начиная с версии 19 (и, возможно, ранее). Не используйте .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  ~

Ответ 4

Вы также можете использовать что-то вроде (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.

- Редактировать, 4 декабря: s/row/rows в последней строке