【问题标题】:Flatten JSON Columns in Dataframe展平数据框中的 JSON 列
【发布时间】:2022-01-12 15:25:52
【问题描述】:

我在如下所示的数据框中有数据。我正在尝试展平数据,以便 JSON blob 中的值转换为列,如果 JSON blob 中有多个记录,它会创建一个新行。我想保留非 JSON 字段(即 ID)。

我特别关注:How to flatten a pandas dataframe with some columns as json? - 但在执行后,我使用未解析 JSON 的相同数据帧失败。下面是该帖子中的函数的 sn-p,它以前对我有用:

def flatten_nested_json_df(df):

    df = df.reset_index()

    print(f"original shape: {df.shape}")
    print(f"original columns: {df.columns}")


    # search for columns to explode/flatten
    s = (df.applymap(type) == list).all()
    list_columns = s[s].index.tolist()

    s = (df.applymap(type) == dict).all()
    dict_columns = s[s].index.tolist()

    print(f"lists: {list_columns}, dicts: {dict_columns}")
    while len(list_columns) > 0 or len(dict_columns) > 0:
        new_columns = []

        for col in dict_columns:
            print(f"flattening: {col}")
            # explode dictionaries horizontally, adding new columns
            horiz_exploded = pd.json_normalize(df[col]).add_prefix(f'{col}.')
            horiz_exploded.index = df.index
            df = pd.concat([df, horiz_exploded], axis=1).drop(columns=[col])
            new_columns.extend(horiz_exploded.columns) # inplace

        for col in list_columns:
            print(f"exploding: {col}")
            # explode lists vertically, adding new columns
            df = df.drop(columns=[col]).join(df[col].explode().to_frame())
            new_columns.append(col)

        # check if there are still dict o list fields to flatten
        s = (df[new_columns].applymap(type) == list).all()
        list_columns = s[s].index.tolist()

        s = (df[new_columns].applymap(type) == dict).all()
        dict_columns = s[s].index.tolist()

        print(f"lists: {list_columns}, dicts: {dict_columns}")

    print(f"final shape: {df.shape}")
    print(f"final columns: {df.columns}")
    return df

感谢任何帮助!

ID PROPERTIES FORMSUBMISSIONS
123 {"firstname":{"value":"FAKE"},"lastmodifieddate":{"value":"FAKE"},"lastname":{"value":"FAKE"}} [{"contact-associated-by":["FAKE"],"conversion-id":"FAKE","form-id":"FAKE","form-type":"FAKE","meta-data":[],"portal-id": FAKE,"timestamp": FAKE,"title":"FAKE"}]

【问题讨论】:

  • 我尝试的每一个方法都出错,'str'对象没有属性'values'或'list'对象没有属性'values' - 我知道我一定缺少一些简单的东西
  • 这个错误通常意味着你传递给pd.json_normalize的是一个列表而不是一个对象。 explode 在传递给 pd.json_normalize 之前的列也是如此。另外,请包含您当前拥有的代码,以便人们可以提供帮助。
  • @emma 感谢您的回复 - 刚刚编辑了我的初始帖子以添加我之前一直在尝试的对我有用的功能 - 当我执行 pd.read_json(dataframe["FORMSUBMISSIONS"][0]) 时,我可以获得所需的结果,但我无法弄清楚如何在数据框中应用它

标签: python json pandas


【解决方案1】:

你可以使用pd.json_normalize,应该更简单。

>>> df
    ID                                         PROPERTIES                                    FORMSUBMISSIONS
0  123  {'firstname': {'value': 'FAKE'}, 'lastmodified...  [{'contact-associated-by': ['FAKE'], 'conversi...

>>> df = df.explode('FORMSUBMISSIONS')  # list to dict
>>> df
    ID                                         PROPERTIES                                    FORMSUBMISSIONS
0  123  {'firstname': {'value': 'FAKE'}, 'lastmodified...  {'contact-associated-by': ['FAKE'], 'conversio...

现在您可以在 FORMSUBMISSIONS 列上执行 json_normalize。为了保留其他列,我使用pd.concat

>>> df = pd.concat([df, pd.json_normalize(df['FORMSUBMISSIONS']), axis=1).drop('FORMSUBMISSIONS', axis=1)

>>> df
    ID                                         PROPERTIES contact-associated-by conversion-id form-id form-type meta-data portal-id timestamp title
0  123  {'firstname': {'value': 'FAKE'}, 'lastmodified...                [FAKE]          FAKE    FAKE      FAKE        []      FAKE      FAKE  FAKE

您可以在 PROPERTIES 列上执行相同的操作。

df = pd.concat([df, pd.json_normalize(df.PROPERTIES)], axis=1).drop('PROPERTIES', axis=1)

【讨论】:

  • 再次感谢您在这里的帮助 - 我执行了这个:df = dataframe df1 = df.explode('FORMSUBMISSIONS') df1 = pd.concat(df1, pd.json_normalize(df1['FORMSUBMISSIONS']), axis=1).drop('FORMSUBMISSIONS', axis=1) df1 但得到了同样的错误'str' object has no attribute 'values'
  • 听起来你在列中有字符串。如果您正在从 JSON 文件中读取数据,您可以粘贴原始 JSON 吗?如果没有,你能告诉我你在explode之前从df.to_dict()得到什么吗?
  • 'FORMSUBMISSIONS': {0: '[{"contact-associated-by":["EMAIL"],"conversion-id":"FAKEVALUE","form-id":"FAKEVALUE","form-type":"FAKEVALUE","meta-data":[],"portal-id":FAKEVALUE,"timestamp":FAKEVALUE,"title":"FAKEVALUE"}]', 这是我运行 df.to_dict() 后的第一条记录
  • 对。你有FORMSUBMISSIONS 的字符串列表。您需要在explode 之前取消字符串化。 df['FORMSUBMISSIONS'] = [json.loads(x) for x in df.FORMSUBMISSIONS]df = df.explode('FORMSUBMISSIONS')
  • 哇,艾玛——我认为这很有效。同样的方法不适用于 PROPERTIES,但我想我只需要多玩一点..谢谢你
猜你喜欢
  • 1970-01-01
  • 2022-01-16
  • 2020-04-30
  • 2020-09-27
  • 2023-03-07
  • 1970-01-01
  • 2019-03-08
  • 2020-05-31
  • 1970-01-01
相关资源
最近更新 更多