【问题标题】:Pandas json normalize why it returns NaN for repeated valuesPandas json 标准化为什么它为重复值返回 NaN
【发布时间】:2022-01-18 15:45:33
【问题描述】:

我有一个数据框,其中 2 列是我想扩展为单独列的字典列表。例如:

 id    text                   agg_inds                                           agg_tars
 1     some text    [{"f1": [15], "f2": "2263"}, {"f1": [16], "f2": "2171"}]    [{"f1": [5, 6, 12], "f2": "2984"}]

我想为名为 agg_indsind_id 的嵌套列 agg_inds 创建 2 个列,并为名为 tar_postar_idagg_tars 创建 2 个不同的列。

使用 json_normalize 的问题是当一个值重复时它返回 NaN 值。例如,在上面的行中,我想要这个:

期望的输出

id  text        ind_pos     ind_id         tar_pos        tar_ind
1               [15]        2263           [5, 6, 12]     2984    
1   some text   [16]        2171           [5, 6, 12]     2984    

但这是当前输出

id  tex  ind_pos      ind_id        tar_pos        tar_ind
1         [15]        2263          [5, 6, 12]     2984    
1   NaN   [16]        2171          NaN            NaN    

代码如下:

s = (df.set_index('id')
          .apply(lambda x: x.apply(pd.Series).stack())
          .reset_index()
          .drop('level_1', 1))

s_ind = pd.json_normalize(s['agg_inds'])
columns_renaming = {"f1": "ind_pos", "f2": "ind_id"}
s_ind.rename(columns=columns_renaming, inplace=True)

s_tar= pd.json_normalize(s['agg_targets'])
columns_renaming = {"f1": "tar_pos", "f2": "tar_id"}
s_tar.rename(columns=columns_renaming, inplace=True)

s = s.drop(columns=['agg_inds', 'agg_targets'])
df_1 = s.join(s_ind)
df_final = df_1.join(s_tar)
print(df_final)

【问题讨论】:

    标签: python pandas explode json-normalize


    【解决方案1】:

    您可以使用ffillNaN 值替换为上一行的值。为此,您只需添加一行:

    s = (df.set_index('id')
              .apply(lambda x: x.apply(pd.Series).stack())
              .reset_index()
              .drop('level_1', 1))
    
    s.ffill(inplace=True)
    
    s_ind = pd.json_normalize(s['agg_inds'])
    columns_renaming = {"f1": "ind_pos", "f2": "ind_id"}
    s_ind.rename(columns=columns_renaming, inplace=True)
    
    s_tar= pd.json_normalize(s['agg_targets'])
    columns_renaming = {"f1": "tar_pos", "f2": "tar_id"}
    s_tar.rename(columns=columns_renaming, inplace=True)
    
    s = s.drop(columns=['agg_inds', 'agg_targets'])
    df_1 = s.join(s_ind)
    df_final = df_1.join(s_tar)
    print(df_final)
    

    输出:

       id        text ind_pos ind_id     tar_pos tar_id
    0   1   some text    [15]   2263  [5, 6, 12]   2984
    1   1   some text    [16]   2171  [5, 6, 12]   2984
    

    【讨论】:

      【解决方案2】:

      如果我有这样的初始数据集:

      # import libraries
      import pandas as pd
      import json
      
      # read data
      df = pd.DataFrame({
          'id': [1],
          'text': ['some text'],
          'agg_inds': ['[{"f1": [15], "f2": "2263"}, {"f1": [16], "f2": "2171"}]'],
          'agg_tars': ['[{"f1": [5, 6, 12], "f2": "2984"}]'],
      })
      
      # convert columns
      for col in ['agg_inds', 'agg_tars']:
          df[col] = df[col].apply(lambda x: json.loads(x))
      
      # set id column as index
      df = df.set_index('id')
      

      然后我可以重用您的处理逻辑,以创建一个函数来提取这两种类型的特征,并从中创建一个数据框:

      def extract_features(col: str, feat_new_names: dict):
          return (
              df[col]
              .apply(pd.Series)
              .stack()
              .apply(pd.Series)
              .reset_index()
              .drop(['level_1'], axis=1)
              .set_index('id')
              .rename(columns=feat_new_names)
          )
      
      df_agg_inds = extract_features(col='agg_inds', feat_new_names={'f1': 'ind_pos', 'f2': 'ind_id'})
      df_agg_tars = extract_features(col='agg_tars', feat_new_names={'f1': 'tar_pos', 'f2': 'tar_id'})
      

      因为所有数据框都将id 列设置为索引,所以我可以使用外连接将它们放在一起而不会丢失任何信息:

      df_final = (
          pd
          .concat([df, df_agg_inds, df_agg_tars], axis=1)
          .drop(['agg_inds', 'agg_tars'], axis=1)
      )
      

      结果如下所示:

      >>> print(df_final)
               text ind_pos ind_id     tar_pos tar_id
      id                                             
      1   some text    [15]   2263  [5, 6, 12]   2984
      1   some text    [16]   2171  [5, 6, 12]   2984
      

      我希望这会有所帮助

      【讨论】:

        猜你喜欢
        • 2018-10-01
        • 2021-10-04
        • 1970-01-01
        • 2019-10-12
        • 2015-05-20
        • 2013-08-06
        • 1970-01-01
        • 2017-05-10
        • 1970-01-01
        相关资源
        最近更新 更多