Dataframe 朱莉娅:将数据帧传递给函数会创建指向该数据帧的指针?

Dataframe 朱莉娅:将数据帧传递给函数会创建指向该数据帧的指针?,dataframe,normalization,julia,Dataframe,Normalization,Julia,我有一个函数,其中我规范化了数据帧的前N列。我想返回规范化的数据帧,但不返回原始数据帧。然而,该函数似乎也改变了传递的数据帧 using DataFrames function normalize(input_df::DataFrame, cols::Array{Int}) norm_df = input_df for i in cols norm_df[i] = (input_df[i] - minimum(input_df[i])) /

我有一个函数,其中我规范化了数据帧的前N列。我想返回规范化的数据帧,但不返回原始数据帧。然而,该函数似乎也改变了传递的数据帧

using DataFrames

function normalize(input_df::DataFrame, cols::Array{Int})
    norm_df = input_df
    for i in cols
        norm_df[i] = (input_df[i] - minimum(input_df[i])) / 
            (maximum(input_df[i]) - minimum(input_df[i]))
    end
    norm_df
end

using RDatasets
iris = dataset("datasets", "iris")
println("original df:\n", head(iris))

norm_df = normalize(iris, [1:4]);
println("should be the same:\n", head(iris))
输出:

original df:
6x5 DataFrame
| Row | SepalLength | SepalWidth | PetalLength | PetalWidth | Species  |
|-----|-------------|------------|-------------|------------|----------|
| 1   | 5.1         | 3.5        | 1.4         | 0.2        | "setosa" |
| 2   | 4.9         | 3.0        | 1.4         | 0.2        | "setosa" |
| 3   | 4.7         | 3.2        | 1.3         | 0.2        | "setosa" |
| 4   | 4.6         | 3.1        | 1.5         | 0.2        | "setosa" |
| 5   | 5.0         | 3.6        | 1.4         | 0.2        | "setosa" |
| 6   | 5.4         | 3.9        | 1.7         | 0.4        | "setosa" |

should be the same:
6x5 DataFrame
| Row | SepalLength | SepalWidth | PetalLength | PetalWidth | Species  |
|-----|-------------|------------|-------------|------------|----------|
| 1   | 0.222222    | 0.625      | 0.0677966   | 0.0416667  | "setosa" |
| 2   | 0.166667    | 0.416667   | 0.0677966   | 0.0416667  | "setosa" |
| 3   | 0.111111    | 0.5        | 0.0508475   | 0.0416667  | "setosa" |
| 4   | 0.0833333   | 0.458333   | 0.0847458   | 0.0416667  | "setosa" |
| 5   | 0.194444    | 0.666667   | 0.0677966   | 0.0416667  | "setosa" |
| 6   | 0.305556    | 0.791667   | 0.118644    | 0.125      | "setosa" |

朱莉娅使用了一种被称为“传递共享”的行为。从文档(我的重点):

Julia函数参数遵循一种有时称为“通过共享传递”的约定,这意味着值在传递给函数时不会被复制。函数参数本身充当新的变量绑定(可以引用值的新位置),但它们引用的值与传递的值相同。调用方可以看到在函数中对可变值(如数组)所做的修改。这与Scheme、大多数Lisp、Python、Ruby和Perl以及其他动态语言中的行为相同

在您的特定情况下,您似乎想要做的是为规范化操作创建一个全新的独立数据帧。您可以使用
deepcopy
执行此操作,例如:

norm_df = deepcopy(input_df)
Julia通常会要求您显式地执行这类操作,因为创建大型数据帧的独立副本在计算上可能非常昂贵,而且Julia是一种面向性能的语言

再次从文档中,注意
copy
deepcopy
之间的以下重要区别:

copy(x)
:创建x的浅层副本:复制外部结构,但不复制所有内部值。例如,复制数组会生成一个新数组,该数组的元素与原始数组的元素相同

deepcopy(x)
:创建x的深度副本:所有内容都以递归方式复制,从而生成完全独立的对象。例如,深度复制数组会生成一个新数组,其元素是原始元素的深度副本

类型
DataFrame
类似于数组,因此需要
deepcopy


一个相关的SO问题是。

谢谢!那么在哪种情况下是复制对象还是深度复制?例如,如果我这样做,
iris2=iris
,然后将
iris2
传递给
normalize()
,那么
iris
是否也会被修改?@AlexanderFlyax是的,
iris
会被修改。通常,任何形式的
y=x
操作都不会创建新的独立对象,无论其类型如何(尽管有趣的是,对于向量,
y=x[1:end]
将(我认为)创建一个独立对象)。对于像
Int64
这样的具体类型,
copy
将创建一个新的独立对象,但是对于
Array{Int64}
copy
只创建一个独立的外部结构,而不创建独立的内部元素,因此在处理数组时需要
deepcopy
DataFrame
类似于数组,因此需要使用
deepcopy
。感谢您的解释。我不是想批评Julia,只是想理解:如果修改副本会修改原始数组,为什么我需要制作数组的副本?如果我想修改原始数组,我会这么做,不是吗?也就是说,它充其量是多余的,充其量是适得其反的。“我错过什么了吗?”亚历山大·弗利克斯问得好。我不知道!我的最佳猜测是,它是围绕作用域展开的,即在某些情况下,在一个作用域中有一组引用(例如调用函数),同时在不同的作用域中也有一组独立的引用(例如被调用函数),这是很有用的,但这两组引用都指向内存中的同一对象。请不要把这当作福音。也许你可以把这个问题作为一个新的问题提出来(不一定非得针对茱莉亚),然后得到更明智的回答。。。