【问题标题】:Memory-efficient lookup table of DataFrames in PythonPython中DataFrames的内存高效查找表
【发布时间】:2022-03-09 04:45:23
【问题描述】:

在我询问的previous question 中,一位响应者建议我将我的数据组织为 DataFrame 的 DataFrame。

df = pd.DataFrame({'Form': {0:'SUV', 1:'Truck', 2:'SUV', 3:'Sedan', 4:'SUV', 5:'Truck'},
                   'Make': {0:'Ford', 1:'Toyota', 2:'Honda', 3:'Ford', 4:'Honda', 5:'Toyota'},
                   'Color': {0:'White', 1:'Black', 2:'Gray', 3:'White', 4:'White', 5:'Black'},
                   'Driver age': {0:25, 1:37, 2:21, 3:54, 4:50, 5:67},
                   'Data': {0: pd.DataFrame([[0, 0], [0.25, 1.7], [1.2, 1.8], [4.5, 4.0]]), 
                            1: pd.DataFrame([[0, 0], [0.15, 1.3], [1.6, 1.3], [4.2, 4.1]]), 
                            2: pd.DataFrame([[0, 0], [0.24, 1.2], [1.3, 1.6], [4.1, 3.9]]), 
                            3: pd.DataFrame([[0, 0], [0.45, 1.6], [1.8, 1.8], [4.2, 4.6]]), 
                            4: pd.DataFrame([[0, 0], [0.85, 1.9], [1.5, 1.7], [4.5, 4.3]]), 
                            5: pd.DataFrame([[0, 0], [0.35, 1.8], [1.5, 1.8], [4.6, 4.1]])} })               

DataFrames 的这个 DataFrame 允许我有条件地选择数据组,例如df[(df['make'] == 'SUV') and (df['age']<=40)]['Data']。问题是当每一行数据本身都是一个很大的.csv时,就很难加载到内存中。

我正在寻找像 h5py 这样可以“流式传输”/读取特定数据部分的模块(它允许指定一个键,例如 df = pd.read_hdf('large_data.hdf', 'SUV-Ford-White-25'),除了 而不是嵌套字典我希望它是一个允许过滤的,例如df = module.read(large_data.some_ext, make == 'SUV', 20 <= age <= 40)xarraypandas 是否有内置的东西?

【问题讨论】:

  • 如果你可以访问一个shell,你可以在加载到pandas之前使用subprocess.runjanitor.io.read_commandline进行预过滤

标签: python pandas dataframe python-xarray h5py


【解决方案1】:

h5py 一样,PyTables(又名tables)也可以创建和读取 HDF5 文件。熊猫 使用 PyTables “在后台”创建和读取 HDF5 文件。 PyTables 具有一些有用的搜索功能,可以完全按照您的意愿进行操作。为了完整起见,我在此答案的末尾包含了一个简短的摘要,比较了每个包。

这是我创建的一个示例,用于演示使用您的数据框(字典)数据的搜索行为。

创建 HDF5 文件
注意:创建 HDF5 文件的大部分“工作”是将字典数据(重新)组织到 NumPy 重新数组中。如果修改了数据结构(移动字典键/值级别),则可以简化该过程——假设结构尚未设置。
步骤总结:

  1. 创建一个定义数据字段(列)的np.dtype
  2. 通过计算与每个主键关联的字典项的数量来确定重新排列的行。
  3. 使用上面的 1 和 2 创建一个由零组成的重新数组。
  4. 遍历字典并将键和值映射到适当的行和字段(列)名称。

以下代码

import tables as tb
import numpy as np

data_dict = {'Form': {0:'SUV', 1:'Truck', 2:'SUV', 3:'Sedan', 4:'SUV', 5:'Truck'},
                   'Make': {0:'Ford', 1:'Toyota', 2:'Honda', 3:'Ford', 4:'Honda', 5:'Toyota'},
                   'Color': {0:'White', 1:'Black', 2:'Gray', 3:'White', 4:'White', 5:'Black'},
                   'Driver_age': {0:25, 1:37, 2:21, 3:54, 4:50, 5:67},
                   'Data': {0: np.array([[0, 0], [0.25, 1.7], [1.2, 1.8], [4.5, 4.0]]), 
                            1: np.array([[0, 0], [0.15, 1.3], [1.6, 1.3], [4.2, 4.1]]), 
                            2: np.array([[0, 0], [0.24, 1.2], [1.3, 1.6], [4.1, 3.9]]), 
                            3: np.array([[0, 0], [0.45, 1.6], [1.8, 1.8], [4.2, 4.6]]), 
                            4: np.array([[0, 0], [0.85, 1.9], [1.5, 1.7], [4.5, 4.3]]), 
                            5: np.array([[0, 0], [0.35, 1.8], [1.5, 1.8], [4.6, 4.1]])} }

recarr_dt = np.dtype( [ ('Form','S10'), ('Make','S10') , ('Color','S10'),
                        ('Driver_age',int), ('Data',float, (4,2)) ] )
nrows = 0
for k, d in data_dict.items():
    nrows = max(nrows, len(d))

recarr = np.zeros(shape=(nrows,), dtype=recarr_dt)  

for k1, v1 in data_dict.items():
    for k2, v2 in  v1.items():
        recarr[k2][k1] = v2
        
with tb.File('SO_71388372.h5','w') as h5w:
    h5w.create_table('/', 'test', obj=recarr)

打开并搜索 HDF5 文件
此示例演示了使用 Table.read_where(condition) 方法进行的 2 次搜索。它显示了多个搜索条件的语法。需要注意的一些事项:

  1. 多个条件需要括号
  2. 没有复合条件 (20 <= Driver_age <= 40) 是 2 个条件
  3. 字符串输入为b"text"(b/c HDF5 字符串不是 Unicode)。

以下代码

import tables as tb
with tb.File('SO_71388372.h5','r') as h5r:
    data_tbl = h5r.root.test
    
    condition = '(Form == b"SUV") & (20 <= Driver_age) & (Driver_age <= 40)'
    data_arr = data_tbl.read_where(condition)
    print(f'\nFor search condition: {condition}')
    print(f'# of rows found: {data_arr.shape}')
    for row in data_arr:
        print(row)
        
    condition = '(Form == b"SUV") & (Make == b"Honda")'
    data_arr = data_tbl.read_where(condition)
    print(f'\nFor search condition: {condition}')
    print(f'# of rows found: {data_arr.shape}')
    for row in data_arr:
        print(row)

这里是从各自的常见问题页面中提取的每个包的摘要。

PyTables(来自 PyTables 常见问题解答)
在 HDF5 和 NumPy 之上构建一个额外的抽象层。具有支持复杂查询的引擎、高效的计算内核和高级索引功能。有一个自定义系统来表示 HDF5 库中可用的数据类型,但 NumPy 中没有。

h5py(来自 h5py 常见问题)
尝试将 HDF5 功能集尽可能接近地映射到 NumPy。还提供对几乎所有 HDF5 C API 的访问。高级类型系统专门使用 NumPy dtype 对象,方法和属性命名遵循 Python 和 NumPy 的字典和数组访问约定。

【讨论】:

  • 这正是我想要的!!!
  • @batlike,上面最复杂的步骤是映射字典中的数据(因为第一个键是字段名,第二个键是行数据)。您如何导入数据并创建字典?如果您从 CSV 文件导入数据,可以使用np.genfromtxt() 进行简化。另外,我根据您的示例为'Data' 创建了一个 (4,2) 数组。这需要针对您希望保存的最大车辆轨迹数据集进行调整。 HDF5 模式的设计至关重要——比代码更重要。使用良好的模式进行编码很容易。 :-)
猜你喜欢
  • 2021-03-10
  • 1970-01-01
  • 1970-01-01
  • 2018-01-14
  • 2013-10-17
  • 2011-04-30
  • 2020-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多