从Pandas DataFrame中删除一列

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

del df['column_name']

为什么我不能使用下面的?

del df.column_name

由于可以将列/系列作为df.column_name访问,我希望这可以工作。

3322622 次浏览

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

In [1]: df = DataFrame([[1, 2, 3], [4, 5, 6]])
In [2]: df[1]Out[2]:0    21    5Name: 1
In [3]: df.1File "<ipython-input-3-e4803c0d1066>", line 1df.1^SyntaxError: invalid syntax

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

del df['column_name']

由于Python中的语法限制,很难使del df.column_name工作。del df[name]在Python的掩护下被翻译成df.__delitem__(name)

在Pandas中做到这一点的最佳方法是使用#0

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

其中1的数字(0表示行,1表示列)。

要删除列而无需重新分配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

还使用列的“text”语法:

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

备注:v0.21.0(2017年10月27日)中引入,drop()方法接受索引/列关键字作为指定轴的替代方法。

所以我们现在可以做:

df = df.drop(columns=['column_nameA', 'column_nameB'])

用途:

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

这将在原地删除一个或多个列。请注意,inplace=True是在熊猫v0.13中添加的,在旧版本上不起作用。在这种情况下,您必须将结果分配回:

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

按指数下降

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

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  threeA    1    2      3B    4    5      6C    7    8      9

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

#请求参数
   two  threeA    2      3B    5      6C    8      9

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

#请求参数
   twoA    2B    5C    8

一个很好的补充是仅删除存在的列的能力。这样你就可以覆盖更多的用例,它只会从传递给它的标签中删除现有列:

简单地添加错误='忽略',例如:

df.drop(['col_name_1', 'col_name_2', ..., 'col_name_N'], inplace=True, axis=1, errors='ignore')
  • 这是从熊猫0.16.1开始的新功能。文档是这里

在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)

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

  • python:del df['column_name']
  • JavaScript:del df['column_name']del df.column_name

从0.16.1版本开始,您可以

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

提出的实际问题,这里的大多数答案都错过了:

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

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

正如他的答案中的韦斯指出del df['column']映射到Python魔术方法df.__delitem__('column'),即在Pandas中实现以删除列

然而,正如上面关于Python魔法方法的链接所指出的:

事实上,__del__几乎不应该被使用,因为它被调用的情况不稳定;谨慎使用!

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

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

示例问题

如果我在数据框中定义一个名为“dtype”或“列”的列怎么办?

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

del df.dtypes会使__delattr__方法感到困惑,就好像它应该删除“dtype”属性或“dtype”列一样。

这个问题背后的架构问题

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

熊猫回答:

  1. 是的,在所有方面
  2. 不,但是如果你想这样做,你可以使用.ix.loc.iloc方法。
  3. 也许,你想阅读数据吗?然后是的除非属性的名称已经被属于数据框的另一个属性占用。你想修改数据吗?然后

TLDR;

你不能做del df.column_name,因为Pandas有一个非常疯狂增长的架构,需要重新考虑,以便这种认知失调不会发生在它的用户身上。

专业提示:

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

这里适合的Python引用的禅:

有多种方法可以删除列。

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

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

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

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

面对模棱两可,拒绝猜测的诱惑。

太长别读

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

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

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

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

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


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

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

df
A  B  C  D  E  F  G  H  I   J0  1  2  3  4  5  6  7  8  9  101  1  2  3  4  5  6  7  8  9  102  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  G0  1  2  3  4  5  6  71  1  2  3  4  5  6  72  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  G0  1  2  3  4  5  6  71  1  2  3  4  5  6  72  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)

来自Boolean的列
为了便于比较

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

它们都评估为:

   A  B  C  D  E  F  G0  1  2  3  4  5  6  71  1  2  3  4  5  6  72  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        1000Select Labelloc    brod           0.747373  0.861979  0.891144  1.284235   3.872157columndrop     1.193983  1.292843  1.396841  1.484429   1.335733comp           0.802036  0.732326  1.149397  3.473283  25.565922comprehension  1.463503  1.568395  1.866441  4.421639  26.552276difference     1.413010  1.460863  1.587594  1.568571   1.569735in1d           0.818502  0.844374  0.994093  1.042360   1.076255isin           1.008874  0.879706  1.021712  1.001119   0.964327setdiff1d      1.352828  1.274061  1.483380  1.459986   1.466575setdifflst     1.233332  1.444521  1.714199  1.797241   1.876425ridx   columndrop     0.903013  0.832814  0.949234  0.976366   0.982888comprehension  0.777445  0.827151  1.108028  3.473164  25.528879difference     1.086859  1.081396  1.293132  1.173044   1.237613setdiff1d      0.946009  0.873169  0.900185  0.908194   1.036124setdifflst     0.732964  0.823218  0.819748  0.990315   1.050910ridxa  columndrop     0.835254  0.774701  0.907105  0.908006   0.932754comprehension  0.697749  0.762556  1.215225  3.510226  25.041832difference     1.055099  1.010208  1.122005  1.119575   1.383065setdiff1d      0.760716  0.725386  0.849949  0.879425   0.946460setdifflst     0.710008  0.668108  0.778060  0.871766   0.939537slc    columndrop     1.268191  1.521264  2.646687  1.919423   1.981091comprehension  0.856893  0.870365  1.290730  3.564219  26.208937difference     1.470095  1.747211  2.886581  2.254690   2.050536setdiff1d      1.098427  1.133476  1.466029  2.045965   3.123452setdifflst     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')所需的时间而言的。似乎经过所有这些努力,我们只是适度地提高了性能。

在此处输入图片描述

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

rs.idxmin().pipe(lambda x: pd.DataFrame(dict(idx=x.values, val=rs.lookup(x.values, x.index)),x.index))
idx       val10     (ridx, setdifflst)  0.65343130    (ridxa, setdifflst)  0.746143100   (ridxa, setdifflst)  0.816207300    (ridx, setdifflst)  0.7801571000  (ridxa, setdifflst)  0.861622

熊猫0.21+答案

Pandas 0.21版稍微改变了#0方法,包括indexcolumns参数,以匹配renamereindex方法的签名。

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

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

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

如果您不是在寻找就地删除,那么您可以通过使用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得到的一样好。

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

new_df = df[['spam', 'sausage']]

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

假设df是一个数据帧。

要删除的列=列0

代码:

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

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

代码:

df = df.drop([col1, col2, . . . , coln], axis=1)

用途:

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)

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

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

这里0是默认行,1是第一列,因此:,1:是删除第一列的参数。

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

   A   B    C     D      E0  1  10  100  1000  100001  2  20  200  2000  20000
df.truncate(before='B', after='D', axis=1)

输出:

    B    C     D0  10  100  10001  20  200  2000

从一般Python的角度来看,如果可以删除属性column_name,则del obj.column_name是有意义的。它需要是一个常规属性-或者具有定义的删除器的属性。

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

  • 考虑df.column_name是一个“虚拟属性”,它本身不是一个东西,它不是该列的“座位”,它只是访问该列的一种方式。就像没有删除器的属性一样。

通过使用自动完成或“IntelliSense”而不是字符串文字来利用:

del df[df.column1.name]
# or
df.drop(df.column1.name, axis=1, inplace=True)

它适用于当前的Pandas版本。