如何将现有Pandas DataFrame的所有值设置为零?

47

我目前有一个已存在的具有日期索引和每列都有特定名称的Pandas DataFrame。

至于数据单元格,它们填充有各种浮点值。

我想复制我的DataFrame,但用零替换所有这些值。

目标是重用DataFrame的结构(尺寸、索引、列名),但通过将所有当前值替换为零来清除它们。

我目前实现这个功能的方式如下:

df[df > 0] = 0

然而,这不会替换数据框中的任何负值。

是否有更普遍的方法来使用单个共同值填充整个现有数据框?

非常感谢您的帮助。


5
这段代码的意思是将DataFrame中的所有元素都设置为0。其中df表示DataFrame对象,而.loc[:,:]用于选取DataFrame中的所有行和列。 - MaxU - stand with Ukraine
7个回答

69

最快的方法,同时保留dtypes,如下所示:

for col in df.columns:
    df[col].values[:] = 0

这将直接写入每列底层的numpy数组。我怀疑任何其他方法都不会比这更快,因为它不会分配额外的存储空间,也不会经过pandas的dtype处理。您还可以使用np.issubdtype仅将数字列清零。如果您有一个混合dtype的DataFrame,这可能是您想要的,但如果您的DataFrame已经完全是数字,则当然不需要。

for col in df.columns:
    if np.issubdtype(df[col].dtype, np.number):
        df[col].values[:] = 0

对于小的DataFrames来说,子类型检查有些昂贵。但是清零非数值列的成本很高,因此如果您不确定您的DataFrame是否完全为数字,则应该包括issubdtype检查。


时间比较

设置

import pandas as pd
import numpy as np

def make_df(n, only_numeric):
    series = [
        pd.Series(range(n), name="int", dtype=int),
        pd.Series(range(n), name="float", dtype=float),
    ]
    if only_numeric:
        series.extend(
            [
                pd.Series(range(n, 2 * n), name="int2", dtype=int),
                pd.Series(range(n, 2 * n), name="float2", dtype=float),
            ]
        )
    else:
        series.extend(
            [
                pd.date_range(start="1970-1-1", freq="T", periods=n, name="dt")
                .to_series()
                .reset_index(drop=True),
                pd.Series(
                    [chr((i % 26) + 65) for i in range(n)],
                    name="string",
                    dtype="object",
                ),
            ]
        )

    return pd.concat(series, axis=1)

>>> make_df(5, True)
   int  float  int2  float2
0    0    0.0     5     5.0
1    1    1.0     6     6.0
2    2    2.0     7     7.0
3    3    3.0     8     8.0
4    4    4.0     9     9.0

>>> make_df(5, False)
   int  float                  dt string
0    0    0.0 1970-01-01 00:00:00      A
1    1    1.0 1970-01-01 00:01:00      B
2    2    2.0 1970-01-01 00:02:00      C
3    3    3.0 1970-01-01 00:03:00      D
4    4    4.0 1970-01-01 00:04:00      E

小型数据框

n = 10_000                                                                                  

# Numeric df, no issubdtype check
%%timeit df = make_df(n, True)
for col in df.columns:
    df[col].values[:] = 0
36.1 µs ± 510 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

# Numeric df, yes issubdtype check
%%timeit df = make_df(n, True)
for col in df.columns:
    if np.issubdtype(df[col].dtype, np.number):
        df[col].values[:] = 0
53 µs ± 645 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

# Non-numeric df, no issubdtype check
%%timeit df = make_df(n, False)
for col in df.columns:
    df[col].values[:] = 0
113 µs ± 391 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

# Non-numeric df, yes issubdtype check
%%timeit df = make_df(n, False)
for col in df.columns:
    if np.issubdtype(df[col].dtype, np.number):
        df[col].values[:] = 0
39.4 µs ± 1.91 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

大型数据框

n = 10_000_000                                                                             

# Numeric df, no issubdtype check
%%timeit df = make_df(n, True)
for col in df.columns:
    df[col].values[:] = 0
38.7 ms ± 151 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

# Numeric df, yes issubdtype check
%%timeit df = make_df(n, True)
for col in df.columns:
    if np.issubdtype(df[col].dtype, np.number):
        df[col].values[:] = 0
39.1 ms ± 556 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

# Non-numeric df, no issubdtype check
%%timeit df = make_df(n, False)
for col in df.columns:
    df[col].values[:] = 0
99.5 ms ± 748 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

# Non-numeric df, yes issubdtype check
%%timeit df = make_df(n, False)
for col in df.columns:
    if np.issubdtype(df[col].dtype, np.number):
        df[col].values[:] = 0
17.8 ms ± 228 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

我之前提供了下面的答案,但现在认为它是有害的——它比上面的答案慢得多,而且更难理解。它唯一的优点就是更容易书写。

The cleanest way is to use a bare colon to reference the entire dataframe.

df[:] = 0

Unfortunately the dtype situation is a bit fuzzy because every column in the resulting dataframe will have the same dtype. If every column of df was originally float, the new dtypes will still be float. But if a single column was int or object, it seems that the new dtypes will all be int.


16
你可以使用 replace 函数:
df2 = df.replace(df, 0)

1
如果您需要执行需要原始副本的操作,则此方法是首选方法。 - NickBraunagel
只需输入“df2 = df.replace(df, 0)”即可。原始数据不会受到影响! - kadee
1
小心值强制转换。 - Yatharth Agarwal
1
这似乎在新的pandas版本(例如1.2.4)中不再起作用。 - kadee
这在 Pandas 的后续版本中不再起作用。 - troymyname00

11

如果您想要创建一份拷贝,最好的方法可能是创建一个新的数据框架,将值设置为0,并使用原始数据框架的列和索引:

pd.DataFrame(0, columns=df.columns, index=df.index)

1
注意:使用0作为初始值将设置数据类型为整数。将浮点数分配给数据框将导致它们被转换为整数。如果要使用浮点数,请将数据类型设置为0.0 - joost

4
晚了一点,但我想分享一种不使用任何循环的替代方法。
df.iloc[:] = 0

1

可以通过将数据框乘以0来实现此目的

df = df * 0

0

提供信息,BallpointBen的被接受的答案对我来说比Joe T Boka提供的.replace()操作快了近2个数量级。两者都很有帮助。谢谢!

明确一下,BallpointBen描述的快速方法是:

for col in df.columns: df[col].values[:] = 0

*我本可以评论这个问题,但由于我已经潜伏多年,所以没有足够的街头信誉/声望。我使用timeit.timeit()进行比较。


0

简单示例。

def zeros_like(df):
    new_df = df.copy()
    for col in new_df.columns:
        new_df[col].values[:] = 0
    return new_df

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