如何将数据从mongodb导入到熊猫?

Nit*_*hin 84 python mongodb pymongo pandas

我在mongodb的集合中有大量数据需要分析.如何将数据导入熊猫?

我是熊猫和numpy的新手.

编辑:mongodb集合包含标记有日期和时间的传感器值.传感器值为float数据类型.

样本数据:

{
"_cls" : "SensorReport",
"_id" : ObjectId("515a963b78f6a035d9fa531b"),
"_types" : [
    "SensorReport"
],
"Readings" : [
    {
        "a" : 0.958069536790466,
        "_types" : [
            "Reading"
        ],
        "ReadingUpdatedDate" : ISODate("2013-04-02T08:26:35.297Z"),
        "b" : 6.296118156595,
        "_cls" : "Reading"
    },
    {
        "a" : 0.95574014778624,
        "_types" : [
            "Reading"
        ],
        "ReadingUpdatedDate" : ISODate("2013-04-02T08:27:09.963Z"),
        "b" : 6.29651468650064,
        "_cls" : "Reading"
    },
    {
        "a" : 0.953648289182713,
        "_types" : [
            "Reading"
        ],
        "ReadingUpdatedDate" : ISODate("2013-04-02T08:27:37.545Z"),
        "b" : 7.29679823731148,
        "_cls" : "Reading"
    },
    {
        "a" : 0.955931884300997,
        "_types" : [
            "Reading"
        ],
        "ReadingUpdatedDate" : ISODate("2013-04-02T08:28:21.369Z"),
        "b" : 6.29642922525632,
        "_cls" : "Reading"
    },
    {
        "a" : 0.95821381,
        "_types" : [
            "Reading"
        ],
        "ReadingUpdatedDate" : ISODate("2013-04-02T08:41:20.801Z"),
        "b" : 7.28956613,
        "_cls" : "Reading"
    },
    {
        "a" : 4.95821335,
        "_types" : [
            "Reading"
        ],
        "ReadingUpdatedDate" : ISODate("2013-04-02T08:41:36.931Z"),
        "b" : 6.28956574,
        "_cls" : "Reading"
    },
    {
        "a" : 9.95821341,
        "_types" : [
            "Reading"
        ],
        "ReadingUpdatedDate" : ISODate("2013-04-02T08:42:09.971Z"),
        "b" : 0.28956488,
        "_cls" : "Reading"
    },
    {
        "a" : 1.95667927,
        "_types" : [
            "Reading"
        ],
        "ReadingUpdatedDate" : ISODate("2013-04-02T08:43:55.463Z"),
        "b" : 0.29115237,
        "_cls" : "Reading"
    }
],
"latestReportTime" : ISODate("2013-04-02T08:43:55.463Z"),
"sensorName" : "56847890-0",
"reportCount" : 8
}
Run Code Online (Sandbox Code Playgroud)

wai*_*kuo 114

pymongo 可能会帮助你,以下是我正在使用的一些代码:

import pandas as pd
from pymongo import MongoClient


def _connect_mongo(host, port, username, password, db):
    """ A util for making a connection to mongo """

    if username and password:
        mongo_uri = 'mongodb://%s:%s@%s:%s/%s' % (username, password, host, port, db)
        conn = MongoClient(mongo_uri)
    else:
        conn = MongoClient(host, port)


    return conn[db]


def read_mongo(db, collection, query={}, host='localhost', port=27017, username=None, password=None, no_id=True):
    """ Read from Mongo and Store into DataFrame """

    # Connect to MongoDB
    db = _connect_mongo(host=host, port=port, username=username, password=password, db=db)

    # Make a query to the specific DB and Collection
    cursor = db[collection].find(query)

    # Expand the cursor and construct the DataFrame
    df =  pd.DataFrame(list(cursor))

    # Delete the _id
    if no_id:
        del df['_id']

    return df
Run Code Online (Sandbox Code Playgroud)

  • 请注意,在df = pd.DataFrame(list(cursor))中的list()评估为列表或生成器,以使CPU保持凉爽。如果您有不计其数的数据项,并且接下来的几行将进行合理的划分,详细程度的调整和剪切,则整个shmegegge仍然可以放心使用。很好。 (2认同)
  • @`df = pd.DataFrame(list(cursor))`非常慢。纯粹的数据库查询要快得多。我们可以将`list`强制类型更改为其他内容吗? (2认同)
  • @Peter 那条线也引起了我的注意。将设计为可迭代并可能包含大量数据的数据库游标转换为内存列表对我来说似乎并不聪明。 (2认同)

sai*_*uri 34

您可以使用此代码将mongodb数据加载到pandas DataFrame.这个对我有用.希望也适合你.

import pymongo
import pandas as pd
from pymongo import MongoClient
client = MongoClient()
db = client.database_name
collection = db.collection_name
data = pd.DataFrame(list(collection.find()))
Run Code Online (Sandbox Code Playgroud)


shx*_*hx2 22

Monary就是这样,而且速度非常快.(另一个链接)

看到这个很酷的帖子,其中包括快速教程和一些时间.


Ika*_*ský 13

我发现另一个非常有用的选项是:

from pandas.io.json import json_normalize

cursor = my_collection.find()
df = json_normalize(cursor)
Run Code Online (Sandbox Code Playgroud)

(或者json_normalize(list(cursor)),取决于您的 python/pandas 版本)。

通过这种方式,您可以免费展开嵌套的 mongodb 文档。

  • 我在使用此方法时遇到错误 `TypeError: data argument can't be an iterator` (2认同)
  • 奇怪,这适用于我的 python 3.6.7 使用 Pandas 0.24.2 。也许你可以试试`df = json_normalize(list(cursor))`? (2认同)

Cy *_* Bu 12

根据PEP,简单比复杂更好:

import pandas as pd
df = pd.DataFrame.from_records(db.<database_name>.<collection_name>.find())
Run Code Online (Sandbox Code Playgroud)

您可以像使用常规mongoDB数据库一样包含条件,甚至可以使用find_one()从数据库中获取一个元素,等等.

瞧!

  • 这对于大量记录来说并不好,因为这不会显示内存错误,反而会因数据太大而挂起系统。而 pd.DataFrame(list(cursor)) 显示内存错误。 (2认同)

小智 10

import pandas as pd
from odo import odo

data = odo('mongodb://localhost/db::collection', pd.DataFrame)
Run Code Online (Sandbox Code Playgroud)


Den*_*zov 6

为了有效地处理核外(不适合RAM)数据(即并行执行),您可以尝试使用Python Blaze生态系统:Blaze/Dask/Odo.

Blaze(和Odo)具有处理MongoDB的开箱即用功能.

一些有用的文章开始:

还有一篇文章展示了Blaze堆栈可能带来的惊人之处:使用Blaze和Impala分析17亿Reddit评论(基本上,在几秒钟内查询975 Gb的Reddit评论).

PS我不隶属于任何这些技术.


小智 6

您还可以使用pymongoarrow —— 它是 MongoDB 提供的官方库,用于将 mongodb 数据导出到 pandas、numPy、parquet 文件等。


Deo*_*ung 5

使用

pandas.DataFrame(list(...))
Run Code Online (Sandbox Code Playgroud)

如果迭代器/生成器结果很大,将消耗大量内存

最好生成小块并在最后连接

def iterator2dataframes(iterator, chunk_size: int):
  """Turn an iterator into multiple small pandas.DataFrame

  This is a balance between memory and efficiency
  """
  records = []
  frames = []
  for i, record in enumerate(iterator):
    records.append(record)
    if i % chunk_size == chunk_size - 1:
      frames.append(pd.DataFrame(records))
      records = []
  if records:
    frames.append(pd.DataFrame(records))
  return pd.concat(frames)
Run Code Online (Sandbox Code Playgroud)