提问人:John 提问时间:11/16/2012 最后编辑:cottontailJohn 更新时间:8/19/2023 访问量:3975175
从 Pandas DataFrame 中删除列
Delete a column from a Pandas DataFrame
问:
要删除 DataFrame 中的列,我可以成功使用:
del df['column_name']
但是为什么我不能使用以下内容呢?
del df.column_name
由于可以通过 访问该系列,我希望这能起作用。df.column_name
答:
最好始终使用表示法。原因之一是属性表示法 () 不适用于编号索引:[]
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
正如你所猜到的,正确的语法是
del df['column_name']
仅仅因为 Python 中的语法限制,很难使工作变得困难。 被 Python 翻译成 under the covers。del df.column_name
del df[name]
df.__delitem__(name)
评论
class A(object): def __init__(self): self.var = 1
a = A(); del a.var
del df[name]
df.__delitem__(name)
del df.name
del a.var
pandas
在 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)
评论
del
drop
del
drop
Panel
)
用:
columns = ['Col1', 'Col2', ...]
df.drop(columns, inplace=True, axis=1)
这将就地删除一列或多列。请注意,这是在 pandas v0.13 中添加的,不适用于旧版本。在这种情况下,您必须重新分配结果:inplace=True
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 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
一个很好的补充是仅当列存在时才删除列。这样,您可以涵盖更多用例,并且它只会从传递给它的标签中删除现有列:
例如,只需添加 errors='ignore':
df.drop(['col_name_1', 'col_name_2', ..., 'col_name_N'], inplace=True, axis=1, errors='ignore')
- 这是从 pandas 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 中无效。
- 蟒:
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')
评论
errors= 'ignore'
df.drop(['column_1','column_2'], axis=1 , inplace=True,errors= 'ignore')
这里提出的大多数答案遗漏的实际问题是:
为什么我不能使用?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_name
del df['column_name']
示例问题
如果我在数据帧中定义一个名为“dtypes”或“columns”的列,该怎么办?
然后假设我想删除这些列。
del df.dtypes
会使方法混淆,就好像它应该删除“dtypes”属性或“dtypes”列一样。__delattr__
此问题背后的架构问题
- 数据帧是列的集合吗?
- 数据帧是行的集合吗?
- 列是 DataFrame 的属性吗?
熊猫回答:
- 是的,在各个方面
- 不可以,但如果你愿意,你可以使用 , 或 方法。
.ix
.loc
.iloc
- 也许,你想读取数据吗?然后是,除非属性的名称已被属于 DataFrame 的另一个属性占用。是否要修改数据?那就不行了。
顶级域名;
你不能这样做,因为 Pandas 有一个相当疯狂的架构,需要重新考虑,以免这种认知失调发生在其用户身上。del df.column_name
专业提示:
不要使用df.column_name。它可能很漂亮,但它会导致认知失调。
Zen of Python 的名言适合这里:
有多种方法可以删除列。
应该有一种——最好只有一种——显而易见的方法来做到这一点。
列有时是属性,但有时不是。
特殊情况还不足以打破规则。
是否删除 dtypes 属性或 dtypes 列?del df.dtypes
面对暧昧,拒绝猜测的诱惑。
评论
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)
Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
np.setdiff1d(df.columns.values, dlst)
array(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype=object)
df.columns.drop(dlst, errors='ignore')
Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
list(set(df.columns.values.tolist()).difference(dlst))
# does not preserve order ['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 not in 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')
如果事实上最好的解决方案使用或黑客.紧随其后,仍然比现在好一点。reindex
reindex_axis
list(set(df.columns.values.tolist()).difference(dlst))
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
熊猫 0.21+ 个回答
Pandas 版本 0.21 略微更改了 drop
方法,以包含 and 参数以匹配 and 方法的签名。index
columns
rename
reindex
df.drop(columns=['column_a', 'column_c'])
就我个人而言,我更喜欢使用该参数来表示列或索引,因为它是几乎所有 pandas 方法中使用的主要关键字参数。但是,现在您在 0.21 版本中增加了一些选择。axis
删除 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.
评论
如果你的原始数据帧 df
不是太大,你没有内存限制,你只需要保留几列,或者,如果你事先不知道所有不需要的额外列的名称,那么你不妨创建一个新的 DataFrame,只包含你需要的列:
new_df = df[['spam', 'sausage']]
我们可以通过 drop() 方法移除或删除指定的列或指定的列。
假设 df 是一个数据帧。
要删除的列 = column0
法典:
df = df.drop(column0, axis=1)
要删除多个列 col1、col2、. . . . 、 coln,我们必须在列表中插入所有需要删除的列。然后通过 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)
使用 和 的函数删除列,当我们有一个带有不需要的值的典型列名时:iloc
dataframe
slicing
df = df.iloc[:,1:] # Removing an unnamed index column
这是默认行,是第一列,因此是我们删除第一列的参数。0
1
:,1:
若要删除特定列之前和之后的列,可以使用截断方法。例如:
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
从一般的 Python 角度来看,如果可以删除该属性,则有意义。它必须是常规属性,或者是具有已定义删除程序的属性。del obj.column_name
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 版本。
如果您想找到从数据框中删除的简单方法,我们开始:column_name
df
df = df[df.columns.drop('column_name')]
删除列不仅有问题(如@firelynx所解释的那样),而且速度非常慢。例如,它比 慢 ~37 倍。del
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();
评论