Pandas:删除所有NaN值的列

146

我有一个DataFrame:

                      0   1   2         3   4       5   6          7
0               #0915-8 NaN NaN       NaN NaN     NaN NaN        NaN
1                   NaN NaN NaN  LIVE WGT NaN  AMOUNT NaN      TOTAL
2               GBW COD NaN NaN     2,280 NaN   $0.60 NaN  $1,368.00
3               POLLOCK NaN NaN     1,611 NaN   $0.01 NaN     $16.11
4                 WHAKE NaN NaN       441 NaN   $0.70 NaN    $308.70
5           GBE HADDOCK NaN NaN     2,788 NaN   $0.01 NaN     $27.88
6           GBW HADDOCK NaN NaN    16,667 NaN   $0.01 NaN    $166.67
7               REDFISH NaN NaN       932 NaN   $0.01 NaN      $9.32
8    GB WINTER FLOUNDER NaN NaN       145 NaN   $0.25 NaN     $36.25
9   GOM WINTER FLOUNDER NaN NaN    25,070 NaN   $0.35 NaN  $8,774.50
10        GB YELLOWTAIL NaN NaN        26 NaN   $1.75 NaN     $45.50

我希望删除所有的NaN以及任何包含超过3个NaN的列(其中一个或两个都可以)��� 我尝试了这段代码:

fish_frame.dropna()
fish_frame.dropna(thresh=len(fish_frame) - 3, axis=1)

但似乎对DataFrame没有任何影响 - 之后我看到的结果相同。

代码有什么问题,如何修复?


8
.dropna() 不会直接在原数据框上进行修改,而是返回一个修改后的数据框。因此你需要将其重新赋值给原数据框,例如:df = df.dropna() 或者显式地使用 inplace=True 参数。 - MaxU - stand with Ukraine
哦,我的错。我懂了。鉴于我的原始数据中有多少个NaN,我应该期望那个命令会产生一个空的数据框吗? - theprowler
1
我认为你的第二个命令应该可以工作(因为它针对列),但第一个命令将删除任何带有 NaN 的行 - 因为所有行都至少有一个 NaN,所以它将删除所有行。 - Corley Brigman
@MaxU:最好说dropna() **默认情况下是inplace=False**,所以你需要分配它;但如果你想要原地操作,只需执行dropna(..., inplace=True) - smci
1
当你说“删除所有NaN值”时,你真正想表达的是“删除所有包含NaN值的列”。这略有不同。 - smci
近似但更早的2012年问题在Pandas数据框中删除NaN / NULL列?。不幸的是,我们无法将其关闭到此位置。还有来自2015年的从pandas数据帧中选择行,其中指定的列不全为NaN - smci
4个回答

263

dropna 的文档字符串中:

删除所有元素都为 NaN 的列:
df.dropna(axis=1, how='all')


   A    B    D
0  NaN  2.0  0
1  3.0  4.0  1
2  NaN  NaN  5

如果您想保留新的数据框而不含有空列,请使用 "inplace = True" 选项。例如:df.dropna(axis=1, how='all', inplace=True) - Alex
@Alex inplace 很可能会被弃用,应该避免使用。https://github.com/pandas-dev/pandas/issues/16529 和 https://towardsdatascience.com/why-you-should-probably-never-use-pandas-inplace-true-9f9f211849e4 - fantabolous

16

dropna() 函数删除缺失值并返回一个数据框。将其分配回原始数据框。

fish_frame = fish_frame.dropna(axis = 1, how = 'all')

关于你的代码:

fish_frame.dropna(thresh=len(fish_frame) - 3, axis=1)

如果数据框的长度为10,这将会删除具有7个或更多NaN值的列。如果你想要删除具有超过3个NaN值的列,那么阈值应该等于3。


好的,MaxU已经解释了为什么会这样。但是对于我的数据框架来说,在运行fish_frame = fish_frame.dropna()之后,它产生了一个空的数据框架。这是否是可以预期的? - theprowler
1
尝试传递参数 how = 'all' - Rakesh Adhikesavan

8

另一个解决方案是创建一个布尔数据框,在非空位置放置True值,然后选择至少有一个True值的列。以下代码会删除所有NaN值的列。

df = df.loc[:,df.notna().any(axis=0)]

如果您想要移除至少有一个缺失值(NaN)的列;

df = df.loc[:,df.notna().all(axis=0)]

这种方法特别适用于删除包含空字符串、零或任何给定值的列。例如:

df = df.loc[:,(df!='').all(axis=0)]

删除至少有一个空字符串的列。


这种方法很有用,因为它指向了有选择地删除列子集的方向。 - pauljohn32

8
dropna()默认返回一个数据框(默认情况下,inplace=False),因此需要将其分配给新的数据框以使其保留在您的代码中。
例如,
fish_frame = fish_frame.dropna()

关于为什么您的dropna返回一个空数据框,我建议您查看dropna方法中的"how"参数(https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html)。另外请注意,axis=0对应列,axis=1对应行。
因此,要删除所有"NAs"的列,可以使用axis=0和how="any"来解决问题:
fish_frame = fish_frame.dropna(axis=0, how="any")

最后,“thresh”参数明确指定需要多少个NA才能导致删除。因此,
fish_frame = fish_frame.dropna(axis=0, thresh=3, how="any") 

应该可以很好地移除任何具有三个NA的列。

另外,正如Corley指出的那样,how="any"是默认设置,因此不必要。


你是不是想说how='all' - jwm
你不能同时使用阈值和how="any"。 - nafrtiti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接