【问题标题】:How to fill dataframe Nan values with empty list [] in pandas?如何在熊猫中用空列表[]填充数据框Nan值?
【发布时间】:2016-01-16 21:38:12
【问题描述】:

这是我的数据框:

          date                          ids
0     2011-04-23  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,...
1     2011-04-24  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,...
2     2011-04-25  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,...
3     2011-04-26  Nan
4     2011-04-27  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,...
5     2011-04-28  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,...

我想用 [] 替换 Nan。怎么做? Fillna([]) 不起作用。我什至尝试过replace(np.nan, []),但它给出了错误:

 TypeError('Invalid "to_replace" type: \'float\'',)

【问题讨论】:

  • 您是如何获得ids 中的列表的?
  • 无法分配空列表,df.ix[df['ids'].isnull(), 'ids'] = set() 设置是否有效?
  • 请注意,这很难做到的一个原因是因为您并不是真的要在数据框单元格中存储非标量值。你可以这样做,它有时作为中间步骤很方便(有许多内置方法将 generate 列表作为元素),但目前还没有强有力的支持。
  • 有趣的是,我设法运行了一个无限循环(到达 RecursionError),使用:df.ids.where(df.ids.isnull(), [[]])

标签: python pandas nan


【解决方案1】:

您可以先使用loc 定位ids 列中具有nan 的所有行,然后使用at 循环遍历这些行以将它们的值设置为一个空列表:

for row in df.loc[df.ids.isnull(), 'ids'].index:
    df.at[row, 'ids'] = []

>>> df
        date                                             ids
0 2011-04-23  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
1 2011-04-24  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
2 2011-04-25  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
3 2011-04-26                                              []
4 2011-04-27  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
5 2011-04-28  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

【讨论】:

    【解决方案2】:

    没有分配:

    1) 假设我们的数据框中只有浮点数和整数

    import math
    df.apply(lambda x:x.apply(lambda x:[] if math.isnan(x) else x))
    

    2) 对于任何数据框

    import math
    def isnan(x):
        if isinstance(x, (int, long, float, complex)) and math.isnan(x):
            return True
    
    df.apply(lambda x:x.apply(lambda x:[] if isnan(x) else x))
    

    【讨论】:

    • 考虑到 numpy 已经作为 np 导入,以下行就足够了 ... df.apply(lambda x: x.apply(lambda x: [] if x is np.nan else x ))
    【解决方案3】:

    经过一番折腾,我发现这种方法应该是最有效的(没有循环,没有应用),只是分配给一个切片:

    isnull = df.ids.isnull()
    
    df.loc[isnull, 'ids'] = [ [[]] * isnull.sum() ]
    

    诀窍是构建您的[] 列表,大小合适(isnull.sum()),然后然后将其包含在列表中:您分配的值是 2D 包含空列表作为元素的数组(1 列,isnull.sum() 行)。

    【讨论】:

    • 这是最有效的答案。
    • 请注意[[]] * isnull.sum() 不会创建isnull.sum() 数量的空列表,它只是创建一个包含多个引用的空列表。
    • 出于某种原因,这对我不起作用,但一个简单的df.loc[isnull, 'ids'] = [[]] 就可以了。可能会随着新版本的 pandas 发生变化。
    • 我非常喜欢这个答案,因为它避免了可能代价高昂的apply,但我收到错误“使用 ndarray 设置时必须具有相等的 len 键和值”。像@Khris 建议的那样简单地做[[]] 会给我同样的错误。但是,stackoverflow.com/a/61944174/4345899 似乎可以工作,所以在 pandas==1.2.2 中的 isna = df[col].isna(); df.loc[isna, [col]] = pd.Series([[]] * isna.sum()).values
    【解决方案4】:

    我的方法与@hellpanderrr 的方法类似,但测试列表性而不是使用isnan

    df['ids'] = df['ids'].apply(lambda d: d if isinstance(d, list) else [])
    

    我最初尝试使用pd.isnull(或pd.notnull),但是当给定一个列表时,它会返回每个元素的空值。

    【讨论】:

      【解决方案5】:

      创建一个检查你的条件的函数,如果不是,它返回一个空列表/空集等。

      然后将该函数应用于变量,但如果您愿意,还可以将新计算的变量分配给旧变量或新变量。

      aa=pd.DataFrame({'d':[1,1,2,3,3,np.NaN],'r':[3,5,5,5,5,'e']})
      
      
      def check_condition(x):
          if x>0:
              return x
          else:
              return list()
      
      aa['d]=aa.d.apply(lambda x:check_condition(x))
      

      【讨论】:

        【解决方案6】:

        也许更密集:

        df['ids'] = [[] if type(x) != list else x for x in df['ids']]
        

        【讨论】:

          【解决方案7】:

          使用 numpy 的另一种解决方案:

          df.ids = np.where(df.ids.isnull(), pd.Series([[]]*len(df)), df.ids)
          

          或者使用 combine_first:

          df.ids = df.ids.combine_first(pd.Series([[]]*len(df)))
          

          【讨论】:

            【解决方案8】:

            这可能更快,一个班轮解决方案:

            df['ids'].fillna('DELETE').apply(lambda x : [] if x=='DELETE' else x)
            

            【讨论】:

              【解决方案9】:

              也许不是最简短/优化的解决方案,但我认为它非常易读:

              # Packages
              import ast
              
              # Masking-in nans
              mask = df['ids'].isna()
              
              # Filling nans with a list-like string and literally-evaluating such string
              df.loc[mask, 'ids'] = df.loc[mask, 'ids'].fillna('[]').apply(ast.literal_eval)
              

              缺点是需要加载ast包。

              编辑

              我最近发现了 eval() 内置的存在。这样可以避免导入任何额外的包。

              # Masking-in nans
              mask = df['ids'].isna()
              
              # Filling nans with a list-like string and literally-evaluating such string
              df.loc[mask, 'ids'] = df.loc[mask, 'ids'].fillna('[]').apply(eval)
              

              【讨论】:

                【解决方案10】:

                令人惊讶的是,将带有空列表的字典作为值传递似乎适用于Series.fillna,但不适用于DataFrame.fillna - 所以如果你想处理单个列,你可以使用这个:

                >>> df
                     A    B    C
                0  0.0  2.0  NaN
                1  NaN  NaN  5.0
                2  NaN  7.0  NaN
                >>> df['C'].fillna({i: [] for i in df.index})
                0    []
                1     5
                2    []
                Name: C, dtype: object
                

                通过将解决方案应用于每一列,可以将解决方案扩展到 DataFrames。

                >>> df.apply(lambda s: s.fillna({i: [] for i in df.index}))
                    A   B   C
                0   0   2  []
                1  []  []   5
                2  []   7  []
                

                注意:对于缺失值很少的大型系列/数据帧,这可能会创建大量的一次性空列表。

                使用pandas 1.0.5 测试。

                【讨论】:

                • 有人会因为我使用这个而杀了我 :) 很好的发现!
                【解决方案11】:

                一个简单的解决方案是:

                df['ids'].fillna("").apply(list)
                

                正如@timgeb 所述,这要求df['ids'] 仅包含列表或nan。

                【讨论】:

                • 酷!请注意,这要求df['ids'] 仅包含列表,除了缺失值(在 OP 的示例中就是这种情况)。
                • 我已经用你的方法测试了@Nick Edgar 方法。你的几乎快 2 倍。谢谢...
                【解决方案12】:

                另一个明确的解决方案:

                # select the nulls
                sel = df.ids.isnull()
                
                # use apply to only replace the nulls with the list  
                df.loc[sel, 'ids'] = df.loc[sel, 'ids'].apply(lambda x: [])
                

                在带有Assigment Expressions (PEP 572) 的Python 3.8 之后,这可以表示为单行而不计算两次选择:

                df.loc[sel, 'ids'] = df.loc[(sel:=df.ids.isnull()), 'ids'].apply(lambda x: [])
                

                【讨论】:

                  猜你喜欢
                  • 2020-11-19
                  • 1970-01-01
                  • 2021-03-02
                  • 2019-11-30
                  • 1970-01-01
                  • 2015-10-12
                  • 2020-07-14
                  • 1970-01-01
                  • 2018-05-07
                  相关资源
                  最近更新 更多