在Python中快速加载和查询数据

时间:2019-05-24 13:39:31

标签: python pandas dataframe pickle pytables

我正在用Python做一些数据分析。我有约15,000种由ISIN代码标识的金融产品,以及每种产品的约15列每日数据。我想通过ISIN代码轻松快速地访问数据。

数据在MySQL数据库中。到目前为止,在Python方面,我一直在使用Pandas DataFrame。

我做的第一件事是使用pd.read_sql直接从数据库加载DF。但是,这相对较慢。然后,我尝试将完整的数据库加载到单个DF中并将其序列化为pickle文件。泡菜文件的加载很快,几秒钟。但是,当查询单个产品时,性能与我查询SQL DB的性能相同。这是一些代码:

import pandas as pd
from sqlalchemy import create_engine, engine
from src.Database import Database
import time
import src.bonds.database.BondDynamicDataETL as BondsETL

database_instance = Database(Database.get_db_instance_risk_analytics_prod())

engine = create_engine(
    "mysql+pymysql://"
    + database_instance.get_db_user()
    + ":"
    + database_instance.get_db_pass()
    + "@"
    + database_instance.get_db_host()
    + "/"
    + database_instance.get_db_name()
)
con = engine.connect()


class DataBase:
    def __init__(self):
        print("made a DatBase instance")

    def get_individual_bond_dynamic_data(self, isin):
        return self.get_individual_bond_dynamic_data_from_db(isin, con)

    @staticmethod
    def get_individual_bond_dynamic_data_from_db(isin, connection):
        df = pd.read_sql(
            "SELECT * FROM BondDynamicDataClean WHERE isin = '"
            + isin
            + "' ORDER BY date ASC",
            con=connection,
        )
        df.set_index("date", inplace=True)
        return df


class PickleFile:
    def __init__(self):
        print("made a PickleFile instance")
        df = pd.read_pickle("bonds_pickle.pickle")
        # df.set_index(['isin', 'date'], inplace=True)
        self.data = df
        print("loaded file")

    def get_individual_bond_dynamic_data(self, isin):
        result = self.data.query("isin == '@isin'")
        return result


fromPickle = PickleFile()
fromDB = DataBase()

isins = BondsETL.get_all_isins_with_dynamic_data_from_db(
    connection=con,
    table_name=database_instance.get_bonds_dynamic_data_clean_table_name(),
)

isins = isins[0:50]

start_pickle = time.time()

for i, isin in enumerate(isins):
    x = fromPickle.get_individual_bond_dynamic_data(isin)
    print("pickle: " + str(i))

stop_pickle = time.time()

for i, isin in enumerate(isins):
    x = fromDB.get_individual_bond_dynamic_data(isin)
    print("db: " + str(i))

stop_db = time.time()

pickle_t = stop_pickle - start_pickle
db_t = stop_db - stop_pickle
print("pickle: " + str(pickle_t))
print("db: " + str(db_t))
print("ratio: " + str(pickle_t / db_t))

这导致:     泡菜:7.636280059814453     分贝:6.167926073074341     比例:1.23806283819615

另外,奇怪的是,在DF上设置索引(取消注释构造函数中的行)会减慢一切!

我想尝试使用https://www.pytables.org/index.html替代熊猫。还有其他想法或意见吗?

问候, 乔治(Georgi)

2 个答案:

答案 0 :(得分:0)

因此,整理一下评论中的一些想法:

  • 如果希望在隔离区的SQL端提高速度,请使用mysqlclient代替PyMySQL。
  • 确保要查询的列在SQL表中建立索引(isin用于查询,date用于排序)。
  • 您可以直接在index_col="date" according to the docs中设置read_sql();可能会更快。
  • 我不是熊猫专家,但我认为self.data[self.data.isin == isin]self.data.query("isin == '@isin'")的表现要好。
  • 如果您不需要跨isin查询事物并且想使用泡菜,则可以将每个isin的数据存储在单独的泡菜文件中。
  • 此外,出于SQL注入攻击的守护神Lil Bobby Tables的考虑,请在SQL语句中使用参数,而不是连接字符串。

答案 1 :(得分:0)

将大型数据帧转换为由ISIN代码索引的较小数据帧的字典{isin-> DF}很有帮助。与从DF相比,从字典中检索数据效率更高。同样,在给定ISIN代码的情况下,能够请求单个DF是很自然的。希望这对其他人有帮助。