DataFrame.merge()中copy = False的确切缺点是什么?

mor*_*ein 18 python pandas

我对论点有点糊涂copyDataFrame.merge()后一个同事问我这个问题.

的文档字符串DataFrame.merge()状态:

copy : boolean, default True
    If False, do not copy data unnecessarily
Run Code Online (Sandbox Code Playgroud)

大熊猫文档状态:

copy:始终True从传递的DataFrame对象复制数据(默认),即使不需要重建索引也是如此.在许多情况下无法避免,但可能会提高性能/内存使用率.可以避免复制的情况在某种程度上是病态的,但仍然提供了这种选择.

文档字符串意味着复制数据不是必需的,并且几乎总是可以跳过.另一方面,该文件说,在许多情况下无法避免复制数据.

我的问题是:

  • 这些案件是什么?
  • 有什么缺点?

And*_*eak 16

免责声明:我对大熊猫不是很有经验,这是我第一次挖掘它的来源,所以我不能保证我在下面的评估中没有遗漏任何东西.

最近重构了相关的代码位.我将根据当前稳定版本0.20讨论该主题,但我不怀疑与早期版本相比的功能变化.

调查始于merge在大熊猫/核心/重塑/ merge.py(原熊猫/工具/ merge.py).忽略一些doc-aware装饰器:

def merge(left, right, how='inner', on=None, left_on=None, right_on=None,
          left_index=False, right_index=False, sort=False,
          suffixes=('_x', '_y'), copy=True, indicator=False):
    op = _MergeOperation(left, right, how=how, on=on, left_on=left_on,
                         right_on=right_on, left_index=left_index,
                         right_index=right_index, sort=sort, suffixes=suffixes,
                         copy=copy, indicator=indicator)
    return op.get_result()
Run Code Online (Sandbox Code Playgroud)

调用merge会将copy参数传递给_MergeOperation的构造函数,然后调用其get_result()方法.带有上下文的前几行:

# TODO: transformations??
# TODO: only copy DataFrames when modification necessary
class _MergeOperation(object):
    [...]
Run Code Online (Sandbox Code Playgroud)

现在第二条评论非常可疑.继续前进,copykwarg 绑定了一个同名的实例属性,它似乎只在类中重新出现一次:

result_data = concatenate_block_managers(
    [(ldata, lindexers), (rdata, rindexers)],
    axes=[llabels.append(rlabels), join_index],
    concat_axis=0, copy=self.copy)
Run Code Online (Sandbox Code Playgroud)

然后,我们可以跟踪concatenate_block_managers在大熊猫/核心/ internals.py功能,仅仅通过对copykwarg来concatenate_join_units.

我们到达原始copy关键字参数的最后安息点concatenate_join_units:

if len(to_concat) == 1:
    # Only one block, nothing to concatenate.
    concat_values = to_concat[0]
    if copy and concat_values.base is not None:
        concat_values = concat_values.copy()
else:
    concat_values = _concat._concat_compat(to_concat, axis=concat_axis)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,唯一copy能做的就是concat_values在连接的特殊情况下将此处的副本重新绑定到相同的名称,而实际上没有任何内容可以连接.

现在,在这一点上,我缺乏熊猫知识开始显示,因为我不确定调用堆栈内部究竟发生了什么.但与上述热山芋方案copy中的串联作用的是无操作状分支结束关键字参数与上面的"TODO"的评论中,完全一致的问题,引用文档:

copy:始终从传递的DataFrame对象复制数据(默认为True),即使不需要重建索引也是如此.在许多情况下无法避免,但可能会提高性能/内存使用率.可以避免复制的情况在某种程度上是病态的,但仍然提供了这种选择.

(强调我的),以及对旧问题相关讨论:

IIRC我认为复制参数在这里只是一个简单的合并,你实际上想要它被复制(我喜欢带有相同索引的reindex)

基于这些提示,我怀疑在绝大多数实际用例中复制是不可避免的,并且copy从不使用关键字参数.然而,由于少数例外跳过副本的步骤可能会提高性能(不会导致任何性能影响任何为广大的用例的平均时间),选择实施.

我怀疑的理由是这样的:如果不这样做,除非必要的副本(只可能在一个非常特殊的少数情况下)的好处是,代码避免这种情况下,一些内存分配和拷贝,但不能返回副本在非常特殊的情况下,如果不希望变异的返回值merge以任何方式影响原始数据帧,可能会导致意外的意外.因此,copy关键字参数的默认值是True,因此用户只有在merge明确志愿为此时才会获得副本(但即便如此,他们仍然可能最终获得副本).