其目的是减少内存使用。这意味着它应该以hash
等于test hash
的方式进行优化。
到目前为止,我已经尝试过:
1.添加了__slots__
,但未进行任何更改。
1.将default dtypefloat64
更改为float32
。虽然这显著减少了mem的使用,但它通过更改哈希值来阻止测试。
1.将数据转换为np.array
减少了CPU时间:from 13 s to 2.05 s
,但不影响内存使用。
要重现的代码:
rows = 40000000
trs = 10
random.seed(42)
generated_data: tp.List[float] = np.array([random.random() for _ in range(rows)])
def df_upd(df_initial: pd.DataFrame, df_new: pd.DataFrame) -> pd.DataFrame:
return pd.concat((df_initial, df_new), axis=1)
class T:
"""adding a column of random data"""
__slots__ = ['var']
def __init__(self, var: float):
self.var = var
def transform(self, df_initial: pd.DataFrame) -> pd.DataFrame:
return df_upd(df_initial, pd.DataFrame({self.var: generated_data}))
class Pipeline:
__slots__ = ['df', 'transforms']
def __init__(self):
self.df = pd.DataFrame()
self.transforms = np.array([T(f"v{i}") for i in range(trs)])
def run(self):
for t in self.transforms:
self.df = t.transform(self.df)
return self.df
if __name__ == "__main__":
# starting the monitoring
tracemalloc.start()
# function call
pipe = Pipeline()
%time df = pipe.run()
print("running")
# displaying the memory
current, peak = tracemalloc.get_traced_memory()
print(f"Current memory usage is {current / 10**3} KB ({(current / 10**3)*0.001} MB); Peak was {peak / 10**3} KB ({(peak / 10**3)*0.001} MB); Diff = {(peak - current) / 10**3} KB ({((peak - current) / 10**3)*0.001} MB)")
# stopping the library
tracemalloc.stop()
# should stay unchanged
%time hashed_df = hashlib.sha256(pd.util.hash_pandas_object(df, index=True).values).hexdigest()
print("hashed_df", hashed_df)
assert hashed_df == test_hash
print("Success!")
1条答案
按热度按时间zc0qhyus1#
如果您避免使用
pd.concat()
并使用 preferred 方式扩充 Dataframe :这将显著降低峰值存储器消耗。
在代码中,修复
Transform
类就足够了:(Note我还将
var
的type
从float
更改为str
,以反映它在代码中的使用方式)。在我的机器里,我从:
当前内存使用量为1600110.987 KB(1600.110987 MB);峰值为4480116.325KB(4480.116325MB);差异= 2880005.338 KB(2880.005338 MB)
至:
当前内存使用量为1760101.105 KB(1760.101105 MB);峰值为1760103.477KB(1760.1034769999999MB);差异= 2.372 KB(0.002372 MB)
(我不确定为什么在这种情况下当前的内存使用率略高)。
为了加快计算速度,您可能需要执行一些预分配。
为此,您可以在Pipeline的
__init__()
中替换:与:
如果您希望更快,可以立即在管道的
__init__
中计算DataFrame,例如:但是我假设您的
Transform
是一个更复杂操作的代理,并且我不确定这种简化是否容易适应问题中的玩具代码。