将 "any" 或 "all" 函数逐行应用于 Julia DataFrames.jl 中任意数量的布尔列

Apply "any" or "all" function row-wise to arbitrary number of Boolean columns in Julia DataFrames.jl

假设我有一个数据框,其中包含代表特定条件的多个布尔列:

df = DataFrame(
         id = ["A", "B", "C", "D"], 
         cond1 = [true, false, false, false], 
         cond2 = [false, false, false, false], 
         cond3 = [true, false, true, false]
)
id cond1 cond2 cond3
1 A 1 0 1
2 B 0 0 0
3 C 0 0 1
4 D 0 0 0

现在假设我想识别满足这些条件中的任何一个的行,即“A”和“C”。明确地做到这一点很容易:

df[:, :all] = df.cond1 .| df.cond2 .| df.cond3

但是当存在任意数量的条件时如何做到这一点,例如:

df[:, :all] = any.([ df[:, Symbol("cond$i")] for i in 1:3 ])

上面的 DimensionMismatch("tried to assign 3 elements to 4 destinations") 失败了,因为 any 函数是按列应用的,而不是按行应用的。所以真正的问题是:如何将 any 按行应用于数据框中的多个布尔列?

理想的输出应该是:

id cond1 cond2 cond3 all
1 A 1 0 1 1
2 B 0 0 0 0
3 C 0 0 1 1
4 D 0 0 0 0

这是一种方法:

julia> df = DataFrame(
                id = ["A", "B", "C", "D", "E"],
                cond1 = [true, false, false, false, true],
                cond2 = [false, false, false, false, true],
                cond3 = [true, false, true, false, true]
       )
5×4 DataFrame
 Row │ id      cond1  cond2  cond3
     │ String  Bool   Bool   Bool
─────┼─────────────────────────────
   1 │ A        true  false   true
   2 │ B       false  false  false
   3 │ C       false  false   true
   4 │ D       false  false  false
   5 │ E        true   true   true

julia> transform(df, AsTable(r"cond") .=> ByRow.([maximum, minimum]) .=> [:any, :all])
5×6 DataFrame
 Row │ id      cond1  cond2  cond3  any    all
     │ String  Bool   Bool   Bool   Bool   Bool
─────┼───────────────────────────────────────────
   1 │ A        true  false   true   true  false
   2 │ B       false  false  false  false  false
   3 │ C       false  false   true   true  false
   4 │ D       false  false  false  false  false
   5 │ E        true   true   true   true   true

请注意,即使对于非常宽的表格,它也非常快:

julia> df = DataFrame(rand(Bool, 10_000, 10_000), :auto);

julia> @time transform(df, AsTable(r"x") .=> ByRow.([maximum, minimum]) .=> [:any, :all]);
  0.059275 seconds (135.41 k allocations: 103.038 MiB)

在示例中我使用了正则表达式列选择器,当然您可以使用任何您喜欢的行选择器。