J'ai une grande quantité de données dans une collection de mongodb que je dois analyser. Comment puis-je importer ces données sur des pandas?
Je suis nouveau sur pandas et numpy.
EDIT: La collection mongodb contient des valeurs de capteur étiquetées avec la date et l'heure. Les valeurs du capteur sont du type de données float.
Exemple de données:
{
"_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
}
pymongo
pourrait vous donner un coup de main, voici quelques codes que j'utilise:
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
Vous pouvez charger vos données mongodb sur pandas DataFrame en utilisant ce code. Cela fonctionne pour moi. J'espère pour vous aussi.
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
fait exactement cela, et c'est très rapide . ( n autre lien )
Voir ce post cool qui comprend un tutoriel rapide et quelques timings.
Selon PEP, simple vaut mieux que compliqué:
import pandas as pd
df = pd.DataFrame.from_records(db.<database_name>.<collection_name>.find())
Vous pouvez inclure des conditions comme vous le feriez avec une base de données mongoDB classique ou même utiliser find_one () pour obtenir un seul élément de la base de données, etc.
et le tour est joué!
import pandas as pd
from odo import odo
data = odo('mongodb://localhost/db::collection', pd.DataFrame)
Pour gérer efficacement les données hors cœur (ne s'intégrant pas dans la RAM) (c'est-à-dire avec une exécution en parallèle), vous pouvez essayer écosystème Python Blaze : Blaze/Dask/Odo.
Blaze (et Odo ) possède des fonctions prédéfinies pour gérer MongoDB.
Quelques articles utiles pour commencer:
Et un article qui montre les possibilités incroyables de Blaze stack: Analyse de 1,7 milliard de commentaires Reddit avec Blaze et Impala (essentiellement, interroger 975 Go de commentaires Reddit en quelques secondes).
P.S. Je ne suis affilié à aucune de ces technologies.
Une autre option que j'ai trouvée très utile est:
from pandas.io.json import json_normalize
cursor = my_collection.find()
df = json_normalize(cursor)
de cette façon, vous obtenez gratuitement le déploiement des documents imbriqués mongodb.
En utilisant
pandas.DataFrame(list(...))
consomme beaucoup de mémoire si le résultat de l'itérateur/générateur est volumineux
mieux générer de petits morceaux et concat à la fin
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
exporter en csv et utiliser read_csv
ou JSON et utilisez DataFrame.from_records
Suite à cette excellente réponse de waitingkuo , je voudrais ajouter la possibilité de le faire en utilisant chunksize en ligne avec . Read_sql () et . Read_csv () =. J'élargis la réponse de Deu Leung en évitant d'aller un à un chaque "enregistrement" de "l'itérateur"/"curseur". Je vais emprunter la fonction précédente 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
Une approche similaire à celle de Rafael Valero, waitingkuo et Deu Leung utilisant pagination:
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