【问题标题】:quickly drop dataframe columns with only one distinct value快速删除只有一个不同值的数据框列
【发布时间】:2016-01-13 16:35:54
【问题描述】:

有没有比下面的代码更快的方法来删除只包含一个不同值的列?

cols=df.columns.tolist()
for col in cols:
    if len(set(df[col].tolist()))<2:
        df=df.drop(col, axis=1)

这对于大型数据帧来说真的很慢。从逻辑上讲,这会计算每列中的值的数量,而实际上它可能会在达到 2 个不同的值后停止计数。

【问题讨论】:

标签: python pandas


【解决方案1】:

您可以使用Series.unique() 方法找出列中的所有唯一元素,对于.unique() 仅返回1 元素的列,您可以删除它。示例 -

for col in df.columns:
    if len(df[col].unique()) == 1:
        df.drop(col,inplace=True,axis=1)

一种不进行就地删除的方法 -

res = df
for col in df.columns:
    if len(df[col].unique()) == 1:
        res = res.drop(col,axis=1)

演示 -

In [154]: df = pd.DataFrame([[1,2,3],[1,3,3],[1,2,3]])

In [155]: for col in df.columns:
   .....:     if len(df[col].unique()) == 1:
   .....:         df.drop(col,inplace=True,axis=1)
   .....:

In [156]: df
Out[156]:
   1
0  2
1  3
2  2

计时结果-

In [166]: %paste
def func1(df):
        res = df
        for col in df.columns:
                if len(df[col].unique()) == 1:
                        res = res.drop(col,axis=1)
        return res

## -- End pasted text --

In [172]: df = pd.DataFrame({'a':1, 'b':np.arange(5), 'c':[0,0,2,2,2]})

In [178]: %timeit func1(df)
1000 loops, best of 3: 1.05 ms per loop

In [180]: %timeit df[df.apply(pd.Series.value_counts).dropna(thresh=2, axis=1).columns]
100 loops, best of 3: 8.81 ms per loop

In [181]: %timeit df.apply(pd.Series.value_counts).dropna(thresh=2, axis=1)
100 loops, best of 3: 5.81 ms per loop

最快的方法似乎仍然是使用unique 并循环遍历列的方法。

【讨论】:

【解决方案2】:

一步:

df = df[[c for c
        in list(df)
        if len(df[c].unique()) > 1]]

两步:

创建具有多个不同值的列名列表。

keep = [c for c
        in list(df)
        if len(df[c].unique()) > 1]

删除不在'keep'中的列

df = df[keep]

注意:此步骤也可以使用要删除的列列表来完成:

drop_cols = [c for c
             in list(df)
             if df[c].nunique() <= 1]
df = df.drop(columns=drop_cols)

【讨论】:

  • 有没有办法查看“两步”示例,而不是存储到列表变量以保留存储变量。获取已删除的变量列表将很有用。
【解决方案3】:
df.loc[:,df.apply(pd.Series.nunique) != 1]

例如

In:
df = pd.DataFrame({'A': [10, 20, np.nan, 30], 'B': [10, np.nan, 10, 10]})
df.loc[:,df.apply(pd.Series.nunique) != 1]

Out:
   A
0  10
1  20
2  NaN
3  30

【讨论】:

  • 在我的示例中处理不正确 var4var6: ``` import pandas as pd import numpy as np data = {'var1': [1,2,3,4,5, np.nan,7,8,9],'var2':['Order',np.nan,'Inv','Order','Order','Shp','Order','Order','Inv '], 'var3':[101,101,101,102,102,102,103,103,np.nan], 'var4':[np.nan,1,1,1,1,1,1,1,1], 'var5':[1,1, 1,1,1,1,1,1,1], 'var6':[np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np. nan,np.nan], 'var7': [1,2,3,4,5,6,7,8,9]} df = pd.DataFrame(data) df5 = df.loc[:,df.apply (pd.Series.nunique)!= 1]```
  • @vasili111 因为np.nan !=np.nan 为真。
【解决方案4】:

两个简单的单行代码,用于返回视图(jz0410 答案的较短版本)

df.loc[:,df.nunique()!=1]

或就地放置(通过drop()

df.drop(columns=df.columns[df.nunique()==1], inplace=True)

【讨论】:

    【解决方案5】:

    您可以通过调用apply 和调用value_counts 创建您的df 的掩码,这将为除一行之外的所有行生成NaN,然后您可以按列调用dropna 并传递参数thresh=2所以必须有 2 个或更多非NaN 值:

    In [329]:   
    df = pd.DataFrame({'a':1, 'b':np.arange(5), 'c':[0,0,2,2,2]})
    df
    
    Out[329]:
       a  b  c
    0  1  0  0
    1  1  1  0
    2  1  2  2
    3  1  3  2
    4  1  4  2
    
    In [342]:
    df[df.apply(pd.Series.value_counts).dropna(thresh=2, axis=1).columns]
    
    Out[342]:
       b  c
    0  0  0
    1  1  0
    2  2  2
    3  3  2
    4  4  2
    

    布尔条件的输出:

    In [344]:
    df.apply(pd.Series.value_counts)
    
    Out[344]:
        a  b   c
    0 NaN  1   2
    1   5  1 NaN
    2 NaN  1   3
    3 NaN  1 NaN
    4 NaN  1 NaN
    
    In [345]:
    df.apply(pd.Series.value_counts).dropna(thresh=2, axis=1)
    
    Out[345]:
       b   c
    0  1   2
    1  1 NaN
    2  1   3
    3  1 NaN
    4  1 NaN
    

    【讨论】:

      【解决方案6】:

      我想加入: 熊猫 1.0.3

      ids = df.nunique().values>1
      df.loc[:,ids]
      

      没那么慢:

      2.81 ms ± 115 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
      

      【讨论】:

        【解决方案7】:
        df=df.loc[:,df.nunique()!=Numberofvalues]
        

        【讨论】:

          【解决方案8】:

          没有一个解决方案在我的用例中起作用,因为我收到了这个错误:(我的数据框包含列表项)。

          TypeError: unhashable type: 'list'

          对我有用的解决方案是:

          ndf = df.describe(include="all").T
          new_cols = set(df.columns) - set(ndf[ndf.unique == 1].index)
          df = df[list(new_cols)]  
          

          【讨论】:

          • 不适用于我的示例:data = {'var1': [1,2,3,4,5,np.nan,7,8,9], 'var2':['Order',np.nan,'Inv','Order','Order','Shp','Order', 'Order','Inv'], 'var3':[101,101,101,102,102,102,103,103,np.nan], 'var4':[np.nan,1,1,1,1,1,1,1,1], 'var5':[1,1,1,1,1,1,1,1,1], 'var6':[np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan], 'var7': [1,2,3,4,5,6,7,8,9]} df = pd.DataFrame(data) df2 = df[df.apply(pd.Series.value_counts).dropna(thresh=2, axis=1).columns]
          【解决方案9】:

          线程和this thread 中的许多示例不适用于我的df。那些工作:

          # from: https://stackoverflow.com/questions/33144813/quickly-drop-dataframe-columns-with-only-one-distinct-value
          # from: https://stackoverflow.com/questions/20209600/pandas-dataframe-remove-constant-column
          
          import pandas as pd
          import numpy as np
          
          
          data = {'var1': [1,2,3,4,5,np.nan,7,8,9],
                 'var2':['Order',np.nan,'Inv','Order','Order','Shp','Order', 'Order','Inv'],
                 'var3':[101,101,101,102,102,102,103,103,np.nan], 
                 'var4':[np.nan,1,1,1,1,1,1,1,1],
                 'var5':[1,1,1,1,1,1,1,1,1],
                 'var6':[np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan],
                 'var7':["a","a","a","a","a","a","a","a","a"],
                 'var8': [1,2,3,4,5,6,7,8,9]}
          
          
          df = pd.DataFrame(data)
          df_original = df.copy()
          
          
          
          #-------------------------------------------------------------------------------------------------
          
          
          df2 = df[[c for c
                  in list(df)
                  if len(df[c].unique()) > 1]]
          
          
          #-------------------------------------------------------------------------------------------------
          
          
          keep = [c for c
                  in list(df)
                  if len(df[c].unique()) > 1]
          
          df3 = df[keep]
          
          
          
          #-------------------------------------------------------------------------------------------------
          
          
          
          keep_columns = [col for col in df.columns if len(df[col].unique()) > 1]
          
          df5 = df[keep_columns].copy()
          
          
          
          #-------------------------------------------------------------------------------------------------
          
          
          
          for col in df.columns:
               if len(df[col].unique()) == 1:
                   df.drop(col,inplace=True,axis=1)
          

          【讨论】:

            【解决方案10】:

            一行

            df=df[[i for i in df if len(set(df[i]))>1]]
            

            【讨论】:

              【解决方案11】:

              pipe 的一种解决方案(如果经常使用的话很方便):

              def drop_unique_value_col(df):
                  return df.loc[:,df.apply(pd.Series.nunique) != 1]
              
              df.pipe(drop_unique_value_col)
              

              【讨论】:

                【解决方案12】:

                这将删除所有只有一个不同值的列。

                for col in Dataframe.columns:
                    
                    if len(Dataframe[col].value_counts()) == 1:
                
                        Dataframe.drop([col], axis=1, inplace=True)
                

                【讨论】:

                  【解决方案13】:

                  我能找到的大多数“pythonic”方式:

                  df = df.loc[:, (df != df.iloc[0]).any()]
                  

                  【讨论】:

                  • 虽然这可能会回答问题,但请说明如何您的解决方案解决了问题,以使答案对未来的读者更有价值。
                  • 不适用于我的示例:` import pandas as pd import numpy as np data = {'var1': [1,2,3,4,5,np.nan,7,8, 9],'var2':['Order',np.nan,'Inv','Order','Order','Shp','Order','Order','Inv'],'var3':[ 101,101,101,102,102,102,103,103,np.nan], 'var4':[np.nan,1,1,1,1,1,1,1,1], 'var5':[1,1,1,1,1,1, 1,1,1], 'var6':[np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan], ' var7': [1,2,3,4,5,6,7,8,9]} df = pd.DataFrame(data) df2 = df.loc[:, (df != df.iloc[0]) .any()]`
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-01-13
                  • 2023-03-22
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多