df = df.drop(df.columns[i], axis=1)

但我得到一个错误,说索引超出了范围,我想这是因为当我删除列的时候,数据框架的形状发生了变化。如果我不存储 "for "循环的输出,那么代码就能工作,但我没有得到我的新数据框架。

我如何解决这个问题?

1 个评论
你的代码的问题是,你在每次迭代后覆盖df,然后删除第3、6、9...列。一旦有一列被删除,列的长度就会减少1,所以你最终会用完所有的列,并且在第一次迭代后会删除错误的列。我在下面的答案中阐述了这个问题和解决方案
python
pandas
dataframe
Samiur Rahman
Samiur Rahman
发布于 2020-12-09
3 个回答
Akshay Sehgal
Akshay Sehgal
发布于 2020-12-09
已采纳
0 人赞同

The issue with code is 在你的循环中,每次丢掉一列,你都会得到一组不同的列,因为你在每次迭代后都会把 df 覆盖回去。当你试图删除这组新列中的第3列时,你不仅删除了错误的一列,而且最终会耗尽所有的列。这就是为什么你会得到你所得到的错误。

iter1 -> 0,1,3,4,5,6,7,8,9,10 ... n #first you drop 2 which is 3rd col
iter2 -> 0,1,3,4,5,7,8,9,10 ... n   #next you drop 6 which is 6th col (should be 5)
iter3 -> 0,1,3,4,5,7,8,9, ... n     #next you drop 10 which is 9th col (should be 8)

你要做的是事先计算好索引,然后一次性删除它们。

你可以简单地只获得你想用范围删除的列的索引,然后放弃这些。

drop_idx = list(range(2,df.shape[1],3)) #Indexes to drop
df2 = df.drop(drop_idx, axis=1)         #Drop them at once over axis=1
print('old columns->', list(df.columns))
print('idx to drop->', drop_idx)
print('new columns->',list(df2.columns))
old columns-> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
idx to drop-> [2, 5, 8]
new columns-> [0, 1, 3, 4, 6, 7, 9]

Note:这只是因为你的列名与索引相同。然而,如果你的列名不是这样的,你将不得不做一个额外的步骤,根据你想放弃的索引来获取列名。

drop_idx = list(range(2,df.shape[1],3))
drop_cols = [j for i,j in enumerate(df.columns) if i in drop_idx] #<--
df2 = df.drop(drop_cols, axis=1)
    
请注意,由于你的列名与索引相同,所以它是有效的,否则你将不得不做一个额外的步骤,用 enumerate 通过 drop_idx 来过滤 list(df.columns) ,然后丢弃剩下的列。
我相信使用列表理解(按照我的回答)来选择你想要的列 keep 几乎总是可读性更强,用途更广。你可以以任何方式过滤、交换或重新排序列,而且它也适用于字符串的列名(一种更常见的情况)。这就是为什么我总是试图引导人们使用它作为列子集的一个更通用的工具(以及列表或字典的子集,对于这个问题)。
同意,但对于这个具体问题,可以避免使用列表理解,因为索引也是数据集的列名。但在一般情况下,是的,正如我的第二个解决方案所建议的,我使用列表理解来选择列名,然后使用矢量(和内存效率) df.drop 来过滤掉它们。
matt
you forgot to replace the drop_idx to drop_cols in the last line from df2 = df.drop(drop_idx, axis=1) --> df2 = df.drop(drop_cols, axis=1)
谢谢你发现这一点。在编辑中修正了它!
jezrael
jezrael
发布于 2020-12-09
0 人赞同

这里有一个颠倒逻辑的解决方案--选择所有的列并删除每一个第三列。

你可以通过比较将 1 添加到帮助器数组中,用3次模数比较来过滤不等于 0 的值,并传递给 DataFrame.loc :

df = pd.DataFrame({
        'A':list('abcdef'),
         'B':[4,5,4,5,5,4],
         'C':[7,8,9,4,2,3],
         'D':[1,3,5,7,1,0],
         'E':[5,3,6,9,2,4],
         'F':list('aaabbb')
df = df.loc[:, (np.arange(len(df.columns)) + 1) % 3 != 0]
print (df)
   A  B  D  E
0  a  4  1  5
1  b  5  3  3
2  c  4  5  6
3  d  5  7  9
4  e  5  1  2
5  f  4  0  4
    
他想列 0, 1, not 2 , 3, 4 , not 5 , ...
@PierreD - 是的,添加了 1
Pierre D
Pierre D
发布于 2020-12-09
0 人赞同

你可以使用列表理解法来过滤列。