【问题标题】:Dropping infinite values from dataframes in pandas?从熊猫的数据框中删除无限值?
【发布时间】:2013-07-02 21:55:01
【问题描述】:

在不重置mode.use_inf_as_null 的情况下,从pandas.DataFrame 中删除naninf/-inf 值的最快/最简单方法是什么?

我希望能够使用dropnasubsethow 参数,除非inf 值被视为缺失,例如:

df.dropna(subset=["col1", "col2"], how="all", with_inf=True)

这可能吗?有没有办法告诉dropna 在其缺失值的定义中包含inf

【问题讨论】:

    标签: python pandas numpy


    【解决方案1】:

    最简单的方法是先将replace() infs 转换为 NaN:

    df.replace([np.inf, -np.inf], np.nan, inplace=True)
    

    然后使用dropna():

    df.replace([np.inf, -np.inf], np.nan, inplace=True) \
        .dropna(subset=["col1", "col2"], how="all")
    

    例如:

    In [11]: df = pd.DataFrame([1, 2, np.inf, -np.inf])
    
    In [12]: df.replace([np.inf, -np.inf], np.nan, inplace=True)
    Out[12]:
        0
    0   1
    1   2
    2 NaN
    3 NaN
    

    同样的方法也适用于系列。

    【讨论】:

    • 如何在某个列中将inf 值“交换”为预定义的int,例如0
    • @3kstc 使用.replace(..., 0)。只对列执行更新这些列,即df[cols] = df[cols].replace(..., 0)
    • 也许值得指出 replace 不能在原地工作,因此返回一个新的 DataFrame
    【解决方案2】:

    使用选项上下文,无需永久设置use_inf_as_na 就可以做到这一点。例如:

    with pd.option_context('mode.use_inf_as_na', True):
        df = df.dropna(subset=['col1', 'col2'], how='all')
    

    当然可以用

    设置将inf永久视为NaN
    pd.set_option('use_inf_as_na', True)
    

    对于旧版本,将use_inf_as_na 替换为use_inf_as_null

    【讨论】:

    • 这是最易读的答案,因此是最好的,尽管它在字面上(但不是精神上)违反了原始问题。
    • Pandas(至少)0.24:use_inf_as_null 已被弃用,并将在未来的版本中删除。请改用use_inf_as_na。添加/更新答案?
    • 在全局设置级别而不是操作级别将inf 视为空值是一个更好的选择。这可能会节省先估算值的时间。
    【解决方案3】:

    使用(快速简单):

    df = df[np.isfinite(df).all(1)]
    

    此答案基于另一个问题中的DougR's answer。 这里是一个示例代码:

    import pandas as pd
    import numpy as np
    df=pd.DataFrame([1,2,3,np.nan,4,np.inf,5,-np.inf,6])
    print('Input:\n',df,sep='')
    df = df[np.isfinite(df).all(1)]
    print('\nDropped:\n',df,sep='')
    

    结果:

    Input:
        0
    0  1.0000
    1  2.0000
    2  3.0000
    3     NaN
    4  4.0000
    5     inf
    6  5.0000
    7    -inf
    8  6.0000
    
    Dropped:
         0
    0  1.0
    1  2.0
    2  3.0
    4  4.0
    6  5.0
    8  6.0
    

    【讨论】:

    • 我收到此错误 - TypeError: 输入类型不支持 ufunc 'isfinite',并且根据强制转换规则 ''safe'' 无法安全地将输入强制转换为任何支持的类型
    • 不是我的代码,我猜!?可能您尝试处理不受支持的类型(如字符串)的列
    【解决方案4】:

    这是另一种使用 .loc 将系列上的 inf 替换为 nan 的方法:

    s.loc[(~np.isfinite(s)) & s.notnull()] = np.nan
    

    所以,回答原来的问题:

    df = pd.DataFrame(np.ones((3, 3)), columns=list('ABC'))
    
    for i in range(3): 
        df.iat[i, i] = np.inf
    
    df
              A         B         C
    0       inf  1.000000  1.000000
    1  1.000000       inf  1.000000
    2  1.000000  1.000000       inf
    
    df.sum()
    A    inf
    B    inf
    C    inf
    dtype: float64
    
    df.apply(lambda s: s[np.isfinite(s)].dropna()).sum()
    A    2
    B    2
    C    2
    dtype: float64
    

    【讨论】:

      【解决方案5】:

      上述解决方案将修改不在目标列中的infs。为了解决这个问题,

      lst = [np.inf, -np.inf]
      to_replace = {v: lst for v in ['col1', 'col2']}
      df.replace(to_replace, np.nan)
      

      【讨论】:

      • python 2.7 及更高版本支持字典理解:{v: lst for v in cols}
      【解决方案6】:

      另一个解决方案是使用isin 方法。使用它来确定每个值是无限还是缺失,然后链接all 方法以确定行中的所有值是无限还是缺失。

      最后,使用该结果的否定通过布尔索引选择不具有所有无限或缺失值的行。

      all_inf_or_nan = df.isin([np.inf, -np.inf, np.nan]).all(axis='columns')
      df[~all_inf_or_nan]
      

      【讨论】:

        【解决方案7】:

        您可以将pd.DataFrame.masknp.isinf 一起使用。您应该首先确保您的数据框系列都是float 类型。然后将dropna 与您现有的逻辑一起使用。

        print(df)
        
               col1      col2
        0 -0.441406       inf
        1 -0.321105      -inf
        2 -0.412857  2.223047
        3 -0.356610  2.513048
        
        df = df.mask(np.isinf(df))
        
        print(df)
        
               col1      col2
        0 -0.441406       NaN
        1 -0.321105       NaN
        2 -0.412857  2.223047
        3 -0.356610  2.513048
        

        【讨论】:

          【解决方案8】:

          要使用单个命令同时删除 Naninf,请使用

          df = df[ np.isfinite( df ).all( axis = 1) ]
          

          如果由于某种原因上述方法对您不起作用,请尝试以下 2 个步骤:

          df = df[ ~( df.isnull().any( axis = 1 ) ) ] #to remove nan
          df = df[ ~( df.isin( [np.inf, -np.inf]).any(axis =1) )] #to remove inf
          

          【讨论】:

            【解决方案9】:

            偶然发现了这一行,我发现一行没有替换或numpy:

            df = pd.DataFrame(
                [[1, np.inf],
                 [1, -np.inf],
                 [1, 2]],
                columns=['a', 'b']
            )
            df.query("b not in [inf, -inf]")
            >>> a  b
             2  1  2.0
            

            对于某些版本的pandas,可能需要在列名b 周围使用后面的`

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2018-01-09
              • 1970-01-01
              • 1970-01-01
              • 2016-04-30
              • 1970-01-01
              • 2020-03-23
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多