簡體   English   中英

將嵌套的mongoDB文檔轉換為平面pandas DataFrame(對象數組中的對象數組)

[英]Convert nested mongoDB document into flat pandas DataFrame (Array of objects within array of objects)

我試圖將mongoDB文檔轉換為扁平的pandas數據幀結構。

我的mongoDB集合結構的一個例子:

data = collection.find_one({'ID':300})
print(data)

{'_id': "ObjectId('5cd932299f6b7d4c9b95af6c')",
 'ID': 300,
 'updated': 23424,
 'data': [
     { 'meta': 8,
       'data': [
           {'value1': 1, 'value2': 2}, 
           {'value1': 3, 'value2': 4}
       ]
     },
     { 'meta': 9,
       'data': [
           {'value1': 5, 'value2': 6}
       ]
     }
  ]
}

當我把它放入熊貓數據幀時,我明白了

df = pd.DataFrame(data)
print(df)

| _id                      | ID  | updated | data                                              
|
|--------------------------|-----|---------|------------------------ ---------------------------|
| 5cd936779f6b7d4c9b95af6d | 300 | 23424   | {'meta': 8, 'data': [{'value1': 1, 'value2': 2... |
| 5cd936779f6b7d4c9b95af6d | 300 | 23424   | {'meta': 9, 'data': [{'value1': 5, 'value2': 6}]} |

當我用pd.concat迭代數據幀時,我得到了

df.rename(columns={'data':'data1'}, inplace=True)
df2 = pd.concat([df, pd.DataFrame(list(df['data1']))], axis=1).drop('data1', 1)
df3 = pd.concat([df2, pd.DataFrame(list(df2['data']))], axis=1).drop('data', 1)
print(df3)

| _id                      | ID  | updated | meta | 0                          | 1                          |
|--------------------------|-----|---------|------|----------------------------|----------------------------|
| 5cd936779f6b7d4c9b95af6d | 300 | 23424   | 8    | {'value1': 1, 'value2': 2} | {'value1': 3, 'value2': 4} |
| 5cd936779f6b7d4c9b95af6d | 300 | 23424   | 9    | {'value1': 5, 'value2': 6} | None                       |

最低級別數組的最低級別對象始終具有相同的名稱。

因此我想要:

| ID  | updated | meta | value1 | value2 |
|-----|---------|------|--------|--------|
| 300 | 23424   | 8    | 1      | 2      |
| 300 | 23424   | 8    | 3      | 4      |
| 300 | 23424   | 9    | 5      | 6      |

我走錯了路嗎?

什么是最方便的解決方法?

好吧,我設法以最可怕的方式解決它。

def flatten(data):
    a = {}
    def make_dict(data):
        for i in list(data):
            if isinstance(data[i], list):
                for j in data[i]:
                    make_dict(j)
            else:
                a.update({i:[]})
        return data

    def add_to_dict(data):
        for i in list(data):
            if isinstance(data[i], list):
                for j in data[i]:
                    add_to_dict(j)
            else:
                a[i].append(data[i])
        max = 0
        for i in a:
            if len(a[i]) > max:
                max = len(a[i])
        for i in a:
            if len(a[i]) < max:
                a[i].append(a[i][-1])

    make_dict(data)
    add_to_dict(data)
    return a


pd.DataFrame(flatten(data))

輸出:

| ID  | updated | meta | value1 | value2 |
|-----|---------|------|--------|--------|
| 300 | 23424   | 8    | 1      | 2      |
| 300 | 23424   | 8    | 3      | 4      |
| 300 | 23424   | 9    | 5      | 6      |

我無法想象這是一個很好的解決方案,所以請隨時幫助我做一個更好的解決方案。

我意識到mongoDB可以完成所有繁重的工作。

工作代碼:

import pandas as pd
from pymongo import MongoClient
mongoClient = MongoClient('localhost', 27017)
db = mongoClient.DB_NAME
collection = db.COLLECTION_NAME

pipeline = [
    {'$match':{'ID':300}},
    {"$unwind":{'path': '$data', 'preserveNullAndEmptyArrays': True}},
    {"$unwind":{'path': '$data.data', 'preserveNullAndEmptyArrays': True}},
    {'$project':{
      'ID':'$ID',
      'updated':"$updated",
      'meta':"$data.meta",
      'value1':"$data.data.value1",
      'value2':"$data.data.value2"
    }}
]

#Make empty dataframe
df = pd.DataFrame() 

#add each doc as a new row in dataframe
for doc in collection.aggregate(pipeline): 
    df = df.append(doc,ignore_index=True)

print(df)

輸出:

| ID  | updated | meta | value1 | value2 |
|-----|---------|------|--------|--------|
| 300 | 23424   | 8    | 1      | 2      |
| 300 | 23424   | 8    | 3      | 4      |
| 300 | 23424   | 9    | 5      | 6      |

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM