我有一个函数,我在其中规范化DataFrame的前N列。我想返回规范化的DataFrame,但保留原文。然而,似乎该函数也改变了传递的DataFrame!
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" |
答案 0 :(得分:11)
朱莉娅使用的行为称为"传递共享"。从文档(强调我的):
Julia函数参数遵循有时称为“pass-by-sharing”的约定,这意味着值在传递给函数时不会被复制。函数参数本身充当新的变量绑定(可以引用值的新位置),但它们引用的值与传递的值相同。 调用者可以看到函数内可变值(如数组)的修改。这与Scheme,大多数Lisps,Python,Ruby和Perl以及其他动态语言中的行为相同。
在您的特定情况下,您似乎想要做的是为规范化操作创建一个全新且独立的DataFrame。您可以使用deepcopy
执行此操作,例如
norm_df = deepcopy(input_df)
Julia通常会要求你明确地做这些事情,因为创建一个大型数据框架的独立副本可能是计算上昂贵的,而Julia是一种面向性能的语言。
再次从文档中,请注意copy
和deepcopy
之间的以下重要区别:
copy(x)
:创建x的浅表副本:复制外部结构,但不复制所有内部值。例如,复制数组会生成一个与原始数组元素相同的新数组。
deepcopy(x)
:创建x的深层副本:以递归方式复制所有内容,从而生成完全独立的对象。例如,深度复制数组会生成一个新数组,其元素是原始元素的深层副本。
类型DataFrame
类似于数组,因此deepcopy
是必需的。
相关的SO问题是here。