【问题标题】:pandas dataframe remove constant column熊猫数据框删除常量列
【发布时间】:2013-11-26 05:59:18
【问题描述】:

我有一个数据框,它可能有也可能没有相同值的列。例如

    row    A    B
    1      9    0
    2      7    0
    3      5    0
    4      2    0

我只想回来

   row    A  
   1      9    
   2      7    
   3      5    
   4      2

有没有一种简单的方法来识别这些列是否存在然后删除它们?

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    我相信这个选项会比这里的其他答案更快,因为它只会遍历数据帧一次进行比较,如果找到非唯一值则短路。

    >>> df
    
       0  1  2
    0  1  9  0
    1  2  7  0
    2  3  7  0
    
    >>> df.loc[:, (df != df.iloc[0]).any()] 
    
       0  1
    0  1  9
    1  2  7
    2  3  7
    

    【讨论】:

    • +1 感谢您的更改。在已经对每个元素进行了 != 比较之后,任何东西上的短路,所以 DSM 的解决方案可能会更有效......想知道是否有更好的短路解决方案。
    • 在我的测试中,我的解决方案总是比计算唯一元素要快,尽管这个因子从 10×10 DataFrame 的 0.1 到 10000×10 的大约 0.5 不等。我认为通过不计算完整的相等数组节省的内存可以与计算所有唯一值(以及维护已经看到的值的表等)所涉及的额外时间进行权衡。
    • 好点,收回效率更高!仍然想知道是否可以在看到第一个差异之后将 != 短路。
    • 请注意,带有 NaN 的列不会被视为常量。这在技术上是正确的(因为 NaN ≠ Nan),但这可能不是我们想要的(因为每个 NaN 之间没有实际差异)。
    • 我有一列是时间戳,我得到TypeError: int() argument must be a string, a bytes-like object or a number, not 'Timestamp' 不明白为什么。
    【解决方案2】:

    像往常一样忽略NaNs,如果nunique() == 1,列是常量。所以:

    >>> df
       A  B  row
    0  9  0    1
    1  7  0    2
    2  5  0    3
    3  2  0    4
    >>> df = df.loc[:,df.apply(pd.Series.nunique) != 1]
    >>> df
       A  row
    0  9    1
    1  7    2
    2  5    3
    3  2    4
    

    【讨论】:

    • df.apply(pd.Series.nunique) 更简单的是 df.nunique(),至少在 Pandas 0.20.3 中。
    • 如果我们希望 NaN 被视为一个唯一值,df.nunique(dropna=False) 效果很好(它处理了 NaN ≠ NaN 的事实,正如我们所期望的那样,将所有 NaN 值计算为相同的值,即使它们不相等)。
    【解决方案3】:

    我在大小为 120*10000 的数据帧上比较了各种方法。并发现有效的是

    def drop_constant_column(dataframe):
        """
        Drops constant value columns of pandas dataframe.
        """
        return dataframe.loc[:, (dataframe != dataframe.iloc[0]).any()]
    

    1 个循环,3 个循环中的最佳值:每个循环 237 毫秒

    其他竞争者是

    def drop_constant_columns(dataframe):
        """
        Drops constant value columns of pandas dataframe.
        """
        result = dataframe.copy()
        for column in dataframe.columns:
            if len(dataframe[column].unique()) == 1:
                result = result.drop(column,axis=1)
        return result
    

    1 次循环,3 次取胜:每个循环 19.2 秒

    def drop_constant_columns_2(dataframe):
        """
        Drops constant value columns of pandas dataframe.
        """
        for column in dataframe.columns:
            if len(dataframe[column].unique()) == 1:
                dataframe.drop(column,inplace=True,axis=1)
        return dataframe
    

    1 个循环,3 次取胜:每个循环 317 毫秒

    def drop_constant_columns_3(dataframe):
        """
        Drops constant value columns of pandas dataframe.
        """
        keep_columns = [col for col in dataframe.columns if len(dataframe[col].unique()) > 1]
        return dataframe[keep_columns].copy()
    

    1 个循环,3 个循环中的最佳值:每个循环 358 毫秒

    def drop_constant_columns_4(dataframe):
        """
        Drops constant value columns of pandas dataframe.
        """
        keep_columns = dataframe.columns[dataframe.nunique()>1]
        return dataframe.loc[:,keep_columns].copy()
    

    1 次循环,3 次取胜:每个循环 1.8 秒

    【讨论】:

    • 使用 len(df.col.unique()) 非常昂贵。一个简单的 df.col.nunique() 将给出相同的结果,但开销显着减少。
    【解决方案4】:

    假设 DataFrame 完全是数字类型:

    你可以试试:

    >>> df = df.loc[:, df.var() == 0.0]
    

    这将删除常量(即方差 = 0)列。

    如果 DataFrame 既是数字类型又是对象类型,那么你应该尝试:

    >>> enum_df = df.select_dtypes(include=['object'])
    >>> num_df = df.select_dtypes(exclude=['object'])
    >>> num_df = num_df.loc[:, num_df.var() == 0.0]
    >>> df = pd.concat([num_df, enum_df], axis=1)
    

    这将只删除数字类型的常量列。

    如果您还想忽略/删除常量枚举列,您应该尝试:

    >>> enum_df = df.select_dtypes(include=['object'])
    >>> num_df = df.select_dtypes(exclude=['object'])
    >>> enum_df = enum_df.loc[:, [True if y !=1 else False for y in [len(np.unique(x, return_counts=True)[-1]) for x in enum_df.T.as_matrix()]]]
    >>> num_df = num_df.loc[:, num_df.var() == 0.0]
    >>> df = pd.concat([num_df, enum_df], axis=1)
    

    【讨论】:

    • 大概你会想要df = df.loc[:, ~df.var() == 0.0],否则你会选择0列。对于可能的浮点错误,np.isclose(0, df.var()) 可能也值得做
    【解决方案5】:

    这是我的解决方案,因为我需要同时处理对象列和数值列。没有声称它的超级高效或任何东西,但它完成了工作。

    def drop_constants(df):
        """iterate through columns and remove columns with constant values (all same)"""
        columns = df.columns.values
        for col in columns:
            # drop col if unique values is 1
            if df[col].nunique(dropna=False) == 1:
                del df[col]
        return df
    

    额外的警告,它不适用于列表或数组的列,因为它们不可散列。

    【讨论】:

      【解决方案6】:

      此线程中的许多示例无法正常工作。检查 this my answer 并收集有效的示例

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-05-28
        • 2018-02-24
        • 2018-01-09
        • 2020-07-26
        • 2018-03-15
        • 2016-08-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多