【问题标题】:Selecting/excluding sets of columns in pandas [duplicate]选择/排除熊猫中的列集[重复]
【发布时间】:2013-02-03 03:29:57
【问题描述】:

我想根据列选择从现有数据框创建视图或数据框。

例如,我想从数据框 df1 创建一个数据框 df2,其中包含除其中两个之外的所有列。我尝试执行以下操作,但没有成功:

import numpy as np
import pandas as pd

# Create a dataframe with columns A,B,C and D
df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD'))

# Try to create a second dataframe df2 from df with all columns except 'B' and D
my_cols = set(df.columns)
my_cols.remove('B').remove('D')

# This returns an error ("unhashable type: set")
df2 = df[my_cols]

我做错了什么?也许更一般地说,pandas 有什么机制来支持从数据帧中选择和排除任意列集?

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    您只需将您的set 转换为list

    import pandas as pd
    df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD'))
    my_cols = set(df.columns)
    my_cols.remove('B')
    my_cols.remove('D')
    my_cols = list(my_cols)
    df2 = df[my_cols]
    

    【讨论】:

    • 谢谢!这工作得很好。只是想知道,Panda 中是否有任何功能可以促进这种类型(或更复杂的类型)列过滤的列规范?
    • @user273158 不知道,我刚开始学习Pandas我自己。
    • 也许使用drop?。 df.drop(my_cols, axis=1) 将生成带有已删除列的 DataFrame 视图。然后,您只需将其分配给新的 DF:df2 = df.drop(my_cols, axis=1)
    • 使用 [drop][1] 作为另一个问题的答案:stackoverflow.com/a/18145399/115237 [1]:pandas.pydata.org/pandas-docs/stable/generated/…
    【解决方案2】:

    你真的不需要把它转换成一个集合:

    cols = [col for col in df.columns if col not in ['B', 'D']]
    df2 = df[cols]
    

    【讨论】:

    • 我计时了,差异和[df.columns[~df.columns.isin['B','D']]。这个答案是最快的。谢谢。
    【解决方案3】:

    以下是创建DataFrame副本的方法,不包括列列表:

    df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD'))
    df2 = df.drop(['B', 'D'], axis=1)
    

    但要小心!您在问题中提到了观点,暗示如果您更改了df,您希望df2 也进行更改。 (就像数据库中的视图一样。)

    此方法无法实现:

    >>> df.loc[0, 'A'] = 999 # Change the first value in df
    >>> df.head(1)
         A         B         C         D
    0  999 -0.742688 -1.980673 -0.920133
    >>> df2.head(1) # df2 is unchanged. It's not a view, it's a copy!
              A         C
    0  0.251262 -1.980673
    

    还要注意@piggybox 的方法也是如此。 (虽然这种方法很好,很漂亮,而且 Pythonic。我不会这样做!!)

    有关视图与副本的更多信息,请参阅该答案所指的 this SO answerthis part of the Pandas docs

    【讨论】:

      【解决方案4】:

      还可以查看内置的DataFrame.filter 函数。

      简约但贪婪的方法(对于给定的df就足够了):

      df.filter(regex="[^BD]")
      

      保守/惰性方法(仅精确匹配):

      df.filter(regex="^(?!(B|D)$).*$")
      

      保守和通用:

      exclude_cols = ['B','C']
      df.filter(regex="^(?!({0})$).*$".format('|'.join(exclude_cols)))
      

      【讨论】:

      • 这种方式允许方法链接。
      • 这很适合选择列,但排除它们似乎很麻烦!
      【解决方案5】:

      您可以删除不需要的列或选择您需要的列

      # Using DataFrame.drop
      df.drop(df.columns[[1, 2]], axis=1, inplace=True)
      
      # drop by Name
      df1 = df1.drop(['B', 'C'], axis=1)
      
      # Select the ones you want
      df1 = df[['a','d']]
      

      【讨论】:

      • 有没有办法只选择n'th 列?即:df1 = my_df[[n]] 其中 nn 列数的最后一列,我正在尝试负索引 [[-1]]
      • @3kstc 你可以使用df1.iloc[:, [-1]] 这将选择所有行,最后一列。
      • 对列使用isin 怎么样?无需丢弃或循环。请参阅下面的答案。
      • 你也可以输入df.drop(columns=['B', 'C'])
      【解决方案6】:

      有一个名为difference 的新索引方法。它返回原始列,并删除作为参数传递的列。

      这里,结果用于从df 中删除列BD

      df2 = df[df.columns.difference(['B', 'D'])]
      

      注意,它是基于集合的方法,所以重复的列名会导致问题,并且列顺序可能会改变。


      优势优于drop:当您只需要列列表时,您无需创建整个数据框的副本。例如,为了在列的子集上删除重复项:

      # may create a copy of the dataframe
      subset = df.drop(['B', 'D'], axis=1).columns
      
      # does not create a copy the dataframe
      subset = df.columns.difference(['B', 'D'])
      
      df = df.drop_duplicates(subset=subset)
      

      【讨论】:

      • 不错。与df.drop(['B', 'D'], axis=1) 相比,这样做有优势/劣势吗?
      • 对我来说优势是代码可读性。我发现使用drop 来选择列违反直觉。
      • difference() 似乎也默认按字母顺序重新排列列
      • @slizb 好点,基于source code 看起来实际上并不能保证返回的索引的顺序,因为该方法使用集合。
      • 似乎 drop 方法稍微快一些(~515 µs vs ~680 µs),至少在我想删除 3 列的 15611 行 x 5 列数据帧的某些测试中, python 3.6 和熊猫 0.20.3。
      【解决方案7】:

      与此类似,在读取文件时,可能希望预先排除列,而不是浪费地将不需要的数据读入内存并随后丢弃它们。

      从 pandas 0.20.0 开始,usecols now accepts callables1此更新允许更灵活的选项来读取列:

      skipcols = [...]
      read_csv(..., usecols=lambda x: x not in skipcols)
      

      后一种模式本质上与传统的 usecols 方法相反 - 仅跳过指定的列。


      给定

      文件中的数据

      import numpy as np
      import pandas as pd
      
      
      df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD'))
      
      filename = "foo.csv"
      df.to_csv(filename)
      

      代码

      skipcols = ["B", "D"]
      df1 = pd.read_csv(filename, usecols=lambda x: x not in skipcols, index_col=0)
      df1
      

      输出

                A         C
      0  0.062350  0.076924
      1 -0.016872  1.091446
      2  0.213050  1.646109
      3 -1.196928  1.153497
      4 -0.628839 -0.856529
      ...
      

      详情

      DataFrame 已写入文件。然后将其作为单独的 DataFrame 读回,现在跳过不需要的列(BD)。

      请注意,对于 OP 的情况,由于已经创建了数据,因此更好的方法是接受的答案,即从现有对象中删除不需要的列。但是,这里介绍的技术在直接将文件中的数据读取到 DataFrame 时最有用。

      this issue 中提出了“skipcols”选项的请求,并在后来的issue 中得到解决。

      【讨论】:

      • 非常感谢!这正是我所需要的。
      【解决方案8】:

      您有 4 列 A、B、C、D

      这是为新数据框选择所需列的更好方法:-

      df2 = df1[['A','D']]
      

      如果您希望使用列号,请使用:-

      df2 = df1[[0,3]]
      

      【讨论】:

      • pandas 将列表和元组视为索引不同。所以df[('A', 'B')] != df[["A", "B"]] - 请注意df["A", "B"] == df[("A", "B")] 不确定我是粉丝....虽然关于实用程序是否证明这种疯狂有一个问题。
      【解决方案9】:

      另一种选择,无需在循环中丢弃或过滤:

      import numpy as np
      import pandas as pd
      
      # Create a dataframe with columns A,B,C and D
      df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD'))
      
      # include the columns you want
      df[df.columns[df.columns.isin(['A', 'B'])]]
      
      # or more simply include columns:
      df[['A', 'B']]
      
      # exclude columns you don't want
      df[df.columns[~df.columns.isin(['C','D'])]]
      
      # or even simpler since 0.24
      # with the caveat that it reorders columns alphabetically 
      df[df.columns.difference(['C', 'D'])]
      

      【讨论】:

      • 应该是答案
      • 不错。 list(df.columns).remove('C') 的失败让我抓狂。
      猜你喜欢
      • 2020-08-01
      • 2019-09-22
      • 2019-04-02
      • 2021-05-18
      • 1970-01-01
      • 1970-01-01
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多