ChatGPT解决这个技术问题 Extra ChatGPT

从 Pandas DataFrame 中删除一列

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

del df['column_name']

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

del df.column_name

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

请注意,此问题正在 Meta 上讨论。

P
Peter Olson

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

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

其中 1axis 编号(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

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

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'])

出于某种原因,这是否推荐超过 del
尽管这种删除方法有其优点,但这个答案并不能真正回答所提出的问题。
是的@Paul,但由于问题的标题,大多数到达这里的人都会通过尝试解决如何删除列来做到这一点。
@beardc drop 优于 del 的另一个优点是 drop 允许您一次删除多个列,执行或不就地操作,还可以删除沿任意轴的记录(对于 3-D 矩阵或Panel)
drop 相对于 del 的另一个优势是 drop 是 pandas API 的一部分并包含文档。
c
cs95

如您所料,正确的语法是

del df['column_name']

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


我意识到这是一个非常古老的“答案”,但我的好奇心被激起了 - 为什么这是 Python 的语法限制? class A(object): def __init__(self): self.var = 1 设置了一个类,然后 a = A(); del a.var 工作正常...
@dwanderson 不同之处在于,当要删除一列时,DataFrame 需要有自己的“如何做”处理。在 del df[name] 的情况下,它被转换为 df.__delitem__(name),这是 DataFrame 可以实现和修改以满足其需求的一种方法。在 del df.name 的情况下,成员变量被删除,没有机会运行任何自定义代码。考虑您自己的示例 - 您可以让 del a.var 打印“删除变量”吗?如果可以的话,请告诉我怎么做。我不能:)
@Yonatan Eugene 的评论也适用于 Python 2;描述符自 2.2 以来一直在 Python 2 中,满足您的要求很简单;)
这个答案并不真正正确 - pandas 开发人员没有,但这并不意味着它很难做到。
P
Peter Mortensen

利用:

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

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

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

P
Peter Mortensen

按索引删除

删除第一、二、四列:

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

删除第一列:

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

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

弹出

Column selection, addition, deletion

删除列 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

P
Peter Mortensen

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

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

首先,我们需要了解问题所在,这需要我们深入研究Python magic methods

正如他的回答中的 Wes points outdel df['column'] 映射到 Python 魔术方法 df.__delitem__('column'),即 implemented in Pandas to drop the column

但是,正如上面关于 Python magic methods 的链接所指出的:

事实上, __del__ 几乎不应该被使用,因为它被称为不稳定的环境;谨慎使用!

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

但是,理论上,可以使用 the magic method __delattr__ 实现 del df.column_name 以在 Pandas 中工作。然而,这确实引入了某些问题,即 del df['column_name'] 实现已经存在的问题,但程度较轻。

示例问题

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

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

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

这个问题背后的架构问题

数据框是列的集合吗?数据框是行的集合吗?列是数据框的属性吗?

熊猫回答:

是的,在所有方面都没有,但如果您愿意,您可以使用 .ix、.loc 或 .iloc 方法。也许,你想读取数据吗?那么是的,除非该属性的名称已经被属于数据框的另一个属性占用。是否要修改数据?那就不要。

TLDR;

您不能这样做 del df.column_name,因为 Pandas 有一个相当广泛发展的架构,需要重新考虑以使其用户不会发生这种认知失调

专家提示:

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

适合此处的 Python 之禅:

有多种删除列的方法。

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

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

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

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

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


实际上解决了原始问题的 WHY 部分。我已经实现了 pandas 数据框的子类。这样做会教你这个答案的重要部分。区分属性和列名是一个大问题。 df.a 无论 a 是属性还是列名,都会留下歧义。但是,在编写 pandas 时, df["a"] 只能是一列。
P
Peter Mortensen

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

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

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

这是从 pandas 0.16.1 开始的新功能。文档在这里。


P
Peter Mortensen

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

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

如果需要这样的应用程序,这还支持删除多个列,其中一些不需要存在(即不引发错误 errors= 'ignore'df.drop(['column_1','column_2'], axis=1 , inplace=True,errors= 'ignore')
P
Peter Mortensen

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

A
Asclepius

熊猫 0.21+ 答案

Pandas 0.21 版稍微更改了 drop 方法,以包含 indexcolumns 参数以匹配 renamereindex 方法的签名。

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

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


P
Peter Mortensen

在 Pandas 0.16.1+ 中,您只能删除每个 the solution posted by 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)

P
Peter Mortensen

利用:

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)

p
piRSquared

TL;博士

为找到一个稍微更有效的解决方案付出了很多努力。在牺牲 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

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

标签选择 布尔选择

标签选择

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

df.columns.difference(dlst) 索引(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object') np.setdiff1d( df.columns.values, dlst) 数组(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype=object) df.columns.drop( dlst, errors='ignore') 索引(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object') list(set( df.columns.values.tolist()).difference(dlst)) # 不保留顺序 ['E', 'D', 'B', 'F', 'G', 'A', 'C'] [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]

然后我们可以评估

df.loc[:, cols] df[cols] df.reindex(columns=cols) 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

布尔切片

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

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

来自布尔的列为了比较

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

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') 所需的时间有关。似乎经过所有努力,我们只能适度提高性能。

https://i.stack.imgur.com/208z6.png

事实上,最好的解决方案在 hack 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       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

P
Peter Mortensen

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

假设 df 是一个数据框。

要删除的列 = column0

代码:

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

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

代码:

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

c
ccpizza

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

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

S
S Habeeb Ullah

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

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

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


a
anothernode

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

Python:del df['column_name']

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


P
Peter Mortensen

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

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


这在技术上是正确的,但是必须列出要保留的每一列而不是只列出要删除的一列(或几列)似乎很愚蠢。
M
Mykola Zotko

要删除特定列之前和之后的列,您可以使用方法 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

c
creanion

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

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

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


F
Falco Alexander

通过在字符串文字上使用自动完成或“智能感知”来利用:

del df[df.column1.name]

# or

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

适用于当前的熊猫