展开双重嵌套的JSON

10

我正在尝试展开一个看起来像这样的JSON文件:

{
"teams": [
  {
    "teamname": "1",
    "members": [
      {
        "firstname": "John", 
        "lastname": "Doe",
        "orgname": "Anon",
        "phone": "916-555-1234",
        "mobile": "",
        "email": "john.doe@wildlife.net"
      },
      {
        "firstname": "Jane",
        "lastname": "Doe",
        "orgname": "Anon",
        "phone": "916-555-4321",
        "mobile": "916-555-7890",
        "email": "jane.doe@wildlife.net"
      }
    ]
  },
  {
    "teamname": "2",
    "members": [
      {
        "firstname": "Mickey",
        "lastname": "Moose",
        "orgname": "Moosers",
        "phone": "916-555-0000",
        "mobile": "916-555-1111",
        "email": "mickey.moose@wildlife.net"
      },
      {
        "firstname": "Minny",
        "lastname": "Moose",
        "orgname": "Moosers",
        "phone": "916-555-2222",
        "mobile": "",
        "email": "minny.moose@wildlife.net"
      }
    ]
  }       
]

}

我希望能将这个导出为Excel表格。 我目前的代码是这样的:

from pandas.io.json import json_normalize
import json
import pandas as pd

inputFile = 'E:\\teams.json'
outputFile = 'E:\\teams.xlsx'

f = open(inputFile)
data = json.load(f)
f.close()

df = pd.DataFrame(data)

result1 = json_normalize(data, 'teams' )
print result1

产生这个输出的结果:

members                                              teamname
0  [{u'firstname': u'John', u'phone': u'916-555-...        1
1  [{u'firstname': u'Mickey', u'phone': u'916-555-...      2

每行中嵌套了2个成员的数据。我想要一个输出表格,显示所有4个成员的数据以及他们所属的团队名称。

2个回答

15

使用pandas.io.json.json_normalize

json_normalize(data,record_path=['teams','members'],meta=[['teams','teamname']])

output:
         email                firstname lastname mobile      orgname    phone       teams.teamname
0   john.doe@wildlife.net       John    Doe                   Anon      916-555-1234    1
1   jane.doe@wildlife.net       Jane    Doe     916-555-7890  Anon      916-555-4321    1
2   mickey.moose@wildlife.net   Mickey  Moose   916-555-1111  Moosers   916-555-0000    2
3   minny.moose@wildlife.net    Minny   Moose                 Moosers   916-555-2222    2


解释

from pandas.io.json import json_normalize
import pandas as pd

我最近才学会如何使用 json_normalize 函数,所以我的解释可能不正确。

从我称之为“第 0 层”开始。

json_normalize(data)

output:
     teams
0   [{'teamname': '1', 'members': [{'firstname': '...

有1列和1行。所有内容都在“ team”列中。

通过使用record_path =查看我所谓的“ Layer 1”

json_normalize(data,record_path='teams')

output:
     members                                          teamname
0   [{'firstname': 'John', 'lastname': 'Doe', 'org...    1
1   [{'firstname': 'Mickey', 'lastname': 'Moose', ...    2

在第一层,我们已经将'teamname'展平了,但是'members'内部还有更多信息。

通过record_path=.查看第二层。这种符号在开始时可能不直观。我现在记得它是由['layer', 'deeperlayer']组成的,其中结果为layer.deeperlayer。

json_normalize(data,record_path=['teams','members'])

output:
           email              firstname lastname   mobile     orgname   phone
0   john.doe@wildlife.net      John        Doe                  Anon    916-555-1234
1   jane.doe@wildlife.net       Jane        Doe   916-555-7890  Anon    916-555-4321
2   mickey.moose@wildlife.net   Mickey     Moose   916-555-1111 Moosers 916-555-0000
3   minny.moose@wildlife.net    Minny       Moose               Moosers 916-555-2222

抱歉我的输出有误,我不知道如何在响应中制作表格。

最后,我们使用meta=添加第1层列。

json_normalize(data,record_path=['teams','members'],meta=[['teams','teamname']])

output:
         email                firstname lastname mobile      orgname    phone       teams.teamname
0   john.doe@wildlife.net       John    Doe                   Anon      916-555-1234    1
1   jane.doe@wildlife.net       Jane    Doe     916-555-7890  Anon      916-555-4321    1
2   mickey.moose@wildlife.net   Mickey  Moose   916-555-1111  Moosers   916-555-0000    2
3   minny.moose@wildlife.net    Minny   Moose                 Moosers   916-555-2222    2

请注意,我们需要一个列表的列表meta=[[]]来引用第一层。 如果我们想从第0层和第1层获取一列,我们可以这样做:

json_normalize(data,record_path=['layer1','layer2'],meta=['layer0',['layer0','layer1']])
json_normalize的结果是一个pandas数据框。

11
这是一种方法。可以给你一些想法。
df = pd.concat(
    [
        pd.concat([pd.Series(m) for m in t['members']], axis=1) for t in data['teams']
    ], keys=[t['teamname'] for t in data['teams']]
)

                                     0                         1
1 email          john.doe@wildlife.net     jane.doe@wildlife.net
  firstname                       John                      Jane
  lastname                         Doe                       Doe
  mobile                                            916-555-7890
  orgname                         Anon                      Anon
  phone                   916-555-1234              916-555-4321
2 email      mickey.moose@wildlife.net  minny.moose@wildlife.net
  firstname                     Mickey                     Minny
  lastname                       Moose                     Moose
  mobile                  916-555-1111                          
  orgname                      Moosers                   Moosers
  phone                   916-555-0000              916-555-2222

为了获得一个漂亮的表格,其中团队名称和成员作为行,所有属性都在列中:
df.index.levels[0].name = 'teamname'
df.columns.name = 'member'

df.T.stack(0).swaplevel(0, 1).sort_index()

enter image description here

为了获取团队名称和成员作为实际列,只需重置索引即可。
df.index.levels[0].name = 'teamname'
df.columns.name = 'member'

df.T.stack(0).swaplevel(0, 1).sort_index().reset_index()

enter image description here

整个事情

import json
import pandas as pd

json_text = """{
"teams": [
  {
    "teamname": "1",
    "members": [
      {
        "firstname": "John", 
        "lastname": "Doe",
        "orgname": "Anon",
        "phone": "916-555-1234",
        "mobile": "",
        "email": "john.doe@wildlife.net"
      },
      {
        "firstname": "Jane",
        "lastname": "Doe",
        "orgname": "Anon",
        "phone": "916-555-4321",
        "mobile": "916-555-7890",
        "email": "jane.doe@wildlife.net"
      }
    ]
  },
  {
    "teamname": "2",
    "members": [
      {
        "firstname": "Mickey",
        "lastname": "Moose",
        "orgname": "Moosers",
        "phone": "916-555-0000",
        "mobile": "916-555-1111",
        "email": "mickey.moose@wildlife.net"
      },
      {
        "firstname": "Minny",
        "lastname": "Moose",
        "orgname": "Moosers",
        "phone": "916-555-2222",
        "mobile": "",
        "email": "minny.moose@wildlife.net"
      }
    ]
  }       
]
}"""


data = json.loads(json_text)

df = pd.concat(
    [
        pd.concat([pd.Series(m) for m in t['members']], axis=1) for t in data['teams']
    ], keys=[t['teamname'] for t in data['teams']]
)

df.index.levels[0].name = 'teamname'
df.columns.name = 'member'

df.T.stack(0).swaplevel(0, 1).sort_index().reset_index()

你创建的示例看起来很完美。但是当我运行代码时,在 df.index.levels[0].name = 'teamname' 这一行会返回以下错误:AttributeError: 'Int64Index' object has no attribute 'levels'。 - spaine
这是我的错。我编辑了帖子,忘记将 pd.concat 分配给数据框 df - piRSquared
这对我非常有帮助 - 我需要进行一些研究才能确切地理解您的代码是如何工作的。我可以问一下您是如何将上面发布的数据制成表格形式的吗? - spaine
嗯,当我包含最后两个脚本中的任意一个或两个时,将其转换为表格后,它仍然保持您在 pd.concat 之后所展示的状态。 - spaine
好的,我之前的代码是基于一个假设,即你的数据和我的一样。我会再次更新代码,确保和我运行的完全一致。 - piRSquared
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接