Julia:将DataFrame传递给函数会创建一个指向DataFrame的指针吗?

时间:2015-01-20 03:34:45

标签: dataframe normalization julia

我有一个函数,我在其中规范化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" |

1 个答案:

答案 0 :(得分:11)

朱莉娅使用的行为称为"传递共享"。从文档(强调我的):

  

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

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

norm_df = deepcopy(input_df)

Julia通常会要求你明确地做这些事情,因为创建一个大型数据框架的独立副本可能是计算上昂贵的,而Julia是一种面向性能的语言。

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

  

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

     

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

类型DataFrame类似于数组,因此deepcopy是必需的。

相关的SO问题是here