如何将多个词典保存到hdf5并合并来自不同词典的公用密钥信息?

时间:2020-04-21 19:25:31

标签: python hdf5 h5py

简而言之,我很感兴趣是否有任何有效的方法可以将具有公共密钥的多个词典保存到hdf5文件中。

也许我有N个具有以下结构的字典(在下面的示例中,我将使用2个字典):

sample_1 = {'gene1_gene1': 1,
            'gene1_gene2': -0.385,
            'gene1_gene3': 0.25,
            'gene2_gene2': 1,
            'gene2_gene3': 0.004,
            'gene3_gene3': 1
           }
sample_2 = {'gene1_gene1': 1,
            'gene1_gene2': -0.0035,
            'gene1_gene4': 0.0421,
            'gene2_gene2': 1,
            'gene2_gene4': -0.0783,
            'gene4_gene4': 1
           }

每个词典包含M个键。有些键对于多个词典是通用的(如gene1_gene2),有些键是唯一的(如gene2_gene3gene2_gene4)。 我想将每个字典保存到一个具有如下结构的hdf5文件中:

{
    'gene1_gene2': {
         'sample_1': -0.385,
         'sample_2': -0.0035,
         ....
    }
    ....
}

因此,该文件必须同时包含每个键的值和相应的样本名称。

之后,我想使用目标geneX_geneY对从hdf5文件中提取样本名称和值。

为此,我编写以下代码:

with h5py.File("out_file.hdf5", 'a') as f:
    for gene_pair, cor_val in sample_N.items():
        try:
            grp = f.create_group(gene_pair)
            grp.create_dataset('data', (0,), maxshape=(None,), dtype=h5py.string_dtype(encoding='ascii'),
                               compression="gzip", compression_opts=9)
            grp.create_dataset('cor', (0,), maxshape=(None,), dtype='f4', compression="gzip", compression_opts=9)
            data = f[gene_pair]['data']
            cor = f[gene_pair]['cor']
            cor.resize(cor.shape[0] + 1, axis=0)
            cor[-1] = cor_val
            data.resize(data.shape[0] + 1, axis=0)
            data[-1] = 'sample_N'
        except:
            data = f[gene_pair]['data']
            cor = f[gene_pair]['cor']
            cor.resize(cor.shape[0] + 1, axis=0)
            cor[-1] = cor_val
            data.resize(data.shape[0] + 1, axis=0)
            data[-1] = 'sample_N'

简而言之,代码创建了与geneX_geneY键对应的组,并将值(f[gene_pair]['cor'])和数据集名称(f[gene_pair]['data'])保存到具有numpy数组的相应数据集。

我很感兴趣,有什么有效的方法吗?

1 个答案:

答案 0 :(得分:0)

如评论中所述,HDF5 / h5py使用NumPy数组结构,不支持字典。坦率地说,我认为数组在管理此类数据方面远胜于字典。 (就我个人而言,我不会将gene_pair数据存储在词典中……加载和卸载时会很混乱……但这就是我。)

无需为gene_paircor创建具有单独数据集的data组。实际上,您的方法使架构变得复杂,需要访问2个不同的数据集才能获得cordata。您可以在每个gene_pair的单个数据集/表中完成所有操作(相当于NumPy记录数组)。有很多方法可以做到这一点。如果可以在此过程的上游更改gene_pair数据结构,则强烈建议使用NumPy记录数组。它具有到HDF5 / h5py数据集的自然映射,创建它们是一个一步的过程。如果您不能(或不想这样做),我有3条建议。

注意:用于创建sample_N词典的代码对于所有方法都是相同的,并在最后提供。

此外,我按照您的示例创建了每个数据集/表,将其作为可扩展的数据集,最初包含零行,一次添加了一行。小型数据样本可以这样做,但是如果您有数百万行,重新分配大型数据集将变得很慢。如果您打算添加大量数据,则建议使用其他方法。分配一个初始的大行块(10e4?),然后跟踪当前行,并根据需要扩展其他大块。这种方法只是“稍微”更复杂。 :-)

方法1: 这是符合您要求的表格格式。它为每个gene_pair名称创建一个数据集(表)。数据集名称是gene_pair的名称,它具有3个字段:Sample_ID(文本),ID(提取的整数)和与此样本相关联的测试值。

with h5py.File("SO_61351577_1.h5", 'w') as h5f:
  for sample_N in sample_dict:
    for gene_pair, cor_val in sample_dict.get(sample_N).items():
        gene_dt = np.dtype ([ ('Sample', 'S20'), ('ID', int), ('Value', float) ]) 
        if gene_pair not in h5f.keys() :
            gene_pair_ds = h5f.create_dataset(gene_pair, (1,), maxshape=(None,), dtype=gene_dt,
                           compression="gzip", compression_opts=9)
        else:
            gene_pair_ds = h5f[gene_pair]
            gene_pair_ds.resize(gene_pair_ds.shape[0] + 1, axis=0)
        gene_pair_ds[-1,'Sample'] = sample_N
        gene_pair_ds[-1,'ID'] = int(sample_N[7:] )
        gene_pair_ds[-1,'Value']  = cor_val

方法2: 这使用不同的表格格式。每个样品都有一行数据,并且在匹配的列/字段下有测试值。这只是您的建议。如果对的数量很大(例如> 100),则没有意义。另外,该表的未输入值是0.0,所以可能会出现问题。
该过程如何进行:首先,我从sample_N字典中获得gene_pair名称,并建立一个唯一名称列表。我使用此列表创建一个NumPy dtype来保存所有数据。然后,我循环访问sample_N字典,并将该样本的所有gene_pair值写入同一行。映射到字段/列是通过gene_pair名称完成的。

#Create a list of unique dictionary keys:
gene_list = []
for sample_N in sample_dict:
    for gene_pair in sample_dict.get(sample_N):
        if gene_pair not in gene_list:
            gene_list.append(gene_pair)
gene_list.sort()
# Create dictionary of names and formats to use for dtype
# Then use as NumPy dtype to create the dataset
dt_genetable = {'names':['Sample','ID'], 'formats':['S20', int] }
for gene_name in gene_list:
     dt_genetable['names'].append(gene_name)
     dt_genetable['formats'].append(float)

with h5py.File("SO_61351577_2.h5", 'w') as h5f:
    genetable_ds = h5f.create_dataset('GeneTable', (0,), maxshape=(None,), 
                        dtype=dt_genetable, compression="gzip", compression_opts=9)

    for sample_N in sample_dict:
        genetable_ds.resize(genetable_ds.shape[0] + 1, axis=0)
        genetable_ds[-1,'Sample'] = sample_N
        genetable_ds[-1,'ID'] = int(sample_N[7:] )
        for gene_pair, cor_val in sample_dict.get(sample_N).items():
            print (sample_N, ':', gene_pair, ':', cor_val)
            genetable_ds[-1,gene_pair]  = cor_val

方法3: 我创建此示例是因为此数据集/表格式最接近于您的原始词典格式。它与方法2相似,但dtype和表稍有不同。与方法2一样,每个样本都有一行数据,另外还有12个用于gene_pair名称和cor_val值的字段。 (我假设您总是有6对。)

# Create dictionary of names and formats to use for dtype
# Then use as NumPy dtype to create dataset
sample_table_dt = {'names':['Sample','ID'], 'formats':['S20', int] }
for cnt in range(1,7,1):
     sample_table_dt['names'].append('gene_name_'+str(cnt))
     sample_table_dt['formats'].append('S20')
     sample_table_dt['names'].append('cor_val_'+str(cnt))
     sample_table_dt['formats'].append(float)

with h5py.File("SO_61351577_3.h5", 'w') as h5f:
    sample_table_ds = h5f.create_dataset('SampleTable', (0,), maxshape=(None,), 
                        dtype=sample_table_dt, compression="gzip", compression_opts=9)

    for sample_N in sample_dict:
        sample_table_ds.resize(sample_table_ds.shape[0] + 1, axis=0)
        sample_table_ds[-1,'Sample'] = sample_N
        sample_table_ds[-1,'ID'] = int(sample_N[7:] )
        gcnt = 1
        for gene_pair, cor_val in sample_dict.get(sample_N).items():
            sample_table_ds[-1,'gene_name_'+str(gcnt)]  = gene_pair
            sample_table_ds[-1,'cor_val_'+str(gcnt)]  = cor_val
            gcnt += 1

用于创建sample_N词典的代码:

sample_1 = {'gene1_gene1': 1,
            'gene1_gene2': -0.385,
            'gene1_gene3': 0.25,
            'gene2_gene2': 1,
            'gene2_gene3': 0.004,
            'gene3_gene3': 1
           }
sample_2 = {'gene1_gene1': 1,
            'gene1_gene2': -0.0035,
            'gene1_gene4': 0.0421,
            'gene2_gene2': 1,
            'gene2_gene4': -0.0783,
            'gene4_gene4': 1
           }
sample_3 = {'gene1_gene1': 1,
            'gene1_gene2': -0.065,
            'gene1_gene4': 0.0567,
            'gene2_gene2': 1,
            'gene2_gene3': -0.0378,
            'gene4_gene4': 1
           }

sample_dict = dict( sample_1=sample_1,
                    sample_2=sample_2,
                    sample_3=sample_3 )