python - ¿Cómo importar datos de mongodb a los pandas?
pymongo (11)
Tengo una gran cantidad de datos en una colección en mongodb que necesito analizar. ¿Cómo importo esa información a los pandas?
Soy nuevo para pandas y numpy.
EDITAR: La colección de mongodb contiene valores de sensor etiquetados con fecha y hora. Los valores del sensor son de tipo de datos flotantes.
Data de muestra:
{
"_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
}
Después de esta gran respuesta de waitingkuo me gustaría agregar la posibilidad de hacerlo utilizando chunksize en línea con .read_sql() y .read_csv() . Amplié la respuesta de Deu Leung evitando ir uno a uno cada ''registro'' del ''iterador'' / ''cursor''. Pediré prestada la función read_mongo anterior.
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
Otra opción que encontré muy útil es:
from pandas.io.json import json_normalize
cursor = my_collection.find()
df = json_normalize(cursor)
De esta forma, obtienes el despliegue de documentos mongodb anidados de forma gratuita.
Para tratar con datos fuera del núcleo (que no se ajustan a la RAM) de manera eficiente (es decir, con ejecución paralela), puede probar el ecosistema Python Blaze : Blaze / Dask / Odo.
Blaze (y Odo ) tiene funciones listas para usar para manejar MongoDB.
Algunos artículos útiles para comenzar:
- Presentamos Blaze Expessions (con el ejemplo de consulta de MongoDB)
- ReproduceIt: conteo de palabras Reddit
- Diferencia entre Dask Arrays y Blaze
Y un artículo que muestra qué cosas increíbles son posibles con Blaze stack: analizando 1.7 mil millones de comentarios de Reddit con Blaze e Impala (en esencia, consultar 975 Gb de comentarios de Reddit en segundos).
PD: No estoy afiliado a ninguna de estas tecnologías.
Puede cargar sus datos de mongodb en pandas DataFrame utilizando este código. Esto funciona para mi. Afortunadamente para ti también
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()))
Según PEP, simple es mejor que complicado:
import pandas as pd
df = pd.DataFrame.from_records(db.<database_name>.<collection_name>.find())
Puede incluir condiciones tal como lo haría con la base de datos mongoDB normal o incluso usar find_one () para obtener solo un elemento de la base de datos, etc.
¡y voilá!
Un enfoque similar al de Rafael Valero, waitingkuo y Deu Leung usando la paginación :
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
Utilizando
pandas.DataFrame(list(...))
consumirá mucha memoria si el resultado del iterador / generador es grande
mejor generar pequeños trozos y concat al final
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
read_csv
a csv y use read_csv
o JSON y use DataFrame.from_records
Monary
hace exactamente eso, y es súper rápido . ( otro enlace )
Mira esta interesante publicación que incluye un tutorial rápido y algunos horarios.
pymongo
podría darte una mano, los siguientes son algunos códigos que estoy usando:
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
import pandas as pd
from odo import odo
data = odo(''mongodb://localhost/db::collection'', pd.DataFrame)