我有一个 JSON 字符串,其中包含将索引映射到 float
值的字典。这是向量的代表。例如,
{
'distro': {0: 2.42, 3: 2.56},
'constant': 4.55
'size': 10000
}
表示大小为 10000
的向量,索引 0
上具有 2.42
,索引 2 上具有
。该向量中的所有其他值均为 2.56
4.55
。
表示此数据结构的最有效方式是什么?会scipy.sparse
帮我?我的主要应用是快速创建密集表示,但我不想预先将它们存储在内存中(因为有很多这样的向量)。
最佳答案
我想你的迭代方式是这样的:
In [204]: dd = {
...: 'distro': {0: 2.42, 3: 2.56},
...: 'constant': 4.55,
...: 'size': 10,
...: }
In [205]: dd
Out[205]: {'constant': 4.55, 'distro': {0: 2.42, 3: 2.56}, 'size': 10}
In [207]: x = np.zeros(dd['size'])
In [208]: x[:] = dd['constant']
In [210]: for i,v in dd['distro'].items():
...: x[i] = v
In [211]: x
Out[211]: array([ 2.42, 4.55, 4.55, 2.56, 4.55, 4.55, 4.55, 4.55, 4.55, 4.55])
x[:]
的替代方案,是x.fill(dd['constant'])
,但不认为速度有太大差异。
这是一种无需显式迭代即可从字典中设置值的方法:
In [221]: ddvals = np.array(list(dd['distro'].items()),dtype='i,f')
In [222]: ddvals
Out[222]:
array([(0, 2.42000008), (3, 2.55999994)],
dtype=[('f0', '<i4'), ('f1', '<f4')])
In [223]: x[ddvals['f0']]=ddvals['f1']
In [224]: x
Out[224]:
array([ 2.42000008, 4.55 , 4.55 , 2.55999994, 4.55 ,
4.55 , 4.55 , 4.55 , 4.55 , 4.55 ])
或者没有结构化数组:
In [225]: vals = np.array(list(dd['distro'].items()))
In [226]: vals
Out[226]:
array([[ 0. , 2.42],
[ 3. , 2.56]])
In [227]: x[vals[:,0]] = vals[:,1]
...
IndexError: arrays used as indices must be of integer (or boolean) type
In [228]: x[vals[:,0].astype(int)] = vals[:,1]
In [229]: x
Out[229]: array([ 2.42, 4.55, 4.55, 2.56, 4.55, 4.55, 4.55, 4.55, 4.55, 4.55])
字典items()
(或 PY3 中的 list(items())
)给出元组列表。较新 numpy
版本不喜欢使用 float 作为索引,因此我们必须添加一些步骤来保留整数键值。
这可能是最简单的:
x[list(dd['distro'].keys())] = list(dd['distro'].values())
(我假设 keys
、 values
和 items
以相同的键顺序返回值)。
对于这个小案例,我怀疑简单的迭代方法更快。但后一种更大的东西可能会更好。我无法预测交叉发生在哪里。
scipy.sparse
制作二维矩阵。它没有实现任何类型的 const
充满。 ( Pandas 稀疏确实有这样的填充)。我们当然可以构造一个sparse
矩阵来自dd['size']
和dd['distro']
。但我不知道它是否会提供任何速度优势。
如果 Tensorflow 是你真正的目标,那么你可能需要更多地了解它的构建方法。也许你不需要经过numpy
或sparse
完全没有。
这个x
,没有 const
可以表示为scipy
稀疏矩阵:
In [247]: Xo = sparse.coo_matrix([x])
In [248]: Xo
Out[248]:
<1x10 sparse matrix of type '<class 'numpy.float64'>'
with 2 stored elements in COOrdinate format>
其主要属性是:
In [249]: Xo.data
Out[249]: array([ 2.42, 2.56])
In [250]: Xo.row
Out[250]: array([0, 0], dtype=int32)
In [251]: Xo.col
Out[251]: array([0, 3], dtype=int32)
In [252]: Xo.shape
Out[252]: (1, 10)
Xr=Xo.tocsr()
csr
格式类似,除了 row
属性被替换为 indptr
数组,每行有一个值 (+1),因此它不会随着非零项的数量而增长。它用于大多数稀疏数学。
还有一个dok
format,它实际上是一个字典子类:
In [258]: dict(Xo.todok())
Out[258]: {(0, 0): 2.4199999999999999, (0, 3): 2.5600000000000001}
<小时/>
如果输入有效json
,您需要将索引键转换为整数。
In [281]: jstr
Out[281]: '{"distro": {"0": 2.42, "3": 2.56}, "constant": 4.55, "size": 10}'
In [282]: jdd = json.loads(jstr)
In [283]: jdd
Out[283]: {'constant': 4.55, 'distro': {'0': 2.42, '3': 2.56}, 'size': 10}
In [284]: list(jdd['distro'].keys())
Out[284]: ['0', '3']
In [285]: np.array(list(jdd['distro'].keys()),int)
Out[285]: array([0, 3])
In [286]: np.array(list(jdd['distro'].values()))
Out[286]: array([ 2.42, 2.56])
我对 SO 搜索的印象是 json.load
与 eval
一样快,甚至更快。它必须解析更简单的语法。
python eval vs ast.literal_eval vs JSON decode
如果您可以处理json
字符串,并将它们存储在某种中间数据结构中,有几种可能性。这些向量有多“稀疏”?如果字典具有几乎所有 1000 个“大小”条目的值,则最好构建完整的 numpy 数组并保存它(例如使用 np.save/load
对)。
如果它是稀疏的(比如 10% 的值是非常量),则保存 2 个索引和值数组可能更有意义(285 和 284)。要么将它们分开,要么将它们加入到我之前生成的结构化数组中。
关于python - 存储该向量的最有效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42983554/