【问题标题】:Creating variable depending on value of another with for loop in Julia DataFrame在 Julia DataFrame 中使用 for 循环根据另一个值创建变量
【发布时间】:2020-11-02 22:27:34
【问题描述】:

我已经关注 Julia 数据帧

    grh  anc     anc1     anc2    anc3     anc4     anc5    anc6     anc7  
1     2    5  0.10000  0.12000  0.1800  0.14000  0.15000  0.1900  0.20000   
2     3    7  0.03299  0.05081  0.0355  0.02884  0.03054  0.0332  0.03115   
3     4    3  0.00000  0.00000  0.0000  0.00000  0.00000  0.0000  0.00000   
4     5    4  0.00000  0.00000  0.0000  0.00000  0.00000  0.0000  0.00000   
5     6    1  0.10000  0.10000  0.1000  0.10000  0.10000  0.1000  0.10000 




       anc8     anc9    anc10  
1   0.10000  0.21000  0.24000  
2   0.02177  0.04903  0.04399  
3   0.00000  0.00000  0.00000  
4   0.00000  0.00000  0.00000  
5   0.10000  0.10000  0.10000 

我想根据变量 anc 的值添加带有 forloop lap1、lap2、...的新列。例如,在第一行,anc=5,所以 lap1 应该等于 anc5 (0.1500) 的值,lap2 等于 anc6 (0.1900)...在第二行 lap1=anc7 (0.03115),lap2=anc8 ( 0.02177),...

所以,输出应该是这样的

grh anc anc1    anc2    anc3    anc4    anc5    anc6    anc7    anc8    anc9    anc10   lap1    lap2    lap3
2   5   0.10000 0.12000 0.18000 0.14000 0.15000 0.19000 0.20000 0.1000  0.21000 0.24000 0.15000 0.19000 0.20000
3   7   0.03299 0.05081 0.0355  0.02884 0.03054 0.0332  0.03115 0.02177 0.04903 0.04399 0.03115 0.02177 0.04903
4   3   0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000
5   4   0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000
6   1   0.10000 0.10000 0.10000 0.10000 0.10000 0.10000 0.10000 0.10000 0.10000 0.10000 0.10000 0.10000 0.10000

我仍然是 Julia 的初学者,如果您有任何想法,我将不胜感激。谢谢

【问题讨论】:

    标签: dataframe for-loop julia


    【解决方案1】:

    这是这样做的方法:

    5×12 DataFrame
    │ Row │ grh   │ anc   │ anc1    │ anc2    │ anc3    │ anc4    │ anc5    │ anc6    │ anc7    │ anc8    │ anc9    │ anc10   │
    │     │ Int64 │ Int64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
    ├─────┼───────┼───────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ 1   │ 2     │ 5     │ 0.1     │ 0.12    │ 0.18    │ 0.14    │ 0.15    │ 0.19    │ 0.2     │ 0.1     │ 0.21    │ 0.24    │
    │ 2   │ 3     │ 7     │ 0.03299 │ 0.05081 │ 0.0355  │ 0.02884 │ 0.03054 │ 0.0332  │ 0.03115 │ 0.02177 │ 0.04903 │ 0.04399 │
    │ 3   │ 4     │ 3     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │
    │ 4   │ 5     │ 4     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │
    │ 5   │ 6     │ 1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │
    
    julia> transform(df, [r"anc" => ByRow((x...) -> x[x[1]+i]) => "lap$i" for i in 1:3])
    5×15 DataFrame
    │ Row │ grh   │ anc   │ anc1    │ anc2    │ anc3    │ anc4    │ anc5    │ anc6    │ anc7    │ anc8    │ anc9    │ anc10   │ lap1    │ lap2    │ lap3    │
    │     │ Int64 │ Int64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
    ├─────┼───────┼───────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ 1   │ 2     │ 5     │ 0.1     │ 0.12    │ 0.18    │ 0.14    │ 0.15    │ 0.19    │ 0.2     │ 0.1     │ 0.21    │ 0.24    │ 0.15    │ 0.19    │ 0.2     │
    │ 2   │ 3     │ 7     │ 0.03299 │ 0.05081 │ 0.0355  │ 0.02884 │ 0.03054 │ 0.0332  │ 0.03115 │ 0.02177 │ 0.04903 │ 0.04399 │ 0.03115 │ 0.02177 │ 0.04903 │
    │ 3   │ 4     │ 3     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │
    │ 4   │ 5     │ 4     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │
    │ 5   │ 6     │ 1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │
    

    (我保留宽输出不截断任何列)

    在代码中,我假设您只想生成 :lap1:lap2:lap3 列,这意味着应该允许 anc 最多取值 8(如果它是 9 或更多你会在代码中得到一个错误,因为没有源可以从中获取数据)。

    理解其工作原理的关键是解析:

    [r"anc" => ByRow((x...) -> x[x[1]+i]) => "lap$i" for i in 1:3]
    

    理解意味着我们将为i创建三个变量,范围从13。所以让我们解决例如i=1。现在:

    • r"anc" 意味着我们会将所有名称中包含"anc" 的列按照它们在数据框中的出现顺序传递给我们的函数(因此首先是"anc",然后是后缀从1 到@987654335 的列@)。这些值将作为位置参数传递
    • 然后ByRow((x...) -> x[x[1]+i]) 表示我们定义了一个函数,它将逐行传递数据,(x...) -> 部分表示x 将是一个包含传递的位置参数的元组,因为我们知道"anc" 是拳头我们将其称为x[1] 的列,然后将i 添加到其中以获得我们感兴趣的列;
    • 最后"lap$i" 为我们提供了输出变量的名称

    另一种写法是:

    julia> transform(df, [AsTable(r"anc") => ByRow(x -> x[Symbol("anc", x.anc+i-1)]) => "lap$i" for i in 1:3])
    5×15 DataFrame
    │ Row │ grh   │ anc   │ anc1    │ anc2    │ anc3    │ anc4    │ anc5    │ anc6    │ anc7    │ anc8    │ anc9    │ anc10   │ lap1    │ lap2    │ lap3    │
    │     │ Int64 │ Int64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
    ├─────┼───────┼───────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ 1   │ 2     │ 5     │ 0.1     │ 0.12    │ 0.18    │ 0.14    │ 0.15    │ 0.19    │ 0.2     │ 0.1     │ 0.21    │ 0.24    │ 0.15    │ 0.19    │ 0.2     │
    │ 2   │ 3     │ 7     │ 0.03299 │ 0.05081 │ 0.0355  │ 0.02884 │ 0.03054 │ 0.0332  │ 0.03115 │ 0.02177 │ 0.04903 │ 0.04399 │ 0.03115 │ 0.02177 │ 0.04903 │
    │ 3   │ 4     │ 3     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │
    │ 4   │ 5     │ 4     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │ 0.0     │
    │ 5   │ 6     │ 1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │ 0.1     │
    

    不同之处在于AsTable 使x 成为NamedTuple,因此我们可以使用作为x.ancSymbols 传递的列名来索引x,如x[Symbol("anc", x.anc+i-1)]


    编辑

    如果您想以牺牲代码复杂性为代价获得更快的速度,您可以编写:

    m = Matrix(df[!, 3:end])
    v = df.anc
    insertcols!(df, ["lap$k" => getindex.(Ref(m), axes(df, 1), v .+ k .- 1) for k in 1:3]...)
    

    【讨论】:

    • 非常感谢您的详细回答。即使速度很慢,它也能正常工作。
    • 有什么方法可以向量化计算而不是逐行应用?
    • 1) ByRow 已经矢量化。 2)像往常一样在 Julia 中,您可以以更复杂的代码为代价来加快速度。我更新了你怎么做的答案。例如。请注意,NamedTuple 的示例显然必须很慢,因为它做了很多字符串操作,但好处是它可能最清楚发生了什么。
    • 好的,确实稍微不那么可重复但确实更快。不确定是否真正理解“Ref”一词的工作原理,但我会搜索。再次感谢您的帮助。
    • Ref 意味着m 应该“保持原样”,因为没有Ref 它将被广播(所以Ref 是广播机制的一种信号,即对象包裹在其中不应该被迭代,而是在每次迭代中“按原样”馈送)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 2021-12-06
    • 2015-12-26
    • 1970-01-01
    • 2019-07-31
    • 2018-03-05
    相关资源
    最近更新 更多