【问题标题】:How can I improve the performance of HDF5 reading data?如何提高 HDF5 读取数据的性能?
【发布时间】:2021-10-11 06:09:06
【问题描述】:

我需要的是尽快获得unique date 的值。

我使用代码df = store.df.date.drop_duplicates() 进行检索。这行代码采用6 seconds。但是,如果我使用mysql并将相同的数据保存到mysql,我使用mysql作为日期列indexing之后,使用sql:select distinct date from table,只需要80ms就可以检索到唯一的date值,即60 times 比 HDF5 快。

有什么方法可以让函数read_unique_date 读取HDF5MySQL uses indexes 更快?

我的代码如下:

import pandas as pd
import numpy as np
from itertools import product
from time import time


def generate_data():
    np.random.seed(202108)

    # date = pd.date_range(start="19900101", end="20210723", freq="D")
    #The above is my original code, you can use the following code to speed up the operation.
    date = pd.date_range(start="20210101", end="20210723", freq="D")
    date = pd.DataFrame(date, columns=["date"])

    # code = pd.DataFrame(range(5000), columns=["code"])
    #The above is my original code, you can use the following code to speed up the operation.
    code = pd.DataFrame(range(50), columns=["code"])

    # generate product of the two columns:
    df = pd.DataFrame(product(date["date"], code["code"]), columns=["date", "code"])
    df['data'] = np.random.random(len(df))
    return df


def save_data(filename, df):
    store = pd.HDFStore(filename)
    store['df'] = df
    store.close()
    return


def read_unique_date(file_name):
    store = pd.HDFStore(file_name)
    start = time()
    df = store.df.date.drop_duplicates()
    store.close()
    stop = time()
    print(stop - start)
    return df


def main():
    path = 'd:\\'
    file = 'large data.h5'
    file_name = path + file
    df = generate_data()
    save_data(file_name, df)
    df1 = read_unique_date(file_name)
    print(df1)
    return df1


if __name__ == '__main__':
    main()

结果是:

0.015624761581420898
0       2021-01-01
50      2021-01-02
100     2021-01-03
150     2021-01-04
200     2021-01-05
           ...    
9950    2021-07-19
10000   2021-07-20
10050   2021-07-21
10100   2021-07-22
10150   2021-07-23
Name: date, Length: 204, dtype: datetime64[ns]
%timeit df1 = read_unique_date(file_name)
16.9 ms ± 200 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

我的原始代码的结果:

%timeit df1 = read_unique_date(file_name)
4.89 s ± 119 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

【问题讨论】:

    标签: python pandas dataframe hdf5


    【解决方案1】:

    简短的回答是,除了数据集的键(数据集名称)和连续的数组索引之外,HDF5 根本没有索引。因此,您可以期望以次线性方式直接从文件中执行的唯一查找操作是检索数据集中的第 N 个值。要直接从文件中查找唯一值,HDF5 必须读取整个文件。您可能可以使用 HDF5 组和引用来编造一些杂乱但实用的东西,但是您只是自己实现索引,我不建议您走这条路。

    另一方面,Pandas 使用哈希表、树和二进制搜索来加速各种查找操作。您可以将数据加载到查询的数据框中。但通常您希望在某个时候移动到适当的数据库。 Pandas 和 HDF5 只能带您到此为止。

    【讨论】:

    • 谢谢你的回答,看来我需要选择另外一个数据库如MongoDB。
    【解决方案2】:

    pandas 有一个名为read_hdf 的方法记录在here。您可以简单地阅读您存储的.h5 说:

    read_df = pd.read_hdf('./large data.h5')
    

    您可以将 read_df 作为pandas 数据框访问。

    现在,如果您要问我,存储文件并再次读取它以供定期循环使用并不是一个好主意。我会以数据框的形式保存数据并仅在必要时写入(即我需要内存中的空间或者我需要通过一些共享访问来更新数据库)。我会说应该考虑制定写入和读取策略以优化代码运行。

    顺便说一句,您的代码使我的调试崩溃:

        df = pd.DataFrame(product(date["date"], code["code"]), columns=["date", "code"])
    

    你可能想再看看它。

    【讨论】:

    • generate_data()生成的数据和我的真实数据大小差不多,这些代码在我的调试环境下可以正常运行。我的使用场景是一次写入数据,多次读取。所以,你的使用场景和我的不一样。
    【解决方案3】:

    您的代码是按原样运行的,因此如果没有您想要的输出示例,就很难在此处说出您想要得到什么。此代码生成的近 1.8 GB 数据与您的问题无关,除非我遗漏了某些内容,而这确实是一个与性能相关的问题。如果以下内容不能解决您的问题,我建议您大幅减少生成的数据并提供所需输出的示例,以便人们可以帮助您,而无需假设您想要达到什么目的。

    猜测您想要什么,我认为问题在于您如何消除重复项。您正在从数据框设置 df 中包含的一系列日期中删除重复项,该日期系列等于这个缩减的系列。相反,我相信您想要的是使用 df.drop_duplicates() 从数据框中删除重复项并将日期列指定为子集。

    例如:df.drop_duplicates(subset="date")

    这能解决您的问题吗?

    【讨论】:

    • 我修改了我的代码。我需要的是使用HDF5 like mysql 使60 times 的速度比当前的df = store.df.date.drop_duplicates() 更快。
    • 我认为您的编辑将有助于找出解决方案(如果存在)。这可能只是两者之间的性能差异。我不熟悉 SQL 以及它是如何工作的,并且在我的修补过程中还没有真正深入到微调性能。抱歉,我无法提供更多帮助。
    • 无论如何,非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2011-09-26
    • 1970-01-01
    • 2019-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-10
    • 2013-12-03
    相关资源
    最近更新 更多