Open7

Juliaでデータ加工いろいろ

yuuyuu

Base.jl

findall()を使った配列の抽出方法

item_set = ["a", "b", "c"]
prob_set = [0.1, 0.2, 0.7]

prob_set[findall(==("a"), item_set)] .*= 2

println(prob_set)
#> [0.2, 0.2, 0.7]
yuuyuu

juliaのfind関数を整理

  • argmin() / argmax()は値が最も小さい/大きい場所のインデックスを返す.
  • findmin() / findmax()は小さい値とインデックスを返す
  • extrema()は最も小さい値と大きい値を返すので、rのrange()関数と同じ
  • findfirst() / findlast()は条件を満たす最初の/最後のインデックスを返す
  • findall()は条件を満たすすべてのインデックスを返す
  • findnext()は検索開始位置を指定して、そのあとに条件を満たすインデックスを返す
  • findprev()はfindnext()の反対
x = [3, 7, 4, 5, 10, 3, 12, 3, 2, 4]
println(argmin(x))
#> 9 # return index
println(findmin(x))
#> (2, 9) # return value and index: tuple
println(extrema(x))
#> (2, 12) #return values (min, max): tuple
println(findfirst(x .== 3))
#> 1 # return index
println(findall(x .== 3))
#> [1, 6, 8]

x = [1, 1, 1, 3, 4]
println(findnext(x .== 1, 2))
#> 2 # return index

配列に対しても可能

x = [1 2 3; 3 5 6]
argmax(x)
#> CartesianIndex(2, 3)
findmin(x)
#> (1, CartesianIndex(1, 1))
findall(x .== 3)
#> 2-element Vector{CartesianIndex{2}}:
#>  CartesianIndex(2, 1)
#>  CartesianIndex(1, 3)

findnext()関数を配列に対して使うと注意が必要?
6から検索開始して、得られたのは、(3,3)なので、
一方向にしか検索しないのではないか

x = [1 2 3; 
    3 5 6; 
    3 8 3]
findnext(x .== 3, CartesianIndex(2, 3))
#> CartesianIndex(3, 3)

x = [1 2 4; 
    3 5 3; 
    3 8 3]
findnext(x .== 3, CartesianIndex(1, 3))
#> CartesianIndex(2, 3)

参考サイト)

yuuyuu

.を使った書き方はブロードキャストを使った書き方なので、それをしない場合は下記のように

a = [2, 1, 3]
findall(x->x==minimum(a), a)
#> 1-element Vector{Int64}:
#> 2
yuuyuu
a = [2, 1, 3]
findall(==(minimum(a)), a)
#> 1-element Vector{Int64}:
#> 2

のようにも書ける

findall(==minimum(a), a)のように書くと、下記のようなエラーがでてしまう

syntax: "==" is not a unary operator

文字列に対しても

item_set = ["a", "b", "c"]
findall(==("b"), item_set)
#> 1-element Vector{Int64}:
#> 2

のように書くことでシンプルに書くことができる

findall(isequal("b"), item_set)

とすると、さらにわかりやすい

yuuyuu

mutate(col = case_when(a == 1 ~ 0, TRUE ~ 1))をjuliaで書く方法

シンプルな ifelse() チェーン

d_sample = DataFrame(
    a = 1:3,
    b = 2:4,
    c = ["a", "b", "c"]
)

d_sample.a = ifelse.(
    (d_sample.c .== "a") .& (d_sample.b .== 2), 5, d_sample.a
)

複雑なら関数に切り出して .() で各行に適用


  • DataFramesMeta.jlの@rtransform or @transform で行う
using DataFramesMeta
d_sample = DataFrame(
    a = 1:3,
    b = 2:4,
    c = ["a", "b", "c"]
)

d_sample = @chain d_sample begin
    @rtransform :d = ifelse(
        :c == "c" && :b == 4, 1,
        :c == "a" && :b == 2 ? 2 : 0
    )
end