【问题标题】:Pandas json column store as nested dataframePandas json 列存储为嵌套数据框
【发布时间】:2022-01-04 10:26:54
【问题描述】:

我有一个包含 json 列的数据框,它非常大而且效率不高,我想将它存储为嵌套数据框。

所以示例数据框看起来像:

id                       date                                                                                                                                              ag                                                                                         marks
0  I2213 2022-01-01 13:28:05.448054  [{'type': 'A', 'values': {'X': {'F1': 0.1, 'F2': 0.2}, 'U': {'F1': 0.3, 'F2': 0.4}}}, {'type': 'B', 'results': {'Y': {'F1': 0.3, 'F2': 0.2}}}]            [{'type': 'A', 'marks': {'X': 0.5, 'U': 0.7}}, {'type': 'B', 'marks': {'Y': 0.4}}]
1  I2213 2022-01-01 14:28:05.448054                                                                                        [{'type': 'B', 'values': {'Z': {'F1': 0.4, 'F2': 0.2}}}]  [{'type': 'A', 'marks': {'X': 0.4, 'U': 0.6}}, {'type': 'B', 'marks': {'Y': 0.3, 'Z': 0.4}}]
2  I2213 2022-01-03 15:28:05.448054                                                                                        [{'type': 'A', 'values': {'X': {'F1': 0.2, 'F2': 0.1}}}]            [{'type': 'A', 'marks': {'X': 0.2, 'U': 0.9}}, {'type': 'B', 'marks': {'Y': 0.2}}]

预期输出:

按日期分组。生成示例数据框的示例代码:

from datetime import datetime, timedelta

def sample_data():
    ag_data = [
        "[{'type': 'A', 'values': {'X': {'F1': 0.1, 'F2': 0.2}, 'U': {'F1': 0.3, 'F2': 0.4}}}, {'type': 'B', 'results': {'Y': {'F1': 0.3, 'F2': 0.2}}}]",
        "[{'type': 'B', 'values': {'Z': {'F1': 0.4, 'F2': 0.2}}}]",
        "[{'type': 'A', 'values': {'X': {'F1': 0.2, 'F2': 0.1}}}]",
    ]
    marks_data = [
         "[{'type': 'A', 'marks': {'X': 0.5, 'U': 0.7}}, {'type': 'B', 'marks': {'Y': 0.4}}]",
         "[{'type': 'A', 'marks': {'X': 0.4, 'U': 0.6}}, {'type': 'B', 'marks': {'Y': 0.3, 'Z': 0.4}}]",
         "[{'type': 'A', 'marks': {'X': 0.2, 'U': 0.9}}, {'type': 'B', 'marks': {'Y': 0.2}}]",
    ]
    date_data = [
        datetime.now() - timedelta(3, seconds=7200),
        datetime.now() - timedelta(3, seconds=3600),
        datetime.now() - timedelta(1),
    ]
    df = pd.DataFrame()
    df['date'] = date_data
    df['ag'] = ag_data
    df['marks'] = marks_data
    df['id'] = 'I2213'
    return df

我尝试使用 json 规范化,但它以柱状方式创建数据框,例如:

d = a['ag'].apply(lambda x: pd.json_normalize(json.loads(x.replace("'", '"'))))

给出带有列type values.X.F1 values.X.F2 values.U.F1 values.U.F2 results.Y.F1 results.Y.F2 的数据框,问题是如何将 dict 键(如 X、Y、F1、F2)作为行而不是列。

是否可以实现如图所示的所需格式?

【问题讨论】:

标签: python json pandas dataframe


【解决方案1】:

我尝试过创建辅助函数。

def ag_col_helper(ag_df):
    s = pd.json_normalize(json.loads(ag_df.replace("\'", "\"")))
    s.set_index('type', inplace=True)
    s1 = s.melt(ignore_index=False, var_name='feature')
    split_vals = s1['feature'].str.split(".", n = 2, expand = True)
    s1['name'] = split_vals[1]
    s1['feature'] =  split_vals[2]
    return s1.groupby(['type', 'name', 'feature']).first().dropna()


def marks_col_helper(marks_df):
    s = pd.json_normalize(json.loads(marks_df.replace("\'", "\"")))
    s.set_index('type', inplace=True)
    s1 = s.melt(ignore_index=False, var_name='name', value_name='marks')
    split_vals = s1['name'].str.split(".", n = 2, expand = True)
    s1['name'] = split_vals[1]
    return s1.groupby(['type', 'name']).first().dropna()

那么这可以应用到列ag

df['ag'] = df['ag'].apply(lambda x: do_something(x))
df['marks'] = df['marks'].apply(lambda x: do_something_marks(x))[0]

然后我们会得到

df.iloc[0]['ag']

                   value
type name feature       
A    U    F1         0.3
          F2         0.4
     X    F1         0.1
          F2         0.2
B    Y    F1         0.3
          F2         0.2

df.iloc[0]['marks']

           marks
type name       
A    U       0.7
     X       0.5
B    Y       0.4

我认为这是您所期望的。

要对日期列进行分组,您可以使用df['Date'] = df['date'].dt.date 创建另一列并执行分组。

【讨论】:

    【解决方案2】:

    看来您可以将数据框设置为数据框中的值。这个:

    import pandas as pd
    
    #creating outer df
    df = pd.DataFrame([{'a':1, 'b':2, 'inner':None},{'a':3, 'b':4, 'inner':None}])
    
    #creating inner dfs
    inner_1 = pd.DataFrame([{'time': 0, 'e': 1}, {'time': 1, 'e': 2}])
    inner_2 = pd.DataFrame([{'time': 0, 'e': 6}, {'time': 1, 'e': 7}])
    inners = [inner_1, inner_2]
    
    df['inner'] = inners
    print(df)
    

    结果:

       a  b       inner
    0  1  2        time  e
               0     0  1
               1     1  2
    1  3  4        time  e
               0     0  6
               1     1  7
    
    

    打印出来的东西很快就会变得混乱,但它似乎就是你想要的。

    针对您的数据,获取您的字典列表并将它们转换为带有pd.DataFramedf。如果您想将所有列表转换为数据框,可以使用以下内容:

    import pandas as pd
    
    #creating outer df
    df = pd.DataFrame([{'a':1, 'b':2, 'inner':None},{'a':3, 'b':4, 'inner':None}])
    
    #creating inner dfs
    inner_1 = [{'time': 0, 'e': 1}, {'time': 1, 'e': 2}]
    inner_2 = [{'time': 0, 'e': 6}, {'time': 1, 'e': 7}]
    inners = [inner_1, inner_2]
    
    df['inner'] = inners
    print('un-transformed')
    print(df)
    
    #transforming all lists into DFs
    for i in range(df.shape[0]): #iterate over rows
        for j in range(df.shape[1]): #iterate over columns
            if type(df.iat[i,j]) == list: #filtering cells that are lists
                df.iat[i, j] = pd.DataFrame(df.iat[i, j]) #convert to df
    
    print("transformed")
    print(df)
    

    返回

    un-transformed
       a  b                                       inner
    0  1  2  [{'time': 0, 'e': 1}, {'time': 1, 'e': 2}]
    1  3  4  [{'time': 0, 'e': 6}, {'time': 1, 'e': 7}]
    transformed
       a  b       inner
    0  1  2        time  e
               0     0  1
               1     1  2
    1  3  4        time  e
               0     0  6
               1     1  7
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-27
      • 2017-03-21
      • 2020-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      • 2019-11-24
      相关资源
      最近更新 更多