如何在pandas数据框架中使用嵌套字典列表来扁平化一列。

问题描述 投票:0回答:1

我收到了单个JSON(500个JSON),并通过append()方法将它们添加到一个现有列表的末尾,从而对其进行修改。

d_path = r'--PATH HERE--'
d_files = [f for f in listdir(d_path) if isfile(join(d_path,f))]
n = num_data
d_dicts=[]
for counter,d_file in enumerate(d_files):
    with open(d_path+'\\'+d_file,encoding="utf8") as json_data:
        d_dicts.append(json.load(json_data))

    if counter == num_data:
        break

在这一步之后,我尝试使用json_normalize将JSON数据归一化为一个平面表(Pandas DataFrame,共有500行)。

df = json_normalize(d)

附加信息。

class 'pandas.core.frame.DataFrame'

dtypes: float64(8), int64(3), object(9)

到目前为止,除了一列之外,工作得很顺利。我最后有一列,每行都有一个字典列表。我试图寻找一个解决方案,但我找不到一个能帮助我的方案。每一行都有一个嵌套的字典。

下面是一个例子 三行列名 信息栏 与虚构数据,但结构相同。

Info_column

[{**'Greeting':** 'Good day', 'Group': '1.2', 'Window': None, 
'Value1': 17.0, 'Value2': 13.23, 'Value3': 11.0, 
'Date1': '2013-09-04', 'Date2': '2012-09-05', 'Date3': '2015-07-22', 
'Married': False, 'Country': None, 
'Person': [{'Age': '25', 'Number': '82', 'Value4': 19.2, 
'Column1': None, 'Column2': None, 'Column3': None, 'Column4': None}]}]

[{'Greeting': 'Good afternoon', 'Group': '1.4', 'Window': None, 
'Value1': 12.0, 'Value2': 9.23, 'Value3': 2.0, 
'Date1': '2016-09-04', 'Date2': '2016-09-16', 'Date3': '2016-07-05', 
'Married': True, 'Country': Germany, 
'Person': [{'Age': '30', 'Number': '9', 'Value4': 10.0, 
'Column1': None, 'Column2': None, 'Column3': None, 'Column4': None}]}]

[{'Greeting': 'Good evening', 'Group': '3.0', 'Window': True, 
'Value1': 24.0, 'Value2': 15.5, 'Value3': 2.0, 
'Date1': '2019-02-01', 'Date2': '2019-05-05', 'Date3': '2018-05-03', 
'Married': False, 'Country': Spain, 
'Person': [{'Age': '24', 'Number': '12', 'Value4': 8.2, 
'Column1': None, 'Column2': None, 'Column3': None, 'Column4': None}]}]

正确的方法是什么?

我的目标是在我的数据框架中,将此列中每一行的信息作为附加列。

我需要在我的DataFrame df中的其他列旁边添加列。

Greeting, Group, Window, Value1, Value2, Value3, Date1, Date2, Date3, Married, Country, Person_Age, Person_Number, Person_Value4, Person_Column1, Person_Column2, Person_Column3, Person_Column4

非常感谢你的帮助

祝贺你,Elle

python json pandas normalize
1个回答
1
投票

你可以尝试以下方法。

def f(x):
   d = {}
   # Each element of the dict
   for k,v in x.items():
      # Check value type
      if isinstance(v,list):
         # If list: iter sub dict
         for k_s, v_s in v[0].items():
            d["{}_{}".format(k, k_s)] = v_s
      else: d[k] = v
   return pd.Series(d)

out = df.join(df["Info_column"].apply(f))\
        .drop("Info_column", axis=1)

解释:

  1. 所有的问题都是关于扁平化的问题。Info_column. 为此,我们定义一个扁平化函数。"flatten". 它的功能如下。

    • 遍历dict中的每一个keyvalue。
      • 检查值的类型
      • 如果这是一个 list:
        • 遍历所有子元素,并将其添加到输出中。
        • 当前键的父键前缀
      • 否则:添加元素
  2. 应用 flatten 的功能。Info_column 使用 apply

  3. 将当前的数据帧与上一步的输出连接起来。join

  4. 移除 Info_column 使用 axis=1.

完整代码+插图:

# Create dummy dataset with 3 columns
data = [["a", 1, {'Greeting': 'Good day', 'Group': '1.2', 'Window': None,
                  'Value1': 17.0, 'Value2': 13.23, 'Value3': 11.0,
                  'Date1': '2013-09-04', 'Date2': '2012-09-05', 'Date3': '2015-07-22',
                  'Married': False, 'Country': None,
                  'Person': [{'Age': '25', 'Number': '82', 'Value4': 19.2,
                              'Column1': None, 'Column2': None, 'Column3': None, 'Column4': None}]}],
        ["b", 5, {'Greeting': 'Good afternoon', 'Group': '1.4', 'Window': None,
                  'Value1': 12.0, 'Value2': 9.23, 'Value3': 2.0,
                  'Date1': '2016-09-04', 'Date2': '2016-09-16', 'Date3': '2016-07-05',
                  'Married': True, 'Country': "Germany",
                  'Person': [{'Age': '30', 'Number': '9', 'Value4': 10.0,
                              'Column1': None, 'Column2': None, 'Column3': None, 'Column4': None}]}],
        ["c", 2, {'Greeting': 'Good evening', 'Group': '3.0', 'Window': True,
                  'Value1': 24.0, 'Value2': 15.5, 'Value3': 2.0,
                  'Date1': '2019-02-01', 'Date2': '2019-05-05', 'Date3': '2018-05-03',
                  'Married': False, 'Country': "Spain",
                  'Person': [{'Age': '24', 'Number': '12', 'Value4': 8.2,
                              'Column1': None, 'Column2': None, 'Column3': None, 'Column4': None}]}]]

df = pd.DataFrame(data, columns=["colA", "colB", "Info_column"])
print(df)
#   colA  colB                                        Info_column
# 0    a     1  {'Greeting': 'Good day', 'Group': '1.2', 'Wind...
# 1    b     5  {'Greeting': 'Good afternoon', 'Group': '1.4',...
# 2    c     2  {'Greeting': 'Good evening', 'Group': '3.0', '...

# Step 1
def flatten(x):
   d = {}
   # Each element of the dict
   for k,v in x.items():
      # Check value type
      if isinstance(v,list):
         # If list: iter sub dict
         for k_s, v_s in v[0].items():
            d["{}_{}".format(k, k_s)] = v_s
      else: d[k] = v
   return pd.Series(d)

# Step 2
print(df["Info_column"].apply(flatten))
#          Greeting Group Window  Value1  Value2  Value3  ... Person_Number Person_Value4 Person_Column1  Person_Column2 Person_Column3 Person_Column4
# 0        Good day   1.2   None    17.0   13.23    11.0  ...            82          19.2           None            None           None           None
# 1  Good afternoon   1.4   None    12.0    9.23     2.0  ...             9          10.0           None            None           None           None
# 2    Good evening   3.0   True    24.0   15.50     2.0  ...            12           8.2           None            None           None           None
# [3 rows x 18 columns]

# Step 3
print(df.join(df["Info_column"].apply(flatten)))
#   colA  colB                                        Info_column        Greeting  ... Person_Column1 Person_Column2  Person_Column3  Person_Column4
# 0    a     1  {'Greeting': 'Good day', 'Group': '1.2', 'Wind...        Good day  ...           None           None            None            None
# 1    b     5  {'Greeting': 'Good afternoon', 'Group': '1.4',...  Good afternoon  ...           None           None            None            None
# 2    c     2  {'Greeting': 'Good evening', 'Group': '3.0', '...    Good evening  ...           None           None            None            None
# [3 rows x 21 columns]

# Step 4
out = df.join(df["Info_column"].apply(flatten)).drop("Info_column", axis=1)
print(out)
#   colA  colB        Greeting Group Window  Value1  ...  Person_Number  Person_Value4 Person_Column1 Person_Column2 Person_Column3  Person_Column4
# 0    a     1        Good day   1.2   None    17.0  ...             82           19.2           None           None           None            None
# 1    b     5  Good afternoon   1.4   None    12.0  ...              9           10.0           None           None           None            None
# 2    c     2    Good evening   3.0   True    24.0  ...             12            8.2           None           None           None            None
# [3 rows x 20 columns]

print(out.columns)
# Index(['colA', 'colB', 'Greeting', 'Group', 'Window', 'Value1', 'Value2',
#        'Value3', 'Date1', 'Date2', 'Date3', 'Married', 'Country', 'Person_Age',
#        'Person_Number', 'Person_Value4', 'Person_Column1', 'Person_Column2',
#        'Person_Column3', 'Person_Column4'],
#       dtype='object')
© www.soinside.com 2019 - 2024. All rights reserved.