我目前有一个已存在的具有日期索引和每列都有特定名称的Pandas DataFrame。
至于数据单元格,它们填充有各种浮点值。
我想复制我的DataFrame,但用零替换所有这些值。
目标是重用DataFrame的结构(尺寸、索引、列名),但通过将所有当前值替换为零来清除它们。
我目前实现这个功能的方式如下:
df[df > 0] = 0
然而,这不会替换数据框中的任何负值。
是否有更普遍的方法来使用单个共同值填充整个现有数据框?
非常感谢您的帮助。
我目前有一个已存在的具有日期索引和每列都有特定名称的Pandas DataFrame。
至于数据单元格,它们填充有各种浮点值。
我想复制我的DataFrame,但用零替换所有这些值。
目标是重用DataFrame的结构(尺寸、索引、列名),但通过将所有当前值替换为零来清除它们。
我目前实现这个功能的方式如下:
df[df > 0] = 0
然而,这不会替换数据框中的任何负值。
是否有更普遍的方法来使用单个共同值填充整个现有数据框?
非常感谢您的帮助。
最快的方法,同时保留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 samedtype
. If every column ofdf
was originallyfloat
, the newdtypes
will still befloat
. But if a single column wasint
orobject
, it seems that the newdtypes
will all beint
.
df2 = df.replace(df, 0)
如果您想要创建一份拷贝,最好的方法可能是创建一个新的数据框架,将值设置为0,并使用原始数据框架的列和索引:
pd.DataFrame(0, columns=df.columns, index=df.index)
0
作为初始值将设置数据类型为整数。将浮点数分配给数据框将导致它们被转换为整数。如果要使用浮点数,请将数据类型设置为0.0
。 - joostdf.iloc[:] = 0
可以通过将数据框乘以0来实现此目的
df = df * 0
提供信息,BallpointBen的被接受的答案对我来说比Joe T Boka提供的.replace()操作快了近2个数量级。两者都很有帮助。谢谢!
明确一下,BallpointBen描述的快速方法是:
for col in df.columns:
df[col].values[:] = 0
*我本可以评论这个问题,但由于我已经潜伏多年,所以没有足够的街头信誉/声望。我使用timeit.timeit()进行比较。
简单示例。
def zeros_like(df):
new_df = df.copy()
for col in new_df.columns:
new_df[col].values[:] = 0
return new_df