关于python:选择/排除pandas 中的列集

Selecting/excluding sets of columns in pandas

本问题已经有最佳答案,请猛点这里访问。

我希望基于列选择从现有数据帧创建视图或数据帧。

例如,我想从一个数据帧df1创建一个数据帧df2,它保存了除其中两列以外的所有列。我试着做了以下工作,但没有成功:

1
2
3
4
5
6
7
8
9
10
11
12
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]

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


您可以删除不需要的列,也可以选择需要的列。

1
2
3
4
5
6
7
8
# 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']]


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

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

这里,输出用于从df中过滤列BD


您不需要将其转换为集合:

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

另一个选项,不在循环中删除或过滤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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'])]]

还可以查看内置的DataFrame.filter功能。

最小但贪婪的方法(对于给定的df足够):

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

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

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

保守和一般:

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


你只需要把你的set转换成list

1
2
3
4
5
6
7
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]


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

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

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

这种方法无法实现:

1
2
3
4
5
6
7
>>> 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的方法也是如此。(尽管这种方法很好,而且很巧妙,而且是Python式的。我不是在做下去!!)

有关视图和副本的更多信息,请参阅此答案和此答案所指的熊猫文档部分。


有4列A、B、C、D

以下是选择新数据帧所需列的更好方法:

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

如果要使用列号,请使用-

1
df2 = df1[[0,3]]

以类似的方式,在读取文件时,可能希望预先排除列,而不是浪费地将不需要的数据读取到内存中,然后丢弃它们。

从pandas 0.20.0开始,usecols现在接受可调用文件。1此更新允许更灵活的阅读列选项:

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

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

鉴于

文件中的数据

1
2
3
4
5
6
7
8
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)

代码

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

产量

1
2
3
4
5
6
7
          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
...

细节

数据帧被写入文件。然后它被作为一个单独的数据帧读回,现在跳过不需要的列(BD)。

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

a request was provided for a"skipcols"option in this issue and was addressed in a later issue.