Pandas 将数据帧转换为内存中类似文件的对象?
我每天将大约200-250万条记录加载到Postgres数据库中 然后,我使用pd.read_sql读取这些数据,将其转换为数据帧,然后执行一些列操作和一些较小的合并。我正在将修改后的数据另存为一个表,供其他人使用 当我做pd.to_sql时,它需要永远。如果我保存一个csv文件并在Postgres中使用COPY FROM,整个过程只需要几分钟,但是服务器在一台单独的机器上,在那里传输文件是一件痛苦的事情 使用psycopg2,看起来我可以使用copy_expert从批量复制中获益,但仍然使用python。如果可能的话,我想避免编写实际的csv文件。我可以在内存中使用熊猫数据帧执行此操作吗 下面是我的pandas代码的一个示例。如果可能的话,我想添加copy_expert或其他东西来加快保存这些数据的速度Pandas 将数据帧转换为内存中类似文件的对象?,pandas,psycopg2,Pandas,Psycopg2,我每天将大约200-250万条记录加载到Postgres数据库中 然后,我使用pd.read_sql读取这些数据,将其转换为数据帧,然后执行一些列操作和一些较小的合并。我正在将修改后的数据另存为一个表,供其他人使用 当我做pd.to_sql时,它需要永远。如果我保存一个csv文件并在Postgres中使用COPY FROM,整个过程只需要几分钟,但是服务器在一台单独的机器上,在那里传输文件是一件痛苦的事情 使用psycopg2,看起来我可以使用copy_expert从批量复制中获益,但仍然使用p
for date in required_date_range:
df = pd.read_sql(sql=query, con=pg_engine, params={'x' : date})
...
do stuff to the columns
...
df.to_sql('table_name', pg_engine, index=False, if_exists='append', dtype=final_table_dtypes)
有人能帮我写示例代码吗?我更喜欢使用熊猫,在记忆中这样做会很好。如果没有,我将只写一个csv临时文件,并这样做
编辑-这是我的最终代码。每个日期(数百万行)只需要几百秒,而不是几个小时
to_sql=“”使用CSV头从STDIN复制%s”“”
Python模块
io
()为类似文件的对象提供了必要的工具
import io
# text buffer
s_buf = io.StringIO()
# saving a data frame to a buffer (same as with a regular file):
df.to_csv(s_buf)
编辑。
(我忘了)为了以后从缓冲区读取,应该将其位置设置为开始:
s_buf.seek(0)
我不熟悉psycopg2
,但根据copy\u expert
和copy\u from
两种方法,都可以使用,例如:
cur.copy_from(s_buf, table)
(对于Python 2,请参见。)我在实现来自ptrj的解决方案时遇到问题 我认为问题源于将缓冲区的位置设置到末尾 见下文:
from StringIO import StringIO
df = pd.DataFrame({"name":['foo','bar'],"id":[1,2]})
s_buf = StringIO()
df.to_csv(s_buf)
s_buf.__dict__
# Output
# {'softspace': 0, 'buflist': ['foo,1\n', 'bar,2\n'], 'pos': 12, 'len': 12, 'closed': False, 'buf': ''}
请注意,pos位于12。我必须将pos设置为0,以便后续的copy_from命令能够工作
s_buf.pos = 0
cur = conn.cursor()
cur.copy_from(s_buf, tablename, sep=',')
conn.commit()
我不知道psycopg2,但您可以尝试这样的方法:
s_buf=io.StringIO()
,df.to_csv(s_buf)
,它将您的df存储在类似缓冲区的文件中。然后可能是从(s_buf,…)复制当前的cur.copy\u,而不是copy\u expert
!不过我还是保留了复印件。当我使用纯pandas.to_sql时,它只花了大约100秒而不是10000秒。做一个真实的回答,这样我就可以接受。很高兴我能帮上忙。谢谢。此外,我还循环查看每个日期以查询该日期。每次我再次连接到数据库时。是否有更好的方法不必连接/重新连接每个环路?就像我连接一次,然后在循环过程中更改查询?我不确定是否理解,但你不能只查询一次整个内容(范围内的所有日期)。如果这个太大,那么可以分块查询。我想它会在数据框中添加另一个带有日期的列。然后,如果不需要,您可以删除此列,或者选择并使用子框架,或者按日期分组并在组中迭代。或者,如果您想完全避免pd.read\u sql
,可以使用copy\u expert
/copy\u to
将数据复制到字符串缓冲区,并使用pd.read\u csv
将其加载到数据帧。这只是我的想法。AttributeError:“\io.StringIO”对象没有属性“write\u cells”
我在周末运行了该代码,没有收到任何错误。星期一我到办公室的时候,我的桌子空了,糟透了。我最终写了临时的csv文件,它完全可以工作。因此,如果我对csv(s_buf)和s_buf.pos=0执行操作,那么它将在不编写csv的情况下工作?@a_bigbadwolf@trench Good point!这是文件/流缓冲区的标准行为(即不是熊猫的过错)。我只是忘了把它包括在内,我道歉。将位置设置为开头的惯用方法是运行sbuf.seek(0)
。
s_buf.pos = 0
cur = conn.cursor()
cur.copy_from(s_buf, tablename, sep=',')
conn.commit()