我会发表一些想法如何解决这个问题,但我仍然在寻找更好的 替代品。
由于引用计数,避免副本很复杂,但有 是可能的。这个问题是由于调用者持有参考 到原来的df
,并且子功能通过df = df.<method>
调用创建新实例。为了解决这个问题,我们必须提出df
本身 可变。不幸的是,Python通常不允许改变函数参数的引用 。
解决方案1:朴素可变引用
最简单的方式工作,周围的限制是对df
包装成一个列表 或字典。在这种情况下,子功能可以修改外部参考,例如,由:
df_list[0] = df_list[0].map_partitions(mapper)
df_list[0] = df_list[0].persist()
然而,这在语法上是尴尬,人们必须非常小心,因为 简化的语法通过df = df_list[0]
再创到 标的的期货,这可能会导致数据重复的新引用。
解决方案2:基于包装-可变引用
改进上,人们可以写一个小包装类,其中包含一个参考 到数据帧。通过这个包装,子函数可以改变参考文献 。为了改进语法问题,可以考虑包装器 应该自动地将功能委托给数据帧还是从中继承 。总的来说,这个解决方案也不太合适。
解决方案3:明确突变
为了避免其他的解决方案,我现在更喜欢以下 变种,通过原有的df
的就地改造,有效地模拟了map_partitions
和persist
可变版本的语法问题实例。
def modify_inplace(old_df, new_df):
# Currently requires accessing private fields of a DataFrame, but
# maybe this could be officially supported by Dask.
old_df.dask = new_df.dask
old_df._meta = new_df._meta
old_df._name = new_df._name
old_df.divisions = new_df.divisions
def iterative_algorithm(df, num_iterations):
for iteration in range(num_iterations):
def mapper(df):
# Actual transform logic...
return df
# Simulate mutable/in-place map_partitions
new_df = df.map_partitions(mapper)
modify_inplace(df, new_df)
# Simulate mutable/in-place persist
new_df = df.persist()
modify_inplace(df, new_df)
# Technically no need to return, because all operations were in-place
return df
这工作得相当好,对我来说,需要仔细遵循以下规则:
- 通过上面的图案更换所有不可变的电话像
df = df.<method>
。
- 注意创建对
df
的引用。例如,在调用persist之前,使用像some_col = df["some_sol"]
这样的变量在语法上的方便性需要del some_col
。否则,以some_col
存储的引用将再次导致数据重复。
你会想在你的'modify_inplace'函数中加入'df.divisions' – MRocklin