优化熊猫计算

时间:2017-07-28 00:13:01

标签: python pandas

我在名为sale_transactions的数据库表中有2200万行房产销售数据。我正在执行一项工作,我从该表中读取信息,执行一些计算,并使用结果创建新表的条目。这个过程如下:

for index, row in zipcodes.iterrows(): # ~100k zipcodes
    sql_string = """SELECT * from sale_transactions WHERE zipcode = '{ZIPCODE}' """
    sql_query = sql_string.format(ZIPCODE=row['zipcode'])         
    df = pd.read_sql(sql_query, _engine)
    area_stat = create_area_stats(df) # function does calculations
    area_stat.save() # saves a Django model

目前,在我的macbook pro(16GB RAM)上,此循环的每次迭代大约需要20秒,这意味着代码需要数周才能完成。昂贵的部分是read_sql行。

如何优化此功能?我无法将整个sale_transactions表读入内存,大约是5 GB,因此每次使用sql查询来捕获WHERE子句的相关行。

关于优化大熊猫的大多数答案都谈到了使用分块进行阅读,但是在这种情况下我需要对所有数据组合执行WHERE,因为我在create_area_stats函数中执行计算,例如十多个销售数量年期间。我不能轻松访问装有RAM的机器,除非我开始使用EC2进入城镇,我担心这会花费很多而且非常麻烦。

建议将不胜感激。

2 个答案:

答案 0 :(得分:1)

我也遇到了类似的问题,下面的代码帮助我有效地阅读了数据库(约4千万行)。

offsetID = 0
totalrow = 0



while (True):

    df_Batch=pd.read_sql_query('set work_mem="1024MB"; SELECT * FROM '+tableName+' WHERE row_number > '+ str(offsetID) +' ORDER BY row_number LIMIT 100000' ,con=engine)
    offsetID = offsetID + len(df_Batch)

    #your operation

    totalrow = totalrow + len(df_Batch) 

你必须在表中创建一个名为row_number的索引。因此,此代码将以索引方式读取您的表(100 000行)。例如,当您想要读取200 000 - 210 000行时,您不需要读取0到210 000.它将直接通过索引读取。所以它会提高你的表现。

答案 1 :(得分:0)

由于操作中的瓶颈是SQL WHERE查询,因此解决方案是索引WHERE语句运行的列(即zipcode列)。

在MySQL中,对此的命令是:

ALTER TABLE `db_name`.`table` 
ADD INDEX `zipcode_index` USING BTREE (`zipcode` ASC);

进行此更改后,循环执行速度提高了8倍。

我发现this article非常有用,因为它鼓励使用EXPLAIN进行概要分析,并在keypossible_key值为NULL