如何检查数据帧是否包含所有 0 个条目?

How to check that a dataframe consists of all 0 entries?

提问人:24n8 提问时间:11/16/2023 最后编辑:Goku - stands with Palestine24n8 更新时间:11/17/2023 访问量:99

问:

我知道一种方法是遍历所有列,例如,

for col in df.columns:
  assert (df[col] != 0).sum() == 0

有没有更好的方法可以对整个数据帧进行操作,而无需遍历每个单独的列?

python-3.x pandas 数据帧

评论

0赞 24n8 11/16/2023
@Mark啊,对,我认为应该是而不是!===
0赞 Nick 11/17/2023
这被证明是一个有趣的问题......

答:

1赞 kevin41 11/16/2023 #1

如果 df 中的所有值都为 0,则此函数将返回,如果不是。TrueFalse

def is_zero(df):
    vals = df.to_numpy()
    return (0 == vals).all()

评论

0赞 Mark 11/16/2023
我想知道你是否能做到没有to_numpy() -> (df == 0).all(axis=None)
0赞 kevin41 11/16/2023
看起来你可以,@Goku发布了不少选项
0赞 Nick 11/16/2023
我已经在另一篇文章中发布了您(和其他答案)的计时结果。
0赞 Nick 11/16/2023
有趣的是,事实证明使用是一件好事to_numpy
0赞 24n8 11/16/2023
@Nick 也许numpy's比pandas更优化?all
1赞 Goku - stands with Palestine 11/16/2023 #2

正如 @Mark 所评论的那样:

您可以尝试:

(df == 0).all()

#output
Col_1    True
Col_2    True
dtype: bool

它将给出单个列的结果,就像所有列一样; 都是Col_10Col_20

如果你这样做:

(df == 0).all(axis=None)

它将提供整个数据帧

您还可以执行以下操作:

all((df == 0).all())

评论

0赞 Nikolaj Š. 11/16/2023
使用要好得多,因为它会返回第一个非零元素(如果有的话),就像@tdelaney的答案一样not any()
0赞 Nick 11/16/2023
我已经在另一篇文章中发布了您(和其他答案)的计时结果。
1赞 Riyan Sthefanus Nainggolan 11/16/2023 #3

看看这个:

df.isin([0]).sum()

1赞 tdelaney 11/16/2023 #4

您可以检查是否有任何内容不是 0,然后否定。使用带有轴 None 的 dataFrame 方法检查所有值。这应该在第一个非零值上停止,该值优于或将构建一个全新的序列或数据帧。.anysumdf == 0

not df.any(axis=None)

评论

1赞 Nick 11/16/2023
我已经在另一篇文章中发布了您(和其他答案)的计时结果。
3赞 Nick 11/16/2023 #5

出于好奇,我测试了这里给出的答案中的方法,我在 StackOverflow 的其他地方发现了类似的问题。以下是方法:

funcs = { 
    'tdelaney' : lambda df:not df.any(axis=None),
    'Goku 1'   : lambda df:(df == 0).all(axis=None),
    'Goku 2'   : lambda df:all((df == 0).all()),
    'kevin41'  : lambda df:(0 == df.to_numpy()).all(),
    'other 1'  : lambda df:not np.any(df),
    'other 2'  : lambda df:(df != 0).sum().sum() == 0,
    'other 3'  : lambda df:(df != 0).any(axis=None)
}

为了进行测试,我使用了 1000 行和 1000 列的数据帧,其中全是零,另外三个值分别为 和 :1[1,1][499,499][999,999]

N = 1000
df0 = pd.DataFrame(np.zeros([N,N]))
df_low = pd.DataFrame(np.zeros([N,N]))
df_mid = pd.DataFrame(np.zeros([N,N]))
df_high = pd.DataFrame(np.zeros([N,N]))
df_low.loc[1, 1] = 1
df_mid.loc[N//2-1, N//2-1] = 1
df_high.loc[N-1, N-1] = 1

然后,我在循环中迭代了函数和数据帧(打印只是为了为 SO 制作表格标记):

for name, func in funcs.items():
    print(f'| {name} ', end='')
    for df in dfs.values():
        time = timeit.timeit(setup='import pandas as pd, numpy as np', stmt='res = func(df)',number=1000,globals=locals())
        print(f'| {time:.3f} ', end='')
    print('|')

结果如下:

方法
特德莱尼 0.846 0.840 0.830 0.854
悟空 1 0.331 0.321 0.316 0.313
悟空2 0.322 0.299 0.309 0.326
凯文41 0.139 0.140 0.145 0.138
其他 1 0.800 0.780 0.784 0.790
其他 2 0.821 0.818 0.816 0.842
其他 3 0.325 0.315 0.312 0.314

可以看出,kevin41 发布的答案是 - 对于这个样本数据 - 是下一个最佳解决方案的两倍多。在那之后,悟空的解决方案和“其他 3 个”解决方案彼此大致相等,最后三个解决方案比它们慢约 2.5 倍。

有趣的是,每种方法的时间和时间是一致的,这表明没有发生短路。df_lowdf_high

评论

1赞 Goku - stands with Palestine 11/16/2023
谢谢@Nick感谢您的努力:)
0赞 Nikolaj Š. 11/17/2023
考虑到期望,看到这样做很糟糕是相当令人惊讶的.any()
1赞 Nick 11/18/2023
@NikolajŠ。同意,我本来希望能特别好地处理这个案子。anylow