Создать 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 в последней строке