从 Pandas DataFrame 中删除一列

2024-12-03 08:44:00
admin
原创
159
摘要:问题描述:要删除 DataFrame 中的一列,我可以成功使用:del df['column_name'] 但为什么我不能使用以下内容?del df.column_name 由于可以通过访问该系列df.column_name,因此我希望它能够起作用。解决方案 1:在 Pandas 中执行此操作的最佳方式是使用...

问题描述:

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

del df['column_name']

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

del df.column_name

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


解决方案 1:

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

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

其中1编号(0对于行和1对于列。)

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

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)

解决方案 2:

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

del df['column_name']

del df.column_name由于 Python 的语法限制,它很难简单地工作。由 Python 在幕后del df[name]进行翻译。df.__delitem__(name)

解决方案 3:

使用:

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

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

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

解决方案 4:

按索引删除

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

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

解决方案 5:

大多数答案都忽略了所提出的实际问题是:

为何我不能使用del df.column_name

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

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

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

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

您可能会争辩说,del df['column_name']不应使用或鼓励这种做法,因此del df.column_name甚至不应考虑这种做法。

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

示例问题

如果我在数据框中定义一个名为“dtypes”或“columns”的列会怎样?

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

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

这一问题背后的架构问题

  1. 数据框是列的集合吗?

  2. 数据框是的集合吗?

  3. 列是数据框的属性吗?

熊猫回答:

  1. 是的,各方面都如此

  2. 不是,但是如果您愿意,您可以使用.ix.loc.iloc方法。

  3. 也许,您想读取数据吗?那么是的除非该属性的名称已被属于数据框的另一个属性占用。您想修改数据吗?那么不是

TLDR;

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

专业提示:

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

Python 之禅的名言适用于此:

删除列的方法有多种。

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

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

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

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

面对模糊性,拒绝猜测的诱惑。

解决方案 6:

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

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

df.drop(['col_name_1', 'col_name_2', ..., 'col_name_N'], inplace=True, axis=1, errors='ignore')
  • 这是 pandas 0.16.1 及以上版本的新功能。文档在此处。

解决方案 7:

从 0.16.1 版本开始,你可以这样做

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

解决方案 8:

始终使用[]符号是一种很好的做法。原因之一是属性符号 ( 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

解决方案 9:

Pandas 0.21+ 答案

Pandas 0.21 版对该drop方法做了些许修改,使其同时包含index和参数,以匹配和方法columns的签名。rename`reindex`

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

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

解决方案 10:

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

解决方案 11:

使用:

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)

解决方案 12:

总结

花费大量精力寻找稍微更有效的解决方案。很难证明增加复杂性的同时牺牲了简单性df.drop(dlst, 1, errors='ignore')

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

序言

删除一列在语义上与选择其他列相同。我将展示一些其他方法供您考虑。

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

这些解决方案具有通用性,并且也适用于简单的情况。


设置

考虑pd.DataFrame df和列表以删除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   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')
  1. np.setdiff1d(df.columns.values, dlst)

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

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

# does not preserve order
['E', 'D', 'B', 'F', 'G', 'A', 'C']
  1. [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')。看来经过这么多努力,我们只是稍微提高了性能。

在此处输入图片描述

事实上,最好的解决方案是使用reindexreindex_axis破解list(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

解决方案 13:

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

假设df是一个数据框。

要删除的列 = column0

代码:

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

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

代码:

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

解决方案 14:

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

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

解决方案 15:

如果您想找到从数据框中删除的简单方法,请按照以下步骤操作:column_name`df`

df = df[df.columns.drop('column_name')]

解决方案 16:

当我们有一个包含不需要的值的典型列名时,使用和iloc函数删除一列:dataframe`slicing`

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

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

解决方案 17:

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

  • Python:del df['column_name']

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

解决方案 18:

删除 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 获得的结果一样好。

解决方案 19:

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

del df[df.column1.name]

# or

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

它与当前的 Pandas 版本配合良好。

解决方案 20:

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

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

就性能而言,如果需要删除单个列,布尔索引(创建所需列的布尔系列并loc对其进行索引)实际上是完成这项工作的最快方法。但是,如果需要删除多个列,drop()则是最快的方法。

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

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 库(timeit在后台执行测试)创建的。这支持了上述说法。主要结论是,当删除单列时,布尔索引速度更快;但是,当删除非常宽的数据框的多列时,drop()速度更快。

表现

用于生成性能图的代码:

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();

解决方案 21:

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

   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

解决方案 22:

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

这无法转化为 Pandas 并且对于 Pandas Dataframes没有意义的原因是:

  • 将其视为df.column_name“虚拟属性”,它本身不是一个事物,它不是该列的“位置”,它只是访问该列的一种方式。很像没有删除器的属性。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用