python - 嵌套的 json 到 csv - 通用方法

标签 python json csv pandas

我是 Python 的新手,我正在努力将嵌套的 json 文件转换为 cvs。为此,我首先加载 json,然后将其转换为使用 json_normalize 打印出漂亮输出的方式,然后使用 pandas 包将规范化部分输出到 cvs

我的示例 json:

[{
 "_id": {
   "id": "123"
 },
 "device": {
   "browser": "Safari",
   "category": "d",
   "os": "Mac"
 },
 "exID": {
   "$oid": "123"
 },
 "extreme": false,
 "geo": {
   "city": "London",
   "country": "United Kingdom",
   "countryCode": "UK",
   "ip": "00.000.000.0"
 },
 "viewed": {
   "$date": "2011-02-12"
 },
 "attributes": [{
   "name": "gender",
   "numeric": 0,
   "value": 0
 }, {
   "name": "email",
   "value": false
 }],
 "change": [{
   "id": {
     "$id": "1231"
   },
   "seen": [{
     "$date": "2011-02-12"
   }]
 }]
}, {
 "_id": {
   "id": "456"
 },
 "device": {
   "browser": "Chrome 47",
   "category": "d",
   "os": "Windows"
 },
 "exID": {
   "$oid": "345"
 },
 "extreme": false,
 "geo": {
   "city": "Berlin",
   "country": "Germany",
   "countryCode": "DE",
   "ip": "00.000.000.0"
 },
 "viewed": {
   "$date": "2011-05-12"
 },
 "attributes": [{
   "name": "gender",
   "numeric": 1,
   "value": 1
 }, {
   "name": "email",
   "value": true
 }],
 "change": [{
   "id": {
     "$id": "1231"
   },
   "seen": [{
     "$date": "2011-02-12"
   }]
 }]
}]

使用以下代码(这里我排除了嵌套部分):

import json
from pandas.io.json import json_normalize


def loading_file():
    #File path
    file_path = #file path here

    #Loading json file
    json_data = open(file_path)
    data = json.load(json_data)
    return data

#Storing avaliable keys
def data_keys(data):
    keys = {}
    for i in data:
        for k in i.keys():
            keys[k] = 1

    keys = keys.keys()

#Excluding nested arrays from keys - hard coded -> IMPROVE
    new_keys = [x for x in keys if
    x != 'attributes' and
    x != 'change']

    return new_keys

#Excluding nested arrays from json dictionary
def new_data(data, keys):
    new_data = []
    for i in range(0, len(data)):
        x = {k:v for (k,v) in data[i].items() if k in keys }
        new_data.append(x)
    return new_data

 def csv_out(data):
     data.to_csv('out.csv',encoding='utf-8')

def main():
     data_file = loading_file()
     keys = data_keys(data_file)
     table = new_data(data_file, keys)
     csv_out(json_normalize(table))

main()

我当前的输出看起来像这样:

| _id.id | device.browser | device.category | device.os |  ... | viewed.$date |
|--------|----------------|-----------------|-----------|------|--------------|
| 123    | Safari         | d               | Mac       | ...  | 2011-02-12   |
| 456    | Chrome 47      | d               | Windows   | ...  | 2011-05-12   |
|        |                |                 |           |      |              |

我的问题是我想将嵌套数组包含到 cvs 中,所以我必须将它们展平。我不知道如何使它通用,所以我在创建表时不使用字典 keys (numeric, id, name) 和 values。我必须让它具有通用性,因为 attributeschange 中的键数。因此,我希望有这样的输出:

| _id.id | device.browser | ... | attributes_gender_numeric | attributes_gender_value | attributes_email_value | change_id | change_seen |
|--------|----------------|-----|---------------------------|-------------------------|------------------------|-----------|-------------|
| 123    | Safari         | ... | 0                         | 0                       | false                  | 1231      | 2011-02-12  |
| 456    | Chrome 47      | ... | 1                         | 1                       | true                   | 1231      | 2011-02-12  |
|        |                |     |                           |                         |                        |           |             |

提前致谢!非常欢迎任何有关如何改进我的代码并使其更高效的提示。

最佳答案

感谢 Amir Ziai 的精彩博文,您可以找到它 here我设法以平面表格的形式输出我的数据。具有以下功能:

#Function that recursively extracts values out of the object into a flattened dictionary
def flatten_json(data):
    flat = [] #list of flat dictionaries
    def flatten(y):
        out = {}

        def flatten2(x, name=''):
            if type(x) is dict:
                for a in x:
                    if a == "name": 
                            flatten2(x["value"], name + x[a] + '_')
                    else:  
                        flatten2(x[a], name + a + '_')
            elif type(x) is list:
                for a in x:
                    flatten2(a, name + '_')
            else:
                out[name[:-1]] = x

        flatten2(y)
        return out

#Loop needed to flatten multiple objects
    for i in range(len(data)):
        flat.append(flatten(data[i]).copy())

    return json_normalize(flat) 

由于名称-值 if 语句,我知道它不是完全通用的。但是,如果删除创建名称-值字典的豁免,则代码可以与其他嵌入式数组一起使用。

关于python - 嵌套的 json 到 csv - 通用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37706351/

相关文章:

Python 多处理错误 'ForkAwareLocal' 对象没有属性 'connection'

Python 创建一个程序来执行和分析类(class)的最终成绩

javascript - 将 JSON 数据解析为 HTML

javascript - 将 JavaScript 对象转换为 Json,并以双引号 (") 作为值

python - ProgrammingError : (psycopg2. ProgrammingError) 无法适配类型 'dict'

c - 无法找到空标记的空 csv 值的值

ruby-on-rails - rake 数据库 :seed unable to read CSV

datetime - 如何使用 GnuPlot 从存储在单独列中的 CSV 文件日期和时间绘制时间序列图表?

Python re regex 子字母不包含在引号中,并且如果它们匹配特定单词(包括正则表达式组/匹配)则不包含在引号中

Python inspect.stack 很慢