M.Hiroi's Home Page

Julia Language Programming

お気楽 Julia プログラミング超入門


Copyright (C) 2021-2026 Makoto Hiroi
All rights reserved.

線形代数編

●複素数

今回は Julia の複素数について簡単にまとめてみました。

julia> complex(1, 2)
1 + 2im

julia> complex(1.0, 2)
1.0 + 2.0im

julia> complex(1.0)
1.0 + 0.0im

julia> typeof(1 + 2im)
Complex{Int64}

julia> typeof(1.0 + 2im)
Complex{Float64}

julia> a = 1 + 2im
1 + 2im

julia> b = 1 - im
1 - 1im

julia> a + b
2 + 1im

julia> a - b
0 + 3im

julia> a * b
3 + 1im

julia> a / b
-0.5 + 1.5im

julia> a * a
-3 + 4im

julia> a ^ 2
-3 + 4im

julia> a == a
true

julia> a != a
false

julia> a != b
true

julia> real(a)
1

julia> imag(a)
2

julia> abs(a)
2.23606797749979

julia> abs2(a)
5

julia> abs(b)
1.4142135623730951

julia> abs2(b)
2

julia> angle(a)
1.1071487177940904

julia> angle(b)
-0.7853981633974483

julia> cis(0)
1.0 + 0.0im

julia> cis(pi/4)
0.7071067811865476 + 0.7071067811865475im

julia> cis(pi/2)
6.123233995736766e-17 + 1.0im

julia> cis(pi)
-1.0 + 1.2246467991473532e-16im

julia> cis(angle(a))
0.44721359549995804 + 0.8944271909999159im

julia> cis(angle(b))
0.7071067811865476 - 0.7071067811865475im

julia> sqrt(-1 + 0im)
0.0 + 1.0im

julia> sqrt(-2 + 0im)
0.0 + 1.4142135623730951im

julia> sqrt(-1 + 0im) ^ 2
-1.0 + 0.0im

julia> sqrt(-2 + 0im) ^ 2
-2.0000000000000004 + 0.0im

julia> exp(complex(0, pi/4))
0.7071067811865476 + 0.7071067811865475im

julia> exp(complex(0, pi)) + 1
0.0 + 1.2246467991473532e-16im

●複素ベクトル

julia> using LinearAlgebra

julia> a = [1 + 2im, 3 + 4im]
2-element Vector{Complex{Int64}}:
 1 + 2im
 3 + 4im

julia> b = [5 + 6im, 7 + 8im]
2-element Vector{Complex{Int64}}:
 5 + 6im
 7 + 8im

julia> conj.(a)
2-element vector{Complex{Int64}}:
 1 - 2im
 3 - 4im

julia> conj.(b)
2-element Vector{Complex{Int64}}:
 5 - 6im
 7 - 8im

julia> a + b
2-element Vector{Complex{Int64}}:
  6 + 8im
 10 + 12im

julia> a - b
2-element Vector{Complex{Int64}}:
 -4 - 4im
 -4 - 4im

julia> a .* b
2-element Vector{Complex{Int64}}:
  -7 + 16im
 -11 + 52im

julia> a ./ b
2-element Vector{Complex{Float64}}:
 0.2786885245901639 + 0.06557377049180328im
 0.4690265486725664 + 0.035398230088495575im

julia> a .+ c
2-element Vector{Complex{Int64}}:
 2 + 1im
 4 + 3im

julia> a .- c
2-element Vector{Complex{Int64}}:
 0 + 3im
 2 + 5im

julia> a .* c
2-element Vector{Complex{Int64}}:
 3 + 1im
 7 + 1im

julia> a ./ c
2-element Vector{Complex{Float64}}:
 -0.5 + 1.5im
 -0.5 + 3.5im

julia> dot(a, b)
70 - 8im

julia> dot(b, a)
70 + 8im

julia> dot(a, a)
30 + 0im

julia> dot(b, b)
174 + 0im

julia> norm(a)
5.477225575051661

julia> norm(b)
13.19090595827292

●複素行列

julia> a = [1+1im 1-1im; 2+3im 2+1im]
2×2 Matrix{Complex{Int64}}:
 1+1im  1-1im
 2+3im  2+1im

julia> transpose(a)
2×2 transpose(::Matrix{Complex{Int64}}) with eltype Complex{Int64}:
 1+1im  2+3im
 1-1im  2+1im

julia> a'
2×2 adjoint(::Matrix{Complex{Int64}}) with eltype Complex{Int64}:
 1-1im  2-3im
 1+1im  2-1im

julia> adjoint(a)
2×2 adjoint(::Matrix{Complex{Int64}}) with eltype Complex{Int64}:
 1-1im  2-3im
 1+1im  2-1im

julia> a''
2×2 Matrix{Complex{Int64}}:
 1+1im  1-1im
 2+3im  2+1im

julia> b = [1+0im 1+1im; 1-1im 0+1im]
2×2 Matrix{Complex{Int64}}:
 1+0im  1+1im
 1-1im  0+1im

julia> (a + b)'
2×2 adjoint(::Matrix{Complex{Int64}}) with eltype Complex{Int64}:
 2-1im  3-2im
 2+0im  2-2im

julia> a' + b'
2×2 Array{Matrix{Int64}}:
 2-1im  3-2im
 2+0im  2-2im

julia> c = 1 - 1im
1 - 1im

julia> (c .* a)'
2×2 adjoint(::Matrix{Complex{Int64}}) with eltype Complex{Int64}:
 2+0im  5-1im
 0+2im  3+1im

julia> conj(c) .* a'
2×2 Matrix{Complex{Int64}}:
 2+0im  5-1im
 0+2im  3+1im

julia> (a * b)'
2×2 adjoint(::Matrix{Complex{Int64}}) with eltype Complex{Int64}:
 1+1im   5-2im
 1-3im  -2-7im

julia> b' * a'
2×2 Matrix{Complex{Int64}}:
 1+1im   5-2im
 1-3im  -2-7im

julia> det(a)
-4.0 + 2.0000000000000004im

julia> det(a')
-4.0 - 2.0im

julia> conj(det(a))
-4.0 - 2.0000000000000004im

julia> inv(a)
2×2 Matrix{Complex{Float64}}:
 -0.3-0.4im   0.3-0.1im
  0.1+0.8im  -0.1-0.3im

julia> inv(a)'
2×2 adjoint(::Matrix{ComplexF64}) with eltype ComplexF64:
 -0.3+0.4im   0.1-0.8im
  0.3+0.1im  -0.1+0.3im

julia> inv(a')
2×2 adjoint(::Matrix{ComplexF64}) with eltype ComplexF64:
 -0.3+0.4im   0.1-0.8im
  0.3+0.1im  -0.1+0.3im

julia> u = [1+2im, 3+4im]
2-element Vector{Complex{Int64}}:
 1 + 2im
 3 + 4im

julia> v = [5+6im, 7+8im]
2-element Vector{Complex{Int64}}:
 5 + 6im
 7 + 8im

julia> a * u
2-element Vector{Complex{Int64}}:
  6 + 4im
 -2 + 18im

julia> dot(a * u, v)
184 - 126im

julia> dot(u, a' * v)
184 - 126im

初版 2021 年 11 月 13 日
改訂 2012 年 12 月 5 日

Julia の基礎知識

●DataFrames.jl

DataFrames.jl は、Julia で二次元の表形式データを効率的に扱うためのライブラリです。各列は異なる型 (数値、文字列、ブール値など) を保持でき、列ごとに名前 (シンボル) を付けることができます。Julia 本体の性能を活かし、大規模なデータセットに対しても高速な計算や統計解析が可能です。また、ライブラリ CSV.jl を使えば、CSV 形式のファイルの読み書きも簡単に行うことができます。

今回は DataFrames.jl の基本的な使い方を簡単に説明します。

●インストール

Julia のパッケージモード (REPL で ] キーを押す) で次のコマンドを実行します。

(@v1.12) pkg> add DataFrames

(@v1.12) pkg> add CSV

DataFrames と CSV をインストールします。インストール終了後 st で状態を表示すると、M.Hiroi の環境では次のように表示されます。

(@v1.12) pkg> st
Status `~/.julia/environments/v1.12/Project.toml`
  [336ed68f] CSV v0.10.16
  [a93c6f00] DataFrames v1.8.2
  [91a5bcdd] Plots v1.41.6
  [f3b207a7] StatsPlots v0.15.8

インストールが終了したら、Backspace または Ctrl + C を押してください。通常の julia> プロンプトに戻ります。

●データフレームの生成

データフレームはコンストラクタ DataFrame() で生成します。列ごとにデータを指定して作成するのが一般的です。

DataFrame() : 空のデータフレームを生成
DataFrame(x=type, ...) : 列名 x とデータ型 type を指定
DataFrame(x=data, ...) : 列名 x とデータ data (vector, range, or constan) を指定
DataFrame("x" => data, ...) : 列名 x とデータをペアで指定する
DataFrame([(x=1, y=2), (x=3, y=4), ...]) : 行データ (名前付きタプル) を格納したベクタで指定する
DataFrame(matrix, [:x, :y, ...]) : 行列と列名を格納したベクタ (または :auto) を指定する

列名 = data 以外の方法でデータを指定する場合、列名には文字列またはシンボルを使います。簡単な使用例を示します。

julia> using DataFrames

julia> DataFrame()
0×0 DataFrame

julia> DataFrame(x=Int64[], y=Float64[])
0×2 DataFrame
 Row │ x      y
     │ Int64  Float64
───┴─────────

julia> DataFrame(x=["foo","bar","baz"], y=[10,20,30], z=0.0)
3×3 DataFrame
 Row │ x       y      z
     │ String  Int64  Float64
───┼──────────────
   1 │ foo        10      0.0
   2 │ bar        20      0.0
   3 │ baz        30      0.0

julia> DataFrame([(x=11, y=12), (x=13, y=14)])
2×2 DataFrame
 Row │ x      y
     │ Int64  Int64
───┼────────
   1 │    11     12
   2 │    13     14

julia> DataFrame(rand(3,3), :auto)
3×3 DataFrame
 Row │ x1          x2        x3
     │ Float64     Float64   Float64
───┼────────────────────
   1 │ 0.00647265  0.175429  0.668197
   2 │ 0.655034    0.936949  0.00115477
   3 │ 0.90156     0.461149  0.968727

データフレーム df の要素は df[row, col] で求めることができます。また、行数・列数は関数 nrow(df), ncol(df), size(df) で取得することができます。

julia> df = DataFrame(
           Name = ["Alice", "Bob", "Charlie"],
           Age = [25, 30, 35],
           Score = [85.5, 92.0, 78.0]
       )
3×3 DataFrame
 Row │ Name     Age    Score
     │ String   Int64  Float64
───┼───────────────
   1 │ Alice       25     85.5
   2 │ Bob         30     92.0
   3 │ Charlie     35     78.0

julia> df[1, :Name]
"Alice"

julia> df[2, :Score]
92.0

julia> nrow(df)
3

julia> ncol(df)
3

julia> size(df)
(3, 3)

列名を取得するには関数 names(df), propertynames(df) を使います。

julia> names(df)
3-element Vector{String}:
 "Name"
 "Age"
 "Score"

julia> propertynames(df)
3-element Vector{Symbol}:
 :Name
 :Age
 :Score

関数 describe(df) は各列の統計量 (平均、最小、最大など) を表示します。

julia> describe(df)
3×7 DataFrame
 Row │ variable  mean     min    median  max      nmissing  eltype
     │ Symbol    Union…   Any    Union…  Any      Int64     DataType
───┼─────────────────────────────────────
   1 │ Name               Alice          Charlie         0  String
   2 │ Age       30.0     25     30.0    35              0  Int64
   3 │ Score     85.1667  78.0   85.5    92.0            0  Float64

●ファイル入出力

CSV.jl を使うと、CSV 形式のファイルを簡単に読み書きすることができます。

読み込み: df = CSV.read("data.csv", DataFrame)
書き出し: CSV.write("output.csv", df)

簡単な使用例を示します。

julia> df
3×3 DataFrame
 Row │ Name     Age    Score
     │ String   Int64  Float64
───┼────────────────
   1 │ Alice       25     85.5
   2 │ Bob         30     92.0
   3 │ Charlie     35     78.0

julia> using CSV

julia> CSV.write("testdat.csv", df)
"testdat.csv"

julia> df1 = CSV.read("testdat.csv", DataFrame)
3×3 DataFrame
 Row │ Name     Age    Score
     │ String7  Int64  Float64
───┼───────────────
   1 │ Alice       25     85.5
   2 │ Bob         30     92.0
   3 │ Charlie     35     78.0

●行と列の取得

関数 first(df, N) はデータフレームの先頭から N 行、関数 last(df, N) は末尾から N 行取り出します。df[M:N, :] は M 〜 N 行目を取り出します。M : N だけではなく、配列のような Indexing も可能です。

julia> first(df, 2)
2×3 DataFrame
 Row │ Name    Age    Score
     │ String  Int64  Float64
───┼──────────────
   1 │ Alice      25     85.5
   2 │ Bob        30     92.0

julia> last(df, 2)
2×3 DataFrame
 Row │ Name     Age    Score
     │ String   Int64  Float64
───┼──────────────
   1 │ Bob         30     92.0
   2 │ Charlie     35     78.0

julia> df[1:2, :]
2×3 DataFrame
 Row │ Name    Age    Score
     │ String  Int64  Float64
───┼──────────────
   1 │ Alice      25     85.5
   2 │ Bob        30     92.0

julia> df[[3, 1], :]
2×3 DataFrame
 Row │ Name     Age    Score
     │ String   Int64  Float64
───┼──────────────
   1 │ Charlie     35     78.0
   2 │ Alice       25     85.5

列を取得するには df.Name, df[:, :Name] を使います。複数の列を指定する場合は、ベクタに列名を格納して渡します。

julia> df.Name
3-element Vector{String}:
 "Alice"
 "Bob"
 "Charlie"

julia> df[:, :Age]
3-element Vector{Int64}:
 25
 30
 35

julia> df[:, [:Name, :Age]]
3×2 DataFrame
 Row │ Name     Age
     │ String   Int64
───┼─────────────
   1 │ Alice       25
   2 │ Bob         30
   3 │ Charlie     35

行や列を取得するとき、データはコピーされます。ただし、列を取得するとき、: のかわりに ! を用いると、データをコピーせずにビュー (view) を生成して返します。

julia> df1 = df[:, :Name]
3-element Vector{String}:
 "Alice"
 "Bob"
 "Charlie"

julia> df1[1] = "ALICE"
"ALICE"

julia> df1
3-element Vector{String}:
 "ALICE"
 "Bob"
 "Charlie"

julia> df
3×3 DataFrame
 Row │ Name     Age    Score
     │ String   Int64  Float64
───┼───────────────
   1 │ Alice       25     85.5
   2 │ Bob         30     92.0
   3 │ Charlie     35     78.0

julia> df2 = df[!, :Name]
3-element Vector{String}:
 "Alice"
 "Bob"
 "Charlie"

julia> df2[1] = "ALICE"
"ALICE"

julia> df2
3-element Vector{String}:
 "ALICE"
 "Bob"
 "Charlie"

julia> df
3×3 DataFrame
 Row │ Name     Age    Score
     │ String   Int64  Float64
───┼───────────────
   1 │ ALICE       25     85.5
   2 │ Bob         30     92.0
   3 │ Charlie     35     78.0

●select() と filter()

列の取得は関数 select(), select!() を使って行うこともできます。

select() は引数のデータフレーム df をコピーし、select!() は df を破壊的に修正します。

julia> select(df, :Name)
3×1 DataFrame
 Row │ Name
     │ String
───┼─────
   1 │ Alice
   2 │ Bob
   3 │ Charlie

julia> select(df, [:Name, :Age])
3×2 DataFrame
 Row │ Name     Age
     │ String   Int64
───┼──────────
   1 │ Alice       25
   2 │ Bob         30
   3 │ Charlie     35

julia> select(df, [:Name, :Score])
3×2 DataFrame
 Row │ Name     Score
     │ String   Float64
───┼───────────
   1 │ Alice       85.5
   2 │ Bob         92.0
   3 │ Charlie     78.0

filter(), filter!() を使うと、条件を満たす行を取り出すことができます。

filter(row -> condition, df) : 行データ row が condition を満たせば、その行を取得する
filter(:col => pred, df) : 行から取り出す列名と真偽を判定する述語 pred をペアで渡す

filter!() は引数の df を破壊的に修正します。

julia> filter(row -> row.Age > 25, df)
2×3 DataFrame
 Row │ Name     Age    Score
     │ String   Int64  Float64
───┼───────────────
   1 │ Bob         30     92.0
   2 │ Charlie     35     78.0

julia> filter(:Age => >(25), df)
2×3 DataFrame
 Row │ Name     Age    Score
     │ String   Int64  Float64
───┼───────────────
   1 │ Bob         30     92.0
   2 │ Charlie     35     78.0

julia> filter(row -> row.Score > 90, df)
1×3 DataFrame
 Row │ Name    Age    Score
     │ String  Int64  Float64
───┼──────────────
   1 │ Bob        30     92.0

julia> filter(:Score => >(90), df)
1×3 DataFrame
 Row │ Name    Age    Score
     │ String  Int64  Float64
───┼──────────────
   1 │ Bob        30     92.0

同様のことは、データフレームの Indexing でも行うことができます。

julia> df[df.Age .> 25, :]
2×3 DataFrame
 Row │ Name     Age    Score
     │ String   Int64  Float64
───┼──────────────
   1 │ Bob         30     92.0
   2 │ Charlie     35     78.0

julia> df[df.Score .> 90, :]
1×3 DataFrame
 Row │ Name    Age    Score
     │ String  Int64  Float64
───┼──────────────
   1 │ Bob        30     92.0

●変形操作

select() は列を選択するだけではなく、列名を変更したり、列のデータに処理を加えて新しい列を作成することもできます。

:OldCol => :NewCol : OldCol を NewCol に変更
:OldCol => proc => :NewCol : 列 OldCol に関数 proc に適用し、その結果を新しい列 NewCol として追加する
:OldCol => ByRow(proc) => :NewCol : 列 OldCol の要素に関数 proc に適用し、その結果を新しい列 NewCol に追加する

列の要素に関数 proc を適用する場合は ByRow(proc) を使うと簡単です。なお、新しい列を追加するだけでよければ、df.NewCol = data で行うことができます。

julia> d = DataFrame(x = [1, 2], y = [3, 4])
2×2 DataFrame
 Row │ x      y
     │ Int64  Int64
───┼────────
   1 │     1      3
   2 │     2      4

julia> select(d, :x => :x1, :y => :y1)
2×2 DataFrame
 Row │ x1     y1
     │ Int64  Int64
───┼────────
   1 │     1      3
   2 │     2      4

julia> select(d, :x, :x => (x -> sqrt.(x)) => :z)
2×2 DataFrame
 Row │ x      z
     │ Int64  Float64
───┼──────────
   1 │     1  1.0
   2 │     2  1.41421

julia> select(d, :x, :x => ByRow(sqrt) => :z)
2×2 DataFrame
 Row │ x      z
     │ Int64  Float64
───┼──────────
   1 │     1  1.0
   2 │     2  1.41421

julia> select(d, :x, :y, [:x, :y] => ((x, y) -> (x .+ y) ./ 2) => :z)
2×3 DataFrame
 Row │ x      y      z
     │ Int64  Int64  Float64
───┼──────────────
   1 │     1      3      2.0
   2 │     2      4      3.0

最後の例のように、元のデータはそのままで新しい列を追加したい場合は、関数 transform(), transform!() を使うと簡単です。

julia> transform(d, :x => ByRow(sqrt))
2×3 DataFrame
 Row │ x      y      x_sqrt
     │ Int64  Int64  Float64
───┼──────────────
   1 │     1      3  1.0
   2 │     2      4  1.41421

julia> transform(d, :y => ByRow(sqrt))
2×3 DataFrame
 Row │ x      y      y_sqrt
     │ Int64  Int64  Float64
───┼──────────────
   1 │     1      3  1.73205
   2 │     2      4  2.0

julia> transform(d, [:x, :y] => ((x, y) -> (x .+ y) ./ 2) => :z)
2×3 DataFrame
 Row │ x      y      z
     │ Int64  Int64  Float64
───┼──────────────
   1 │     1      3      2.0
   2 │     2      4      3.0

All() を使うと、すべての列を選択することができます。

All() .=> function : ブロードキャストを使うと列ごとに関数 function を適用する
All() => function  : 各列の要素を取り出し、それらを function に渡して呼び出す
julia> transform(d, All() .=> ByRow(sqrt))
2×4 DataFrame
 Row │ x      y      x_sqrt   y_sqrt
     │ Int64  Int64  Float64  Float64
───┼────────────────────
   1 │     1      3  1.0      1.73205
   2 │     2      4  1.41421  2.0

julia> transform(d, All() => +)
2×3 DataFrame
 Row │ x      y      x_y_+
     │ Int64  Int64  Int64
───┼─────────────
   1 │     1      3      4
   2 │     2      4      6

julia> transform(d, All() => ((x, y) -> (x + y) / 2) => :z)
2×3 DataFrame
 Row │ x      y      z
     │ Int64  Int64  Float64
───┼─────────────
   1 │     1      3      2.0
   2 │     2      4      3.0

AsTable は、select() や transform() で「複数の列を一つのまとまり (名前付きタプルなど) にして関数に渡す」、または「関数の戻り値 (名前付きタプルなど) を複数の列として展開する」ために使用します。

julia> d1 = select(d, AsTable(:) => ByRow(identity))
2×1 DataFrame
 Row │ x_y_identity
     │ NamedTuple…
───┼───────────
   1 │ (x = 1, y = 3)
   2 │ (x = 2, y = 4)

julia> select(d1, :x_y_identity => AsTable)
2×2 DataFrame
 Row │ x      y
     │ Int64  Int64
───┼───────────
   1 │     1      3
   2 │     2      4

julia> transform(d, AsTable([:x, :y]) => ByRow(row -> (row.x + row.y) / 2) => :z)
2×3 DataFrame
 Row │ x      y      z
     │ Int64  Int64  Float64
───┼──────────────
   1 │     1      3      2.0
   2 │     2      4      3.0

●データの集計

関数 combine() は、データフレーム (またはグループ化されたデータフレーム) に対して集計や変換を行い、結果を新しいデータフレームに格納して返します。具体的には、特定の列 col に対して関数 f を適用し、その結果を格納したデータフレームを返します。col と f はペア col => f で指定します。

julia> using Statistics   # mean(), 平均値を求める

julia> df
3×3 DataFrame
 Row │ Name     Age    Score    
     │ String   Int64  Float64  
───┼───────────────
   1 │ Alice       25     85.5 
   2 │ Bob         30     92.0 
   3 │ Charlie     35     78.0 

julia> combine(df, :Age => mean)
1×1 DataFrame
 Row │ Age_mean
     │ Float64
───┼──────
   1 │     30.0

julia> combine(df, :Age => mean, :Age => sum)
1×2 DataFrame
 Row │ Age_mean  Age_sum
     │ Float64   Int64
───┼────────────
   1 │     30.0       90

julia> combine(df, [:Age, :Score] .=> mean)
1×2 DataFrame
 Row │ Age_mean  Score_mean
     │ Float64   Float64
───┼─────────────
   1 │     30.0     85.1667

関数 groupby() を使うと、データをグループに分けて、グループごとに集計することができます。

gd = groupby(df, 列名)
combine(gd, 列名 => 関数 => 出力先列名)

groupby() で列を配列で指定すると、複数列でグループ化をすることができます。

リスト : 生徒の伸長

df_height = DataFrame(
  Name = ["Ada", "Alice", "Carey", "Ellen", "Hanna", "Janet",
          "Linda", "Maria", "Miranda", "Sara", "Tracy", "Violet"],
  Height = [148.7, 149.5, 133.7, 157.9, 154.2, 147.8, 
           154.6, 159.1, 148.2, 153.1, 138.2, 138.7],
  Class = [:A,:B,:C,:D,:A,:B,:C,:D,:A,:B,:C,:D]
)
julia> df_height = DataFrame(
         Name = ["Ada", "Alice", "Carey", "Ellen", "Hanna", "Janet",
                 "Linda", "Maria", "Miranda", "Sara", "Tracy", "Violet"],
         Height = [148.7, 149.5, 133.7, 157.9, 154.2, 147.8,
                  154.6, 159.1, 148.2, 153.1, 138.2, 138.7],
         Class = [:A,:B,:C,:D,:A,:B,:C,:D,:A,:B,:C,:D]
       )
12×3 DataFrame
 Row │ Name     Height   Class
     │ String   Float64  Symbol
───┼───────────────
   1 │ Ada        148.7  A
   2 │ Alice      149.5  B
   3 │ Carey      133.7  C
   4 │ Ellen      157.9  D
   5 │ Hanna      154.2  A
   6 │ Janet      147.8  B
   7 │ Linda      154.6  C
   8 │ Maria      159.1  D
   9 │ Miranda    148.2  A
  10 │ Sara       153.1  B
  11 │ Tracy      138.2  C
  12 │ Violet     138.7  D

julia> df_class = groupby(df_height, :Class)
GroupedDataFrame with 4 groups based on key: Class
First Group (3 rows): Class = :A
 Row │ Name     Height   Class
     │ String   Float64  Symbol
───┼───────────────
   1 │ Ada        148.7  A
   2 │ Hanna      154.2  A
   3 │ Miranda    148.2  A
⋮
Last Group (3 rows): Class = :D
 Row │ Name    Height   Class
     │ String  Float64  Symbol
───┼───────────────
   1 │ Ellen     157.9  D
   2 │ Maria     159.1  D
   3 │ Violet    138.7  D

julia> combine(df_class, :Height => mean)
4×2 DataFrame
 Row │ Class   Height_mean
     │ Symbol  Float64
───┼───────────────
   1 │ A           150.367
   2 │ B           150.133
   3 │ C           142.167
   4 │ D           151.9

julia> combine(df_class, :Height => maximum)
4×2 DataFrame
 Row │ Class   Height_maximum
     │ Symbol  Float64
───┼───────────────
   1 │ A                154.2
   2 │ B                153.1
   3 │ C                154.6
   4 │ D                159.1

julia> combine(df_class, :Height => minimum)
4×2 DataFrame
 Row │ Class   Height_minimum
     │ Symbol  Float64
───┼───────────────
   1 │ A                148.2
   2 │ B                147.8
   3 │ C                133.7
   4 │ D                138.7

●行と列のイテレーション

データフレーム df を 1 行ずつ処理する場合、関数 eachrow(df) を使用します。各行は DataFrameRow という型で返され、列名でアクセスすることができます。

julia> d = DataFrame(rand(3, 3), [:x, :y, :z])
3×3 DataFrame
 Row │ x         y          z
     │ Float64   Float64    Float64
───┼───────────────────
   1 │ 0.346425  0.364283   0.599289
   2 │ 0.104331  0.438215   0.0422631
   3 │ 0.365164  0.0548274  0.495545

julia> for row in eachrow(d) println(row) end
DataFrameRow
 Row │ x         y         z
     │ Float64   Float64   Float64
───┼───────────────────
   1 │ 0.346425  0.364283  0.599289
DataFrameRow
 Row │ x         y         z
     │ Float64   Float64   Float64
───┼───────────────────
   2 │ 0.104331  0.438215  0.0422631
DataFrameRow
 Row │ x         y          z
     │ Float64   Float64    Float64
───┼───────────────────
   3 │ 0.365164  0.0548274  0.495545

julia> for row in eachrow(d) println(row.x, row.y, row.z) end
0.34642496259045620.36428313121846680.5992887456834662
0.104330706549074390.438215036620621450.04226314830872879
0.365163828384003960.054827361797255890.4955448988219937

julia> map(row -> [row.x, row.y, row.z], eachrow(d))
3-element Vector{Vector{Float64}}:
 [0.3464249625904562, 0.3642831312184668, 0.5992887456834662]
 [0.10433070654907439, 0.43821503662062145, 0.04226314830872879]
 [0.36516382838400396, 0.05482736179725589, 0.4955448988219937]

各列を 1 つのベクトルとして処理する場合は関数 eachcol(df) を使用します。pairs(eachcol(df)) を使うと、列名 (Symbol) とデータのペアを取得できます。

julia> for col in eachcol(d) println(col) end
[0.3464249625904562, 0.10433070654907439, 0.36516382838400396]
[0.3642831312184668, 0.43821503662062145, 0.05482736179725589]
[0.5992887456834662, 0.04226314830872879, 0.4955448988219937]

julia> for col in pairs(eachcol(d)) println(col) end
Pair{Symbol, AbstractVector}(:x, [0.3464249625904562, 0.10433070654907439, 0.36516382838400396])
Pair{Symbol, AbstractVector}(:y, [0.3642831312184668, 0.43821503662062145, 0.05482736179725589])
Pair{Symbol, AbstractVector}(:z, [0.5992887456834662, 0.04226314830872879, 0.4955448988219937])

Julia の for ループは高速なので、eachrow(df) などを使ってループを回しても、問題になることは少ないと思います。eachrow() よりも高速に動作させたい場合、各行を名前付きタプルとして取り出す方法があります。型推論が効きやすいためループ処理のパフォーマンスが向上する、といわれています。この方法も簡単で、ライブラリ Tables.jl の関数 namedtupleiterator() を呼び出すだけです。

Tables.jl は、データフレームや CSV ファイル、データベース、名前付きタプルの配列など、さまざまな形式の「表形式データ」を共通の形式で相互変換するためのインターフェースを提供するパッケージです。Julia のパッケージモード (REPL で ] キーを押す) で次のコマンドを実行するとインストールすることができます。

(@v1.12) pkg> add Tables
(@v1.12) pkg> st
Status `~/.julia/environments/v1.12/Project.toml`
  [336ed68f] CSV v0.10.16
  [a93c6f00] DataFrames v1.8.2
  [91a5bcdd] Plots v1.41.6
  [f3b207a7] StatsPlots v0.15.8
  [bd369af6] Tables v1.12.1

M.Hiroi の環境では Tables v1.12.1 がインストールされました。

あとは、eachrow() のかわりに Tables.namedtupleiterator() を呼び出すだけです。

julia> using Tables

julia> for row in Tables.namedtupleiterator(d) println(row) end
(x = 0.3464249625904562, y = 0.3642831312184668, z = 0.5992887456834662)
(x = 0.10433070654907439, y = 0.43821503662062145, z = 0.04226314830872879)
(x = 0.36516382838400396, y = 0.05482736179725589, z = 0.4955448988219937)

Tables.jl はデータ形式の変換や、自作のデータ構造を「テーブル」として扱いたい場合、とても役に立ちます。

DataFrame.jl の基本的な使い方を簡単に説明しました。DataFrames.jl は高機能で多機能なライブラリなので、使いこなすのはちょっと大変だと思いますが、基本的な操作はそれほど難しくはありません。興味のある方はいろいろ試してみてください。


初版 2026 年 4 月 29 日