Python 属性错误:';发电机&x27;对象没有属性';到sql';使用生成器创建datframe时
我正在尝试从fixedwidth文件创建一个datafrmae并加载到postgresql数据库中。我的输入文件非常大(~16GB)和2000万条记录。因此,如果我创建数据帧,它将消耗大部分可用RAM。这需要很长时间才能完成。所以我考虑使用chunksize(使用python生成器)选项并将记录提交到表中。但是它失败了,因为Python 属性错误:';发电机&x27;对象没有属性';到sql';使用生成器创建datframe时,python,python-3.x,pandas,dataframe,generator,Python,Python 3.x,Pandas,Dataframe,Generator,我正在尝试从fixedwidth文件创建一个datafrmae并加载到postgresql数据库中。我的输入文件非常大(~16GB)和2000万条记录。因此,如果我创建数据帧,它将消耗大部分可用RAM。这需要很长时间才能完成。所以我考虑使用chunksize(使用python生成器)选项并将记录提交到表中。但是它失败了,因为'AttributeError:'generator'对象没有属性'to_sql'错误 受这个答案的启发 输入文件:test_file.txt XOXOXOXOXOXO9 A
'AttributeError:'generator'对象没有属性'to_sql'
错误
受这个答案的启发
输入文件:test_file.txt
XOXOXOXOXOXO9
AOAOAOAOAOAO8
BOBOBOBOBOBO7
COCOCOCOCOCO6
DODODODODODO5
EOEOEOEOEOEO4
FOFOFOFOFOFO3
GOGOGOGOGOGO2
HOHOHOHOHOHO1
sample.py
import pandas.io.sql as psql
import pandas as pd
from sqlalchemy import create_engine
def chunck_generator(filename, header=False,chunk_size = 10 ** 5):
for chunk in pd.read_fwf(filename, colspecs=[[0,12],[12,13]],index_col=False,header=None, iterator=True, chunksize=chunk_size):
yield (chunk)
def _generator( engine, filename, header=False,chunk_size = 10 ** 5):
chunk = chunck_generator(filename, header=False,chunk_size = 10 ** 5)
chunk.to_sql('sample_table', engine, if_exists='replace', schema='sample_schema', index=False)
yield row
if __name__ == "__main__":
filename = r'test_file.txt'
engine = create_engine('postgresql://ABCD:ABCD@ip:port/database')
c = engine.connect()
conn = c.connection
generator = _generator(engine=engine, filename=filename)
while True:
print(next(generator))
conn.close()
错误:
chunk.to_sql('sample_table', engine, if_exists='replace', schema='sample_schema', index=False)
AttributeError: 'generator' object has no attribute 'to_sql'
我的主要目标是提高绩效。请帮助我解决这个问题,或者建议更好的方法。提前谢谢。我给你提了一些建议,比如:
def _generator( engine, filename, ...):
for chunk in pd.read_fwf(filename, ...):
yield chunk.to_sql('sample_table', engine, ...) # not sure about this since row was not define
for row in _generator(engine=engine, filename=filename)
print(row)
“chunck_generator”将返回一个“generator”对象,而不是块的实际元素。您需要迭代对象以从中获取块
>>> def my_generator(x):
... for y in range(x):
... yield y
...
>>> g = my_generator(10)
>>> print g.__class__
<type 'generator'>
>>> ele = next(g, None)
>>> print ele
0
>>> ele = next(g, None)
>>> print ele
1
但它似乎在抽搐。我可以这样做:
import pandas.io.sql as psql
import pandas as pd
from sqlalchemy import create_engine
def sql_generator(engine, filename, header=False,chunk_size = 10 ** 5):
frame = pd.read_fwf(
filename,
colspecs=[[0,12],[12,13]],
index_col=False,
header=None,
iterator=True,
chunksize=chunk_size
):
for chunk in frame:
yield chunk.to_sql(
'sample_table',
engine,
if_exists='replace',
schema='sample_schema',
index=False
)
if __name__ == "__main__":
filename = r'test_file.txt'
engine = create_engine('postgresql://USEE:PWD@IP:PORT/DB')
for sql in sql_generator(engine, filename):
print sql
结论:
to_sql方法加载大文件效率不高。所以我在包psycopg2中使用copy_from方法,并在创建数据帧时使用chunksize选项。
在30分钟内加载了980万条记录(约17GB),每条记录有98列
我已经删除了我实际文件的原始引用(我在原始帖子中使用了示例文件)
chunck\u generator
是一个生成器对象,它没有方法到\u sql()
。您可能需要使用current\u chunk=next(chunk)
来获取区块。另外,行
没有定义。@TwistedSim是的,我同意。不管怎样,我都可以解决这个问题。我应该保留数据帧属性。您希望在哪里定义此to_sql
方法?当然不是在所有生成器上,或者在所有iterables上,或者在您创建的特定生成器上,从函数中生成值?如果你想调用DataFrame的方法,你必须在DataFrame上调用它,而不是在其他类型的对象上。我可以使用del[df]或grabage收集器释放每个块内存吗?它应该自己进行垃圾收集。代码工作正常,但to_sql运行非常缓慢。插入100k条记录(100k行,98列—所有文本类型列)需要30分钟。有什么见解吗?你不想分块——你可能想使用一个可以关闭事务的数据库加载实用程序。Postgres似乎提供了一个复制功能,使大文件的加载更加高效。谢谢我找到了加载980万条记录的方法。我使用了部分代码和psycopg2包来加载数据。数据在30分钟内加载
import pandas.io.sql as psql
import pandas as pd
from sqlalchemy import create_engine
def sql_generator(engine, filename, header=False,chunk_size = 10 ** 5):
frame = pd.read_fwf(
filename,
colspecs=[[0,12],[12,13]],
index_col=False,
header=None,
iterator=True,
chunksize=chunk_size
):
for chunk in frame:
yield chunk.to_sql(
'sample_table',
engine,
if_exists='replace',
schema='sample_schema',
index=False
)
if __name__ == "__main__":
filename = r'test_file.txt'
engine = create_engine('postgresql://USEE:PWD@IP:PORT/DB')
for sql in sql_generator(engine, filename):
print sql
import pandas as pd
import psycopg2
import io
def sql_generator(cur,con, filename, boundries, col_names, header=False,chunk_size = 2000000):
frame = pd.read_fwf(filename,colspecs=boundries,index_col=False,header=None,iterator=True,chunksize=chunk_size,names=col_names)
for chunk in frame:
output = io.StringIO()
chunk.to_csv(output, sep='|', quoting=3, escapechar='\\' , index=False, header=False,encoding='utf-8')
output.seek(0)
cur.copy_from(output, 'sample_schema.sample_table', null="",sep="|")
yield con.commit()
if __name__ == "__main__":
boundries = [[0,12],[12,13]]
col_names = ['col1','col2']
filename = r'test_file.txt' #Refer to sample file in the original post
con = psycopg2.connect(database='database',user='username', password='pwd', host='ip', port='port')
cur = con.cursor()
for sql in sql_generator(cur,con, filename, boundries, col_names):
print(sql)
con.close()