【问题标题】:Checking elements in multiple columns of Dataframe in Julia在 Julia 中检查 Dataframe 多列中的元素
【发布时间】:2021-01-12 16:40:05
【问题描述】:

我有一个关于在操作 DataFrame 时在任何循环中使用条件的问题。

例如, 我有一个数据框

df:

a b c

1 2 5
3 4 3
2 1 7
6 3 6
5 1 9

我正在尝试编写一个带有条件的循环,该条件一次检查两个列 (a and b),如果值 i 在任一列或两列中可用,那么它应该从列 @987654324 中获取值@ 并将其存储在一个数组中。

使用它我可以稍后执行统计操作,例如查找数组的平均值。

我为这个任务写了一个简化的代码sn-p:

for i in 1:5
  result1 = Float64[]
  result2 = Float64[]
  if (df[:, :a] = i) 
      push!(result1, df[:, :c])
  elseif (df[:, :b] = i)
      push!(result2, df[:, :c])
  end

  unique!(result1)
  unique!(result2)

  result = vcat(result1, result2)

  global mean_val = mean(result)
end

这里,i 值的范围为 1 到 5,对于每个值,a and b 列都将检查其是否存在,如果值存在,则 c 列中的值应推送到受尊重的结果数组。

我尝试过使用来自社区的其他一些建议,例如:

代码示例1:


for i in 1:5
  mean_val = mean(df[:, :c] for i in ("a", "b")
end

代码示例2:

for i in 1:5
  df.row = axes(df, 1)
  mean_val = mean((filter(x->x[:a] == i || x[:b] == i ,df))[:c])
end

但是这些不起作用并返回所需的输出。

请就我在代码中的错误提出建议。 另外,请建议是否有任何文档解释了在语句中实现多个条件以及访问数据框元素以进行 julia 中的任何其他操作。

提前谢谢你

【问题讨论】:

    标签: dataframe loops julia


    【解决方案1】:

    (我认为)您想要实现的第一种方法是使用indexing syntax 获取数据框的子集:

    julia> using DataFrames
    julia> df = DataFrame(a = rand(1:5, 10), b = rand(1:5, 10), c = rand(1:100, 10))
    10×3 DataFrame
     Row │ a      b      c     
         │ Int64  Int64  Int64 
    ─────┼─────────────────────
       1 │     1      2     25
       2 │     5      4     72
       3 │     4      3     37
       4 │     4      3     46
       5 │     3      2     31
       6 │     3      5     43
       7 │     5      1     35
       8 │     5      2     54
       9 │     1      1     64
      10 │     1      4     57
    
    julia> idx = (df.a .== 3) .| (df.b .== 3)
    10-element BitArray{1}:
     0
     0
     1
     1
     1
     1
     0
     0
     0
     0
    
    julia> filtered_c = df[idx, :c]
    4-element Array{Int64,1}:
     37
     46
     31
     43
    

    然后,您可以对生成的过滤值计算所需的任何统计信息:

    julia> using Statistics
    
    julia> mean(filtered_c)
    39.25
    

    做同样事情的另一种方法是使用filter 来过滤你想要保留的行:

    julia> filtered_df = filter(row -> (row.a==3 || row.b==3), df)
    4×3 DataFrame
     Row │ a      b      c     
         │ Int64  Int64  Int64 
    ─────┼─────────────────────
       1 │     4      3     37
       2 │     4      3     46
       3 │     3      2     31
       4 │     3      5     43
    
    # This way of writing things is equivalent to the previous one, but
    # might be more readable in cases where the condition you're checking
    # is more complex
    julia> filtered_df = filter(df) do row
               row.a == 3 || row.b == 3
           end
    4×3 DataFrame
     Row │ a      b      c     
         │ Int64  Int64  Int64 
    ─────┼─────────────────────
       1 │     4      3     37
       2 │     4      3     46
       3 │     3      2     31
       4 │     3      5     43
    
    julia> mean(filtered_df.c)
    39.25
    

    【讨论】:

      【解决方案2】:

      作为对 François Févotte 出色回答的一个小效率说明,这样做会更快:

      julia> filter([:a, :b] => (a,b) -> a == 3 || b == 3, df, view=true)
      4×3 SubDataFrame
       Row │ a      b      c
           │ Int64  Int64  Int64
      ─────┼─────────────────────
         1 │     3      5      1
         2 │     3      5      9
         3 │     4      3     74
         4 │     4      3     63
      

      如果您有一个非常大的数据框。这里有两个区别:

      1. 我使用[:a, :b] => (a,b) -> a == 3 || b == 3 synax,它是类型稳定的(因此它会更快地迭代行);
      2. 我使用view=true 来生成源数据帧的视图,它分配的资源要少得多(这可能对非常大的数据帧很重要);

      以下是您在较大数据框中拥有的不同行子集选项的一个小示例:

      julia> df = DataFrame(a=rand(1:3, 10^8), b=rand(1:3, 10^8), c=rand(10^8));
      
      julia> function test()
                 @time filter(row -> (row.a==3 || row.b==3), df)
                 @time df[(df.a .== 3) .| (df.b .== 3), :]
                 @time @view df[(df.a .== 3) .| (df.b .== 3), :]
                 @time filter([:a, :b] => (a,b) -> a == 3 || b == 3, df)
                 @time filter([:a, :b] => (a,b) -> a == 3 || b == 3, df, view=true)
                 return nothing
             end
      test (generic function with 1 method)
      
      julia> test()
       19.912672 seconds (333.67 M allocations: 6.652 GiB, 5.71% gc time, 0.41% compilation time)
        1.152460 seconds (29 allocations: 1.667 GiB, 14.88% gc time)
        0.515334 seconds (15 allocations: 435.807 MiB, 40.49% gc time)
        1.066756 seconds (412.82 k allocations: 1.689 GiB, 5.56% gc time, 12.54% compilation time)
        0.646710 seconds (382.98 k allocations: 455.835 MiB, 31.27% gc time, 23.02% compilation time)
      
      julia> test()
       18.194791 seconds (333.34 M allocations: 6.635 GiB, 4.87% gc time)
        1.018816 seconds (29 allocations: 1.667 GiB, 15.34% gc time)
        0.469027 seconds (15 allocations: 435.807 MiB, 41.19% gc time)
        0.912572 seconds (30 allocations: 1.667 GiB, 5.32% gc time)
        0.480374 seconds (16 allocations: 435.807 MiB, 41.15% gc time)
      

      【讨论】:

        猜你喜欢
        • 2021-01-17
        • 2021-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-12
        • 1970-01-01
        相关资源
        最近更新 更多