【问题标题】:Saving numpy array in mongodb在mongodb中保存numpy数组
【发布时间】:2011-09-16 02:11:52
【问题描述】:

我有几个 MongoDB 文档,其中一个字段最好表示为矩阵(numpy 数组)。我想将此文档保存到 MongoDB,我该怎么做?

{
'name' : 'subject1',
'image_name' : 'blah/foo.png',
'feature1' : np.array(...)
}

【问题讨论】:

  • 您是否尝试过序列化(例如,pickle)?
  • 虽然不是数据库替代品,但您也可以考虑使用 pytables(基于 hdf5 构建)来存储您的 numpy 数组...pytables.org/moin

标签: python mongodb numpy nosql


【解决方案1】:

我知道这是一个老问题,但这是一个优雅的解决方案,适用于新版本的 pymongo:

import pickle
from bson.binary import Binary, USER_DEFINED_SUBTYPE
from bson.codec_options import TypeCodec, TypeRegistry, CodecOptions
import numpy as np

class NumpyCodec(TypeCodec):
    python_type = np.ndarray
    bson_type = Binary

    def transform_python(self, value):
        return Binary(pickle.loads(value), USER_DEFINED_SUBTYPE)

    def transform_bson(self, value):
        if value.subtype == USER_DEFINED_SUBTYPE:
            return pickle.dumps(value, protocol=2)
        return value

def get_codec_options():
    numpy_codec = NumpyCodec()
    type_registry = TypeRegistry([numpy_codec])
    codec_options = CodecOptions(type_registry=type_registry)
    return codec_options

def get_collection(name, db):
    codec_options = get_codec_options()
    return db.get_collection(name, codec_options=codec_options)

那么你可以通过这种方式收集:

from pymongo import MongoClient
client = MongoClient()
db = client['my_db']
my_collection = get_collection('my_collection', db)

之后,您只需在数据库中透明地插入和查找 Numpy 数组。

【讨论】:

    【解决方案2】:

    你试过MongoWrapper吗,我觉得很简单:

    声明与 mongodb 服务器和集合的连接以保存您的 np。

    import monogowrapper as mdb
    db = mdb.MongoWrapper(dbName='test',
                          collectionName='test_collection', 
                          hostname="localhost", 
                          port="27017") 
    my_dict = {"name": "Important experiment", 
                "data":np.random.random((100,100))}
    

    字典和你期望的一样:

    print my_dict
    {'data': array([[ 0.773217,  0.517796,  0.209353, ...,  0.042116,  0.845194,
             0.733732],
           [ 0.281073,  0.182046,  0.453265, ...,  0.873993,  0.361292,
             0.551493],
           [ 0.678787,  0.650591,  0.370826, ...,  0.494303,  0.39029 ,
             0.521739],
           ..., 
           [ 0.854548,  0.075026,  0.498936, ...,  0.043457,  0.282203,
             0.359131],
           [ 0.099201,  0.211464,  0.739155, ...,  0.796278,  0.645168,
             0.975352],
           [ 0.94907 ,  0.363454,  0.912208, ...,  0.480943,  0.810243,
             0.217947]]),
     'name': 'Important experiment'}
    

    将数据保存到mongo:

    db.save(my_dict)
    

    加载数据:

    my_loaded_dict = db.load({"name":"Important experiment"})
    

    【讨论】:

      【解决方案3】:

      我们已经构建了一个开源库,用于在 MongoDB 中存储数字数据(Pandas、numpy 等):

      https://github.com/manahl/arctic

      最重要的是,它非常易于使用、速度非常快,并且支持数据版本控制、多个数据库等等。

      【讨论】:

      • 这似乎是一种存储您的 pandas 数据框然后对其运行查询的方法(尤其是使用日期/时间列)。
      【解决方案4】:

      代码 pymongo.binary.Binary(...) 对我不起作用,可能是我们需要使用 bson 作为 @tcaswell 建议。

      无论如何这里是多维numpy数组的一种解决方案

      >>from bson.binary import Binary
      >>import pickle
      # convert numpy array to Binary, store record in mongodb
      >>record['feature2'] = Binary(pickle.dumps(npArray, protocol=2), subtype=128 )
      # get record from mongodb, convert Binary to numpy array
      >> npArray = pickle.loads(record['feature2'])
      

      话虽如此,功劳归于MongoWrapper 使用了他们编写的代码。

      【讨论】:

        【解决方案5】:

        你试过Monary吗?

        他们在网站上有示例

        http://djcinnovations.com/index.php/archives/103

        【讨论】:

          【解决方案6】:

          对于一维 numpy 数组,您可以使用列表:

          # serialize 1D array x
          record['feature1'] = x.tolist()
          
          # deserialize 1D array x
          x = np.fromiter( record['feature1'] )
          

          对于多维数据,我相信你需要使用pickle和pymongo.binary.Binary:

          # serialize 2D array y
          record['feature2'] = pymongo.binary.Binary( pickle.dumps( y, protocol=2) ) )
          
          # deserialize 2D array y
          y = pickle.loads( record['feature2'] )
          

          【讨论】:

          • 这可以通过使用pickle.dumps(y, protocol=2) 来改进,从而使数据的二进制表示更加紧凑和快速。
          • 另外,你可以试试 cpickle,它比 pickle 快 1000 倍,因为它是在 c:docs.python.org/library/pickle.html#module-cPickle 中实现的
          • 在较新(至少 2.4)版本的 pymongo 中,binary.Binary 已移至 bson
          • 我不断收到错误消息:TypeError: Required argument 'dtype' (pos 2) not found
          • @AlexGaudio 关于使用 cPickle 的评论仅与 Python 2 相关。如今(Python 3),accelerated libraries are used by default
          猜你喜欢
          • 2015-11-17
          • 2021-07-12
          • 2017-01-13
          • 1970-01-01
          • 2018-07-09
          • 2019-02-25
          • 2020-10-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多