在python中两个对象之间存储和使用信息的最佳方法是什么?

时间:2016-05-16 12:53:38

标签: python database numpy pandas hdf

我有一组对象的名称/ id(就生活中的对象而言,而不是python对象)。

为简单起见,这些对象具有以下名称:

A, B, C, D, E ...

此类物体的数量约为2000(以及将来可能约为6000)。

我正在尝试确定完成任务的最佳方法:在每对对象之间存储信息(param1,param2,...,paramN)的最佳方式是什么。看起来像以下数据结构:

                A               B              C              D 
A             -          [param1, param2] [param1, param2] [param1, param2]

B      [param1, param2]        -          [param1, param2] [param1, param2]

C      [param1, param2]  [param1, param2]       -          [param1, param2]

D      [param1, param2]  [param1, param2] [param1, param2]        -

考虑以下几个方面非常重要:

  • cell [A,B] = cell [B,A]所以我们只需要存储所有表的1/2
  • 我需要在tmp目录中保存此表并在我的python应用程序启动时加载
  • 我需要在我的python应用程序中快速从此表中提取值

我的解决方案: 我使用了pandas.DataFrame模块。 对于每个参数: param1,param2,... 我制作单独的三角形表: param1table,param2table,... 填写后我将它们保存在CSV文件中:< em> param1table.csv,param2table.csv,.... csv

在我的程序中,如果我需要成对param1:A,B,我需要加载 param1table.csv (pandas.read_csv)并查看值[A,B]是否存在返回它,否则返回[B,A]

我认为这不是有效的方法。

2 个答案:

答案 0 :(得分:2)

根据我的ML和数据科学经验,有两种常见的方法可以在python脚本之间共享数据:CSV和HDF5。如果csv对你来说很好,请尽可能长时间使用它,因为HDF5不能很好地处理非整数值。

如果您的磁盘容量存在问题,只需压缩数据即可 Pandas'read_csv()非常了解最流行的压缩算法。

如果加载速度问题 - 将其分块,然后对其进行分类。

此外,如果您的数据是“镜像”的,为什么不简单地命名您的列,然后以正确的方式调用它? E.G。:call(cell [B,A]) - &gt;呼叫(小区[A,B]) - &gt;细胞[B,A]。

添加:对于某些极端情况,您可以单独保存每一行(不要忘记剪切它的空白部分),然后为最常用的调用创建某种缓存缓冲区。

答案 1 :(得分:1)

如果您想坚持pd.DataFrame,可以使用MultiIindex see docsObject_1Object_2作为indexParam_1Param_2columns。这是首选,因为DataFrame并非设计用于存储list个对象。

您可以使用np.triu提取当前DataFrame的上三角形(返回归零的下三角形),使用.replace(0, np.nan).stack()转换为长整数形成。从那里只需要使用reset_index() .split()list df.col.str.split(','), expand=True个对象。

您可以轻松确保仅存储Object_1Object_2但不存储Object_2Object_1,并使用df.loc[('Object_1', 'Object_2'), :]访问您的参数。

您可以将结果存储在.csvhdf中,这对于n * (n-1) / 2行来说会更快(see docs)。

举例说明:

import pandas as pd
import numpy as np
import string
from itertools import permutations

从简单的DataFrame开始,看起来类似于您当前使用的那个:

objs = [o for o in permutations(list(string.ascii_uppercase[:5]), 2)]
obj_1, obj_2 = zip(*objs)
params = [list(np.random.randint(low=0, high=10, size=2)) for j in range(len(objs))]
df = pd.DataFrame(data={'obj_1': obj_1, 'obj_2': obj_2, 'params': params})
df = df.set_index(['obj_1', 'obj_2']).unstack()

obj_2       A       B       C       D       E
obj_1                                        
A        None  [4, 7]  [7, 5]  [0, 5]  [3, 0]
B      [4, 6]    None  [0, 8]  [0, 7]  [7, 2]
C      [6, 9]  [6, 2]    None  [7, 8]  [3, 1]
D      [0, 0]  [2, 4]  [9, 8]    None  [1, 8]
E      [2, 3]  [8, 6]  [5, 7]  [5, 8]    None

假设params是对称的,让我们摆脱下三角:

mask = np.ones(df.shape,dtype='bool')
mask[np.tril_indices(len(df))] = False
df = df.where(mask)

obj_2      A       B       C       D       E
obj_1                                       
A        NaN  [4, 7]  [7, 5]  [0, 5]  [3, 0]
B        NaN     NaN  [0, 8]  [0, 7]  [7, 2]
C        NaN     NaN     NaN  [7, 8]  [3, 1]
D        NaN     NaN     NaN     NaN  [1, 8]
E        NaN     NaN     NaN     NaN     NaN

接下来转换为长格式并从params中提取list

df = df.stack()
df['param_1'], df['param_2'] = (zip(*df.params))

             params  param_1  param_2
obj_1 obj_2                          
A     B      [4, 7]        4        7
      C      [7, 5]        7        5
      D      [0, 5]        0        5
      E      [3, 0]        3        0
B     C      [0, 8]        0        8
      D      [0, 7]        0        7
      E      [7, 2]        7        2
C     D      [7, 8]        7        8
      E      [3, 1]        3        1
D     E      [1, 8]        1        8

所以我们不再需要params

df.drop('params', axis=1, inplace=True)

现在可以这样访问:

df.loc[('B', 'C')]

param_1    0
param_2    8

或单独:

df.loc[('B', 'C'), 'param_1']

0