从 Pandas DataFrame 中删除列

Delete a column from a Pandas DataFrame

提问人:John 提问时间:11/16/2012 最后编辑:cottontailJohn 更新时间:8/19/2023 访问量:3975175

问:

要删除 DataFrame 中的列,我可以成功使用:

del df['column_name']

但是为什么我不能使用以下内容呢?

del df.column_name

由于可以通过 访问该系列,我希望这能起作用。df.column_name

Python Pandas 数据帧

评论


答:

38赞 Andy Hayden 11/16/2012 #1

最好始终使用表示法。原因之一是属性表示法 () 不适用于编号索引:[]df.column_name

In [1]: df = DataFrame([[1, 2, 3], [4, 5, 6]])

In [2]: df[1]
Out[2]:
0    2
1    5
Name: 1

In [3]: df.1
  File "<ipython-input-3-e4803c0d1066>", line 1
    df.1
       ^
SyntaxError: invalid syntax
1307赞 Wes McKinney 11/21/2012 #2

正如你所猜到的,正确的语法是

del df['column_name']

仅仅因为 Python 中的语法限制,很难使工作变得困难。 被 Python 翻译成 under the covers。del df.column_namedel df[name]df.__delitem__(name)

评论

35赞 dwanderson 10/4/2016
我意识到这是一个超级古老的“答案”,但我的好奇心被激起了——为什么这是 Python 的语法限制? 设置一个类,然后工作正常......class A(object): def __init__(self): self.var = 1a = A(); del a.var
25赞 Yonatan 12/22/2016
@dwanderson区别在于,当要删除列时,DataFrame 需要有自己的处理“如何执行”。在 的情况下,它被转换为 DataFrame 可以实现和修改其需要的方法。在 的情况下,成员变量将被删除,而没有任何自定义代码运行的机会。考虑你自己的例子 - 你能得到“删除变量”的打印吗?如果可以的话,请告诉我怎么做。我不能:)del df[name]df.__delitem__(name)del df.namedel a.var
12赞 Eugene Pakhomov 1/20/2017
@Yonatan 您可以使用 docs.python.org/3/reference/datamodel.html#object.__delattr__ 或描述符:docs.python.org/3/howto/descriptor.html
6赞 C S 6/20/2017
@Yonatan Eugene 的评论也适用于 Python 2;描述符自 2.2 以来一直存在于 Python 2 中,满足您的要求是微不足道的;)
7赞 wizzwizz4 9/30/2017
这个答案并不完全正确——开发人员没有,但这并不意味着它很难做到。pandas
3541赞 LondonRob 8/9/2013 #3

在 Pandas 中执行此操作的最佳方法是使用 drop

df = df.drop('column_name', axis=1)

其中 是号(表示行和列。101

或者,该方法接受 / 关键字作为指定轴的替代方法。所以我们现在可以做:drop()indexcolumns

df = df.drop(columns=['column_nameA', 'column_nameB'])
  • 这是在 v0.21.0(2017 年 10 月 27 日)中引入的

若要删除列而不必重新分配,可以执行以下操作:df

df.drop('column_name', axis=1, inplace=True)

最后,要按列而不是按列标签删除,请尝试删除,例如第 1、2 和 4 列:

df = df.drop(df.columns[[0, 1, 3]], axis=1)  # df.columns is zero-based pd.Index

此外,还使用列的“文本”语法:

df.drop(['column_nameA', 'column_nameB'], axis=1, inplace=True)

评论

111赞 beardc 12/11/2013
出于某种原因,这是否建议结束?del
35赞 Paul 5/28/2014
尽管这种删除方法有其优点,但这个答案并不能真正回答所提出的问题。
164赞 LondonRob 5/29/2014
没错@Paul,但由于问题的标题,大多数到达这里的人都会通过尝试弄清楚如何删除列来做到这一点。
40赞 hobs 4/15/2016
@beardc over 的另一个优点是允许您一次删除多个列,是否就地执行操作,还可以沿任何轴删除记录(对于 3-D 矩阵或dropdeldropPanel)
24赞 modulitos 8/12/2016
over 的另一个优点是 drop 是 pandas API 的一部分,包含文档。dropdel
314赞 Krishna Sankar 3/24/2014 #4

用:

columns = ['Col1', 'Col2', ...]
df.drop(columns, inplace=True, axis=1)

这将就地删除一列或多列。请注意,这是在 pandas v0.13 中添加的,不适用于旧版本。在这种情况下,您必须重新分配结果:inplace=True

df = df.drop(columns, axis=1)
156赞 jezrael 7/15/2015 #5

按索引删除

删除第一列、第二列和第四列:

df.drop(df.columns[[0,1,3]], axis=1, inplace=True)

删除第一列:

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

有一个可选参数,使原来 可以在不创建副本的情况下修改数据。inplace

弹出

列选择、添加、删除

删除列:column-name

df.pop('column-name')

例子:

df = DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6]), ('C', [7,8, 9])], orient='index', columns=['one', 'two', 'three'])

print df:

   one  two  three
A    1    2      3
B    4    5      6
C    7    8      9

df.drop(df.columns[[0]], axis=1, inplace=True) print df:

   two  three
A    2      3
B    5      6
C    8      9

three = df.pop('three') print df:

   two
A    2
B    5
C    8
72赞 eiTan LaVi 1/3/2016 #6

一个很好的补充是仅当列存在时才删除列。这样,您可以涵盖更多用例,并且它只会从传递给它的标签中删除现有列:

例如,只需添加 errors='ignore'

df.drop(['col_name_1', 'col_name_2', ..., 'col_name_N'], inplace=True, axis=1, errors='ignore')
  • 这是从 pandas 0.16.1 开始的新功能。文档在这里。
28赞 Alexander 2/14/2016 #7

在 Pandas 0.16.1+ 中,只有根据 eiTan LaVi 发布的解决方案存在列,您才能删除列。在该版本之前,您可以通过条件列表推导式获得相同的结果:

df.drop([col for col in ['col_name_1','col_name_2',...,'col_name_N'] if col in df],
        axis=1, inplace=True)
3赞 Doctor 4/20/2016 #8

点语法在 JavaScript 中有效,但在 Python 中无效。

  • 蟒:del df['column_name']
  • JavaScript:del df['column_name'] del df.column_name
49赞 sushmit 5/1/2016 #9

从版本 0.16.1 开始,您可以执行

df.drop(['column_name'], axis = 1, inplace = True, errors = 'ignore')

评论

4赞 muon 10/22/2016
这也支持删除多个列,其中一些不需要存在(即不会引发错误),如果这样的应用程序需要的话!errors= 'ignore'df.drop(['column_1','column_2'], axis=1 , inplace=True,errors= 'ignore')
100赞 firelynx 5/3/2016 #10

这里提出的大多数答案遗漏的实际问题是:

为什么我不能使用?del df.column_name

首先,我们需要了解问题,这需要我们深入研究 Python 的魔术方法

正如 Wes 在他的回答中指出的那样,映射到 Pandas 中实现的 Python 魔术方法,以删除列。del df['column']df.__delitem__('column')

但是,正如上面关于 Python 魔术方法的链接中所指出的:

事实上,由于调用它的不稳定环境,几乎永远不应该使用;请谨慎使用!__del__

你可以争辩说,这不应该被使用或鼓励,因此甚至不应该被考虑。del df['column_name']del df.column_name

然而,从理论上讲,可以使用魔术方法__delattr__在熊猫中工作。然而,这确实引入了某些问题,即实现中已经存在的问题,但程度较小。del df.column_namedel df['column_name']

示例问题

如果我在数据帧中定义一个名为“dtypes”或“columns”的列,该怎么办?

然后假设我想删除这些列。

del df.dtypes会使方法混淆,就好像它应该删除“dtypes”属性或“dtypes”列一样。__delattr__

此问题背后的架构问题

  1. 数据帧是的集合吗?
  2. 数据帧是的集合吗?
  3. 列是 DataFrame 的属性吗?

熊猫回答:

  1. 是的,在各个方面
  2. 不可以,但如果你愿意,你可以使用 , 或 方法。.ix.loc.iloc
  3. 也许,你想读取数据吗?然后是除非属性的名称已被属于 DataFrame 的另一个属性占用。是否要修改数据?那就不行了。

顶级域名;

你不能这样做,因为 Pandas 有一个相当疯狂的架构,需要重新考虑,以免这种认知失调发生在其用户身上。del df.column_name

专业提示:

不要使用df.column_name。它可能很漂亮,但它会导致认知失调

Zen of Python 的名言适合这里:

有多种方法可以删除列。

应该有一种——最好只有一种——显而易见的方法来做到这一点。

列有时是属性,但有时不是。

特殊情况还不足以打破规则。

是否删除 dtypes 属性或 dtypes 列?del df.dtypes

面对暧昧,拒绝猜测的诱惑。

评论

2赞 pauljohn32 7/21/2021
实际上解决了原始问题的 WHY 部分。我已经实现了 pandas 数据帧的子类。这样做会教你这个答案的重要部分。区分属性和列名是一个大问题。df.a 留下了歧义,无论 a 是属性还是列名。但是,由于 pandas 是这样写的,df[“a”] 只能是一列。
1赞 Joooeey 1/24/2023
这是涵盖所有基本方面的原始问题的唯一答案!
21赞 piRSquared 9/20/2017 #11

TL的;博士

为了找到一个稍微更有效的解决方案,我们付出了很多努力。很难证明增加的复杂性是合理的,同时牺牲了df.drop(dlst, 1, errors='ignore')

df.reindex_axis(np.setdiff1d(df.columns.values, dlst), 1)

前导码
删除一列在语义上与选择其他列相同。我将展示一些其他要考虑的方法。

我还将重点介绍一次删除多个列并允许尝试删除不存在的列的一般解决方案。

使用这些解决方案是通用的,也适用于简单情况。


设置
考虑要删除的 和 列表
pd.DataFramedfdlst

df = pd.DataFrame(dict(zip('ABCDEFGHIJ', range(1, 11))), range(3))
dlst = list('HIJKLM')

df

   A  B  C  D  E  F  G  H  I   J
0  1  2  3  4  5  6  7  8  9  10
1  1  2  3  4  5  6  7  8  9  10
2  1  2  3  4  5  6  7  8  9  10

dlst

['H', 'I', 'J', 'K', 'L', 'M']

结果应如下所示:

df.drop(dlst, 1, errors='ignore')

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

由于我将删除一列等同于选择其他列,因此我将它分为两种类型:

  1. 标签选择
  2. 布尔选择

标签选择

我们首先制造标签列表/数组,这些标签表示我们要保留的列,而没有要删除的列。

  1. df.columns.difference(dlst)

    Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
    
  2. np.setdiff1d(df.columns.values, dlst)

    array(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype=object)
    
  3. df.columns.drop(dlst, errors='ignore')

    Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
    
  4. list(set(df.columns.values.tolist()).difference(dlst))

    # does not preserve order
    ['E', 'D', 'B', 'F', 'G', 'A', 'C']
    
  5. [x for x in df.columns.values.tolist() if x not in dlst]

    ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    

标签中的列
为了比较选择过程,假设:

 cols = [x for x in df.columns.values.tolist() if x not in dlst]

然后我们可以评估

  1. df.loc[:, cols]
  2. df[cols]
  3. df.reindex(columns=cols)
  4. df.reindex_axis(cols, 1)

所有评估结果为:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

布尔切片

我们可以构造一个用于切片的布尔数组/列表

  1. ~df.columns.isin(dlst)
  2. ~np.in1d(df.columns.values, dlst)
  3. [x not in dlst for x in df.columns.values.tolist()]
  4. (df.columns.values[:, None] != dlst).all(1)

布尔值
中的列 为了比较起见

bools = [x not in dlst for x in df.columns.values.tolist()]
  1. df.loc[: bools]

所有评估结果为:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

稳健的时序

功能

setdiff1d = lambda df, dlst: np.setdiff1d(df.columns.values, dlst)
difference = lambda df, dlst: df.columns.difference(dlst)
columndrop = lambda df, dlst: df.columns.drop(dlst, errors='ignore')
setdifflst = lambda df, dlst: list(set(df.columns.values.tolist()).difference(dlst))
comprehension = lambda df, dlst: [x for x in df.columns.values.tolist() if x not in dlst]

loc = lambda df, cols: df.loc[:, cols]
slc = lambda df, cols: df[cols]
ridx = lambda df, cols: df.reindex(columns=cols)
ridxa = lambda df, cols: df.reindex_axis(cols, 1)

isin = lambda df, dlst: ~df.columns.isin(dlst)
in1d = lambda df, dlst: ~np.in1d(df.columns.values, dlst)
comp = lambda df, dlst: [x not in dlst for x in df.columns.values.tolist()]
brod = lambda df, dlst: (df.columns.values[:, None] != dlst).all(1)

测试

res1 = pd.DataFrame(
    index=pd.MultiIndex.from_product([
        'loc slc ridx ridxa'.split(),
        'setdiff1d difference columndrop setdifflst comprehension'.split(),
    ], names=['Select', 'Label']),
    columns=[10, 30, 100, 300, 1000],
    dtype=float
)

res2 = pd.DataFrame(
    index=pd.MultiIndex.from_product([
        'loc'.split(),
        'isin in1d comp brod'.split(),
    ], names=['Select', 'Label']),
    columns=[10, 30, 100, 300, 1000],
    dtype=float
)

res = res1.append(res2).sort_index()

dres = pd.Series(index=res.columns, name='drop')

for j in res.columns:
    dlst = list(range(j))
    cols = list(range(j // 2, j + j // 2))
    d = pd.DataFrame(1, range(10), cols)
    dres.at[j] = timeit('d.drop(dlst, 1, errors="ignore")', 'from __main__ import d, dlst', number=100)
    for s, l in res.index:
        stmt = '{}(d, {}(d, dlst))'.format(s, l)
        setp = 'from __main__ import d, dlst, {}, {}'.format(s, l)
        res.at[(s, l), j] = timeit(stmt, setp, number=100)

rs = res / dres

rs

                          10        30        100       300        1000
Select Label                                                           
loc    brod           0.747373  0.861979  0.891144  1.284235   3.872157
       columndrop     1.193983  1.292843  1.396841  1.484429   1.335733
       comp           0.802036  0.732326  1.149397  3.473283  25.565922
       comprehension  1.463503  1.568395  1.866441  4.421639  26.552276
       difference     1.413010  1.460863  1.587594  1.568571   1.569735
       in1d           0.818502  0.844374  0.994093  1.042360   1.076255
       isin           1.008874  0.879706  1.021712  1.001119   0.964327
       setdiff1d      1.352828  1.274061  1.483380  1.459986   1.466575
       setdifflst     1.233332  1.444521  1.714199  1.797241   1.876425
ridx   columndrop     0.903013  0.832814  0.949234  0.976366   0.982888
       comprehension  0.777445  0.827151  1.108028  3.473164  25.528879
       difference     1.086859  1.081396  1.293132  1.173044   1.237613
       setdiff1d      0.946009  0.873169  0.900185  0.908194   1.036124
       setdifflst     0.732964  0.823218  0.819748  0.990315   1.050910
ridxa  columndrop     0.835254  0.774701  0.907105  0.908006   0.932754
       comprehension  0.697749  0.762556  1.215225  3.510226  25.041832
       difference     1.055099  1.010208  1.122005  1.119575   1.383065
       setdiff1d      0.760716  0.725386  0.849949  0.879425   0.946460
       setdifflst     0.710008  0.668108  0.778060  0.871766   0.939537
slc    columndrop     1.268191  1.521264  2.646687  1.919423   1.981091
       comprehension  0.856893  0.870365  1.290730  3.564219  26.208937
       difference     1.470095  1.747211  2.886581  2.254690   2.050536
       setdiff1d      1.098427  1.133476  1.466029  2.045965   3.123452
       setdifflst     0.833700  0.846652  1.013061  1.110352   1.287831

fig, axes = plt.subplots(2, 2, figsize=(8, 6), sharey=True)
for i, (n, g) in enumerate([(n, g.xs(n)) for n, g in rs.groupby('Select')]):
    ax = axes[i // 2, i % 2]
    g.plot.bar(ax=ax, title=n)
    ax.legend_.remove()
fig.tight_layout()

这与运行所需的时间有关。似乎经过所有这些努力,我们只是适度地提高了性能。df.drop(dlst, 1, errors='ignore')

enter image description here

如果事实上最好的解决方案使用或黑客.紧随其后,仍然比现在好一点。reindexreindex_axislist(set(df.columns.values.tolist()).difference(dlst))dropnp.setdiff1d

rs.idxmin().pipe(
    lambda x: pd.DataFrame(
        dict(idx=x.values, val=rs.lookup(x.values, x.index)),
        x.index
    )
)

                      idx       val
10     (ridx, setdifflst)  0.653431
30    (ridxa, setdifflst)  0.746143
100   (ridxa, setdifflst)  0.816207
300    (ridx, setdifflst)  0.780157
1000  (ridxa, setdifflst)  0.861622
32赞 Ted Petrou 10/24/2017 #12

熊猫 0.21+ 个回答

Pandas 版本 0.21 略微更改了 drop 方法,以包含 and 参数以匹配 and 方法的签名。indexcolumnsrenamereindex

df.drop(columns=['column_a', 'column_c'])

就我个人而言,我更喜欢使用该参数来表示列或索引,因为它是几乎所有 pandas 方法中使用的主要关键字参数。但是,现在您在 0.21 版本中增加了一些选择。axis

3赞 Daksh Gupta 9/9/2018 #13

删除 Pandas DataFrame 中列的另一种方法

如果您不想就删除,则可以通过使用 function 指定列来创建新的 DataFrame:DataFrame(...)

my_dict = { 'name' : ['a','b','c','d'], 'age' : [10,20,25,22], 'designation' : ['CEO', 'VP', 'MD', 'CEO']}

df = pd.DataFrame(my_dict)

创建一个新的 DataFrame 作为

newdf = pd.DataFrame(df, columns=['name', 'age'])

你得到的结果与你得到的一样好 del / drop.

评论

1赞 cs95 5/24/2019
这在技术上是正确的,但必须列出要保留的每一列,而不仅仅是要删除的一列(或几列),这似乎很愚蠢。
6赞 ccpizza 3/16/2020 #14

如果你的原始数据帧 df 不是太大,你没有内存限制,你只需要保留几列,或者,如果你事先不知道所有不需要的额外列的名称,那么你不妨创建一个新的 DataFrame,只包含你需要的列:

new_df = df[['spam', 'sausage']]
16赞 Littin Rajan 4/19/2020 #15

我们可以通过 drop() 方法移除删除指定的列或指定的列。

假设 df 是一个数据帧。

要删除的列 = column0

法典:

df = df.drop(column0, axis=1)

要删除多个列 col1、col2、. . . . 、 coln,我们必须在列表中插入所有需要删除的列。然后通过 drop() 方法删除它们。

法典:

df = df.drop([col1, col2, . . . , coln], axis=1)
26赞 Praveen Bushipaka 10/16/2020 #16

用:

df.drop('columnname', axis =1, inplace = True)

或者你可以和

del df['colname']

根据列号删除多个列

df.drop(df.iloc[:,1:3], axis = 1, inplace = True)

根据列名删除多个列

df.drop(['col1','col2',..'coln'], axis = 1, inplace = True)
5赞 S Habeeb Ullah 11/15/2020 #17

使用 和 的函数删除列,当我们有一个带有不需要的值的典型列名时:ilocdataframeslicing

df = df.iloc[:,1:] # Removing an unnamed index column

这是默认行,是第一列,因此是我们删除第一列的参数。01:,1:

0赞 Mykola Zotko 10/6/2021 #18

若要删除特定列之前和之后的列,可以使用截断方法。例如:

   A   B    C     D      E
0  1  10  100  1000  10000
1  2  20  200  2000  20000

df.truncate(before='B', after='D', axis=1)

输出:

    B    C     D
0  10  100  1000
1  20  200  2000
0赞 creanion 11/10/2021 #19

从一般的 Python 角度来看,如果可以删除该属性,则有意义。它必须是常规属性,或者是具有已定义删除程序的属性。del obj.column_namecolumn_name

这不能转化为 Pandas,并且对 Pandas Dataframes 没有意义的原因是:

  • 将其视为一个“虚拟属性”,它本身不是一个东西,它不是该列的“座位”,它只是访问该列的一种方式。很像一个没有删除器的属性。df.column_name
2赞 Falco Alexander 7/22/2022 #20

利用“自动完成”或“IntelliSense”对字符串文本进行利用:

del df[df.column1.name]

# or

df.drop(df.column1.name, axis=1, inplace=True)

它适用于当前的 Pandas 版本。

1赞 Jordy 3/5/2023 #21

如果您想找到从数据框中删除的简单方法,我们开始:column_namedf

df = df[df.columns.drop('column_name')]
1赞 cottontail 6/8/2023 #22

删除列不仅有问题(如@firelynx所解释的那样),而且速度非常慢。例如,它比 慢 ~37 倍。deldrop()

from timeit import timeit
setup = "import pandas as pd; df=pd.DataFrame([range(10000)])"

for _ in range(3):
    t1 = timeit("df = df.drop(columns=df.columns[0])", setup, number=10000)
    t2 = timeit("del df[df.columns[0]]", setup, number=10000)
    print(f"{t2/t1:.2f}")
    
# 37.40
# 37.45
# 37.34

在性能方面,如果需要删除单个列,布尔索引(创建所需列的布尔序列并对其进行索引)实际上是最快的工作方法。但是,如果需要删除多列,则最快的方法。locdrop()

作为复习,有问题的方法如下(本页给出的所有方法都经过测试,但这两种方法是最快的)。

import pandas as pd
df = pd.DataFrame([range(10)]*5).add_prefix('col')

# drop a single column (the performance comparison is shown in LHS subplot)
df1 = df.loc[:, df.columns != 'col2']                # boolean indexing
df2 = df.drop(columns='col2')                        # drop

# drop multiple columns (the performance comparison is shown in RHS subplot)
df1 = df.loc[:, ~df.columns.isin(['col2', 'col4'])]  # boolean indexing
df2 = df.drop(columns=['col2', 'col4'])              # drop

以下性能比较图是使用 perfplot 库(在后台执行测试)创建的。这支持了上述说法。主要收获是删除单列时,布尔索引更快;但是,对于非常宽的数据帧,删除多列时,速度更快。timeitdrop()

performance

用于生成性能图的代码:

import pandas as pd
import perfplot
import random
import matplotlib.pyplot as plt

plt.figure(figsize=(12,5), facecolor='white')
plt.subplot(1, 2, 1)
perfplot.plot(
    setup=lambda n: pd.DataFrame([range(n+1)]),
    kernels=[lambda df: df.drop(columns=df.columns[0]), lambda df: df.loc[:, df.columns != df.columns[0]]],
    labels= ['drop', 'boolean indexing'],
    n_range=[2**k for k in range(21)],
    xlabel='Number of columns in a dataframe',
    title='Removing a single column from a dataframe',
    equality_check=pd.DataFrame.equals)

plt.subplot(1, 2, 2)
perfplot.plot(
    setup=lambda n: (pd.DataFrame([range(n+1)]), random.sample(range(n+1), k=(n+1)//2)),
    kernels=[lambda df,cols: df.drop(columns=cols), lambda df,cols: df.loc[:, ~df.columns.isin(cols)]],
    labels= ['drop', 'boolean indexing'],
    n_range=[2**k for k in range(21)],
    xlabel='Number of columns in a dataframe',
    title='Removing multiple columns from a dataframe',
    equality_check=pd.DataFrame.equals)

plt.tight_layout();