У меня есть большой объем данных в коллекции в mongodb, которые мне нужно проанализировать. Как мне импортировать эти данные в панды?
Я новичок в pandas и 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
}
mongo_doc.data_frame = my_pandas_df
Ответы:
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
источник
list()
внутренняя частьdf = pd.DataFrame(list(cursor))
оценивается как список или генератор для охлаждения процессора. Если у вас есть миллион элементов данных, и следующие несколько строк будут разумно разделены, детализированы и обрезаны, весь shmegegge все еще можно безопасно использовать. Приятно.df = pd.DataFrame(list(cursor))
. Запросы чистого БД выполняются намного быстрее. Можем ли мы изменитьlist
кастинг на что-нибудь другое?Вы можете загрузить свои данные 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()))
источник
Monary
делает именно это, и это очень быстро . ( другая ссылка )Посмотрите этот классный пост, который включает в себя краткое руководство и некоторые тайминги.
источник
client = Monary(host, 27017, database="db_tmp") columns = ["col1", "col2"] data_type = ["int64", "int64"] arrays = client.query("db_tmp", "coll", {}, columns, data_type)
для50000
записей занимает около200s
.Согласно PEP, простое лучше, чем сложное:
import pandas as pd df = pd.DataFrame.from_records(db.<database_name>.<collection_name>.find())
Вы можете включить условия, как если бы вы работали с обычной базой данных mongoDB, или даже использовать find_one () для получения только одного элемента из базы данных и т. Д.
и вуаля!
источник
import pandas as pd from odo import odo data = odo('mongodb://localhost/db::collection', pd.DataFrame)
источник
Для эффективной работы с данными вне ядра (не вмещающимися в ОЗУ) (то есть с параллельным выполнением) вы можете попробовать экосистему Python Blaze : Blaze / Dask / Odo.
Blaze (и Odo ) имеет готовые функции для работы с MongoDB.
Несколько полезных статей для начала:
И статья, которая показывает, какие удивительные вещи возможны со стеком Blaze: Анализ 1,7 миллиарда комментариев Reddit с помощью Blaze и Impala (по сути, запрос 975 ГБ комментариев Reddit за секунды).
PS Я не связан ни с одной из этих технологий.
источник
Еще один вариант, который я нашел очень полезным:
from pandas.io.json import json_normalize cursor = my_collection.find() df = json_normalize(cursor)
таким образом вы получаете разворачивание вложенных документов mongodb бесплатно.
источник
TypeError: data argument can't be an iterator
3.6.7
с использованием панд0.24.2
. Может, лучше попробоватьdf = json_normalize(list(cursor))
?С помощью
pandas.DataFrame(list(...))
будет потреблять много памяти, если результат итератора / генератора большой
лучше генерировать небольшие куски и конкатенировать в конце
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)
источник
http://docs.mongodb.org/manual/reference/mongoexport
экспортировать в CSV и использовать
read_csv
или JSON и использоватьDataFrame.from_records()
источник
DataFrame.from_records()
.После этого отличного ответа от waitkuo я хотел бы добавить возможность сделать это с помощью chunksize в соответствии с .read_sql () и .read_csv () . Я увеличиваю ответ Деу Люнга , избегая перехода по одной каждой «записи» «итератора» / «курсора». Я позаимствую предыдущую функцию read_mongo .
def read_mongo(db, collection, query={}, host='localhost', port=27017, username=None, password=None, chunksize = 100, 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) client = MongoClient(host=host, port=port) # Make a query to the specific DB and Collection db_aux = client[db] # Some variables to create the chunks skips_variable = range(0, db_aux[collection].find(query).count(), int(chunksize)) if len(skips_variable)<=1: skips_variable = [0,len(skips_variable)] # Iteration to create the dataframe in chunks. for i in range(1,len(skips_variable)): # Expand the cursor and construct the DataFrame #df_aux =pd.DataFrame(list(cursor_aux[skips_variable[i-1]:skips_variable[i]])) df_aux =pd.DataFrame(list(db_aux[collection].find(query)[skips_variable[i-1]:skips_variable[i]])) if no_id: del df_aux['_id'] # Concatenate the chunks into a unique df if 'df' not in locals(): df = df_aux else: df = pd.concat([df, df_aux], ignore_index=True) return df
источник
Похожий подход, как у Рафаэля Валеро, waitkuo и Deu Leung с использованием разбивки на страницы :
def read_mongo( # db, collection, query=None, # host='localhost', port=27017, username=None, password=None, chunksize = 100, page_num=1, no_id=True): # Connect to MongoDB db = _connect_mongo(host=host, port=port, username=username, password=password, db=db) # Calculate number of documents to skip skips = chunksize * (page_num - 1) # Sorry, this is in spanish # https://www.toptal.com/python/c%C3%B3digo-buggy-python-los-10-errores-m%C3%A1s-comunes-que-cometen-los-desarrolladores-python/es if not query: query = {} # Make a query to the specific DB and Collection cursor = db[collection].find(query).skip(skips).limit(chunksize) # Expand the cursor and construct the DataFrame df = pd.DataFrame(list(cursor)) # Delete the _id if no_id: del df['_id'] return df
источник
Вы можете добиться желаемого с помощью pdmongo в трех строках:
import pdmongo as pdm import pandas as pd df = pdm.read_mongo("MyCollection", [], "mongodb://localhost:27017/mydb")
Если ваши данные очень большие, вы можете сначала выполнить агрегированный запрос, отфильтровав данные, которые вам не нужны, а затем сопоставить их с нужными столбцами.
Вот пример сопоставления
Readings.a
с столбцомa
и фильтрации поreportCount
столбцу:import pdmongo as pdm import pandas as pd df = pdm.read_mongo("MyCollection", [{'$match': {'reportCount': {'$gt': 6}}}, {'$unwind': '$Readings'}, {'$project': {'a': '$Readings.a'}}], "mongodb://localhost:27017/mydb")
read_mongo
принимает те же аргументы, что и агрегат pymongoисточник