最近流行りつつある科学計算処理向けの高水準言語「Julia」の基本操作をまとめていきます。
1.準備編
2.確率分布・仮説検定と可視化編
3.データフレーム操作編
chapter.5 データフレーム操作
DataFrames.jl を使ったデータフレーム操作についてまとめます
公式:https://juliadata.github.io/DataFrames.jl/stable/man/getting_started/
1.パッケージ install
julia> import Pkg; Pkg.add("DataFrames")
2.データフレーム生成方法
行列データから生成する場合
julia> data = [
1 0.179324 "A";
2 0.818923 "B";
3 0.979487 "C";
4 0.882494 "A";
5 0.00530208 "B"];
julia> DataFrame(data)
5×3 DataFrame
│ Row │ x1 │ x2 │ x3 │
│ │ Any │ Any │ Any │
├─────┼─────┼────────────┼─────┤
│ 1 │ 1 │ 0.179324 │ A │
│ 2 │ 2 │ 0.818923 │ B │
│ 3 │ 3 │ 0.979487 │ C │
│ 4 │ 4 │ 0.882494 │ A │
│ 5 │ 5 │ 0.00530208 │ B │
列名を与える場合
julia> DataFrame(data, [:A, :B, :C])
5×3 DataFrame
│ Row │ A │ B │ C │
│ │ Any │ Any │ Any │
├─────┼─────┼────────────┼─────┤
│ 1 │ 1 │ 0.179324 │ A │
│ 2 │ 2 │ 0.818923 │ B │
│ 3 │ 3 │ 0.979487 │ C │
│ 4 │ 4 │ 0.882494 │ A │
│ 5 │ 5 │ 0.00530208 │ B │
列ベクトルから生成する場合
julia> DataFrame(
A=1:5,
B=rand(5),
C=["A", "B", "C", "A", "B"])
5×3 DataFrame
│ Row │ A │ B │ C │
│ │ Int64 │ Float64 │ String │
├─────┼───────┼───────────┼────────┤
│ 1 │ 1 │ 0.0974522 │ A │
│ 2 │ 2 │ 0.194185 │ B │
│ 3 │ 3 │ 0.280582 │ C │
│ 4 │ 4 │ 0.838387 │ A │
│ 5 │ 5 │ 0.745305 │ B │
辞書型データから生成する場合
※以後このデータを使います
julia> data = Dict(
:A => 1:5,
:B => rand(5),
:C => ["A", "B", "C", "A", "B"]);
julia> df = DataFrame(data)
5×3 DataFrame
│ Row │ A │ B │ C │
│ │ Int64 │ Float64 │ String │
├─────┼───────┼──────────┼────────┤
│ 1 │ 1 │ 0.558038 │ A │
│ 2 │ 2 │ 0.319128 │ B │
│ 3 │ 3 │ 0.858239 │ C │
│ 4 │ 4 │ 0.578579 │ A │
│ 5 │ 5 │ 0.142839 │ B │
※symbol 型について補足
:A といった表記は symbol 型のデータを表しています。
筆者も詳しくありませんが、変数を表すためのデータと表現すると感覚的に近い気がしています。
julia> string = "A";
julia> typeof(string)
String
julia> symbol = :A;
julia> typeof(symbol)
Symbol
julia> Symbol(string) # String から Symbol への変換
:A
CSV から読み込む場合パッケージが必要
julia> import Pkg; Pkg.add("CSV")
julia> using CSV
手元にデータがないのでとりあえず書き込みから
julia> data = Dict(
:A => 1:5,
:B => rand(5),
:C => ["A", "B", "C", "A", "B"]);
julia> df = DataFrame(data);
julia> CSV.write("dataframe.csv", df)
"dataframe.csv"
読み込み
julia> new_df = CSV.read("dataframe.csv");
julia> new_df
5×3 DataFrame
│ Row │ A │ B │ C │
│ │ Int64 │ Float64 │ String │
├─────┼───────┼───────────┼────────┤
│ 1 │ 1 │ 0.0387064 │ A │
│ 2 │ 2 │ 0.0974289 │ B │
│ 3 │ 3 │ 0.281637 │ C │
│ 4 │ 4 │ 0.566432 │ A │
│ 5 │ 5 │ 0.685344 │ B │
3.データ基本情報の確認
先頭 n 行を確認
julia> n = 3;
julia> first(df, n)
3×3 DataFrame
│ Row │ A │ B │ C │
│ │ Int64 │ Float64 │ String │
├─────┼───────┼──────────┼────────┤
│ 1 │ 1 │ 0.558038 │ A │
│ 2 │ 2 │ 0.319128 │ B │
│ 3 │ 3 │ 0.858239 │ C │
最終 n 行を確認
julia> n = 3;
julia> last(df, n)
3×3 DataFrame
│ Row │ A │ B │ C │
│ │ Int64 │ Float64 │ String │
├─────┼───────┼──────────┼────────┤
│ 1 │ 3 │ 0.858239 │ C │
│ 2 │ 4 │ 0.578579 │ A │
│ 3 │ 5 │ 0.142839 │ B │
行数と列数の確認
julia> size(df)
(5, 3)
カラム名を確認
julia> names(df)
3-element Array{Symbol,1}:
:A
:B
:C
データ型を確認
julia> eltype.(eachcol(df))
3-element Array{DataType,1}:
Int64
Float64
String
各種統計量(など)を確認
julia> describe(df)
3×8 DataFrame. Omitted printing of 2 columns
│ Row │ variable │ mean │ min │ median │ max │ nunique │
│ │ Symbol │ Union… │ Any │ Union… │ Any │ Union… │
├─────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┤
│ 1 │ A │ 3.0 │ 1 │ 3.0 │ 5 │ │
│ 2 │ B │ 0.491365 │ 0.142839 │ 0.558038 │ 0.858239 │ │
│ 3 │ C │ │ A │ │ C │ 3 │
4.データ抽出
R, numpy, pandas とほぼ同じ書き方です
列を取り出す
julia> df.A
5-element Array{Int64,1}:
1
2
3
4
5
複数列を取り出す
julia> df[:,[:A, :B]]
5×2 DataFrame
│ Row │ A │ B │
│ │ Int64 │ Float64 │
├─────┼───────┼──────────┤
│ 1 │ 1 │ 0.558038 │
│ 2 │ 2 │ 0.319128 │
│ 3 │ 3 │ 0.858239 │
│ 4 │ 4 │ 0.578579 │
│ 5 │ 5 │ 0.142839 │
列を取り出して算術も簡単
julia> df.D = df.A .* 40;
julia> df
5×4 DataFrame
│ Row │ A │ B │ C │ D │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 1 │ 1 │ 0.558038 │ A │ 40 │
│ 2 │ 2 │ 0.319128 │ B │ 80 │
│ 3 │ 3 │ 0.858239 │ C │ 120 │
│ 4 │ 4 │ 0.578579 │ A │ 160 │
│ 5 │ 5 │ 0.142839 │ B │ 200 │
行を抽出
julia> df[2, :]
DataFrameRow
│ Row │ A │ B │ C │ D │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 2 │ 2 │ 0.319128 │ B │ 80 │
複数行を抽出
julia> df[2:5,:] # row index が変わっている点に注意!
4×4 DataFrame
│ Row │ A │ B │ C │ D │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 1 │ 2 │ 0.319128 │ B │ 80 │
│ 2 │ 3 │ 0.858239 │ C │ 120 │
│ 3 │ 4 │ 0.578579 │ A │ 160 │
│ 4 │ 5 │ 0.142839 │ B │ 200 │
条件抽出
julia> df[df.A.>3,:]
2×4 DataFrame
│ Row │ A │ B │ C │ D │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 1 │ 4 │ 0.578579 │ A │ 160 │
│ 2 │ 5 │ 0.142839 │ B │ 200 │
複数条件による抽出
julia> df[(df.A.>3).&(df.C.=="B"),:]
1×4 DataFrame
│ Row │ A │ B │ C │ D │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 1 │ 5 │ 0.142839 │ B │ 200 │
抽出した条件の値を書き換える
julia> df[(df.A.>3).&(df.C.=="B"),:C] .= "X";
julia> df
5×4 DataFrame
│ Row │ A │ B │ C │ D │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 1 │ 1 │ 0.558038 │ A │ 40 │
│ 2 │ 2 │ 0.319128 │ B │ 80 │
│ 3 │ 3 │ 0.858239 │ C │ 120 │
│ 4 │ 4 │ 0.578579 │ A │ 160 │
│ 5 │ 5 │ 0.142839 │ X │ 200 │
5.結合(join, append)
Union
julia> df2 = DataFrame(
A=[10],
B=[0.1],
C=["C"],
D=[20]);
julia> append!(df, df2) # 再帰的なので注意!
6×4 DataFrame
│ Row │ A │ B │ C │ D │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 1 │ 1 │ 0.558038 │ A │ 40 │
│ 2 │ 2 │ 0.319128 │ B │ 80 │
│ 3 │ 3 │ 0.858239 │ C │ 120 │
│ 4 │ 4 │ 0.578579 │ A │ 160 │
│ 5 │ 5 │ 0.142839 │ X │ 200 │
│ 6 │ 10 │ 0.1 │ C │ 20 │
Join
デフォルトでは inner join
julia> df3 = DataFrame(C = ["A", "B"],E=["abc", "xyz"]);
julia> join(df, df3, on=:C)
3×5 DataFrame
│ Row │ A │ B │ C │ D │ E │
│ │ Int64 │ Float64 │ String │ Int64 │ String │
├─────┼───────┼──────────┼────────┼───────┼────────┤
│ 1 │ 1 │ 0.558038 │ A │ 40 │ abc │
│ 2 │ 2 │ 0.319128 │ B │ 80 │ xyz │
│ 3 │ 4 │ 0.578579 │ A │ 160 │ abc │
left join
julia> join(df, df3, on=:C, kind=:left)
6×5 DataFrame
│ Row │ A │ B │ C │ D │ E │
│ │ Int64 │ Float64 │ String │ Int64 │ String⍰ │
├─────┼───────┼──────────┼────────┼───────┼─────────┤
│ 1 │ 1 │ 0.558038 │ A │ 40 │ abc │
│ 2 │ 2 │ 0.319128 │ B │ 80 │ xyz │
│ 3 │ 3 │ 0.858239 │ C │ 120 │ missing │
│ 4 │ 4 │ 0.578579 │ A │ 160 │ abc │
│ 5 │ 5 │ 0.142839 │ X │ 200 │ missing │
│ 6 │ 10 │ 0.1 │ C │ 20 │ missing │
# なぜか文字化けが起こる...
詳細はこちら
6.集計(aggregate, by)
aggregate 関数
・第一引数にdataframe
・第二引数に集計 key とするカラム名(配列にすると multi index 集計)
・第三引数に集計方法(配列可)
julia> aggregate(df, :C, sum)
4×4 DataFrame
│ Row │ C │ A_sum │ B_sum │ D_sum │
│ │ String │ Int64 │ Float64 │ Int64 │
├─────┼────────┼───────┼──────────┼───────┤
│ 1 │ A │ 5 │ 1.13662 │ 200 │
│ 2 │ B │ 2 │ 0.319128 │ 80 │
│ 3 │ C │ 13 │ 0.958239 │ 140 │
│ 4 │ X │ 5 │ 0.142839 │ 200 │
※集計を行う場合は Statistics.jl を入れておいたほうがいい。
julia> import Pkg; Pkg.add("Statistics")
julia> using Statistics
なぜかmeanも無い( describe では mean あったのに何故!?)
by 関数
・第一引数にdataframe
・第二引数に集計 key とするカラム名(配列にすると multi index 集計)
・第三引数に辞書型で集計対象(key)と集計方法(value)を指定
例1.
julia> by(df, :C ,:A=>sum)
4×2 DataFrame
│ Row │ C │ A_sum │
│ │ String │ Int64 │
├─────┼────────┼───────┤
│ 1 │ A │ 5 │
│ 2 │ B │ 2 │
│ 3 │ C │ 13 │
│ 4 │ X │ 5 │
例2.
julia> by(df, :C ,(:A=>sum, :A=>mean, :B=>std))
4×4 DataFrame
│ Row │ C │ A_sum │ A_mean │ B_std │
│ │ String │ Int64 │ Float64 │ Float64 │
├─────┼────────┼───────┼─────────┼──────────┤
│ 1 │ A │ 5 │ 2.5 │ 0.014525 │
│ 2 │ B │ 2 │ 2.0 │ NaN │
│ 3 │ C │ 13 │ 6.5 │ 0.536156 │
│ 4 │ X │ 5 │ 5.0 │ NaN │
7.その他
sort 関数
第二引数で指定したカラム名でソート
julia> sort!(df, :B)
6×4 DataFrame
│ Row │ A │ B │ C │ D │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 1 │ 10 │ 0.1 │ C │ 20 │
│ 2 │ 5 │ 0.142839 │ X │ 200 │
│ 3 │ 2 │ 0.319128 │ B │ 80 │
│ 4 │ 1 │ 0.558038 │ A │ 40 │
│ 5 │ 4 │ 0.578579 │ A │ 160 │
│ 6 │ 3 │ 0.858239 │ C │ 120 │
降順
julia> sort!(df, :B, rev = true)
6×4 DataFrame
│ Row │ A │ B │ C │ D │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 1 │ 3 │ 0.858239 │ C │ 120 │
│ 2 │ 4 │ 0.578579 │ A │ 160 │
│ 3 │ 1 │ 0.558038 │ A │ 40 │
│ 4 │ 2 │ 0.319128 │ B │ 80 │
│ 5 │ 5 │ 0.142839 │ X │ 200 │
│ 6 │ 10 │ 0.1 │ C │ 20 │
カラム名の変更
rename 関数
例1. リストで変更
julia> new_colname = [:W, :X, :Y, :Z];
julia> rename!(df, new_colname)
6×4 DataFrame
│ Row │ W │ X │ Y │ Z │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 1 │ 3 │ 0.858239 │ C │ 120 │
│ 2 │ 4 │ 0.578579 │ A │ 160 │
│ 3 │ 1 │ 0.558038 │ A │ 40 │
│ 4 │ 2 │ 0.319128 │ B │ 80 │
│ 5 │ 5 │ 0.142839 │ X │ 200 │
│ 6 │ 10 │ 0.1 │ C │ 20 │
例2. 辞書で変更
julia> new_colname = Dict(:W=>:A, :X =>:B, :Y=>:C, :Z=>:D);
julia> rename!(df, new_colname)
6×4 DataFrame
│ Row │ A │ B │ C │ D │
│ │ Int64 │ Float64 │ String │ Int64 │
├─────┼───────┼──────────┼────────┼───────┤
│ 1 │ 3 │ 0.858239 │ C │ 120 │
│ 2 │ 4 │ 0.578579 │ A │ 160 │
│ 3 │ 1 │ 0.558038 │ A │ 40 │
│ 4 │ 2 │ 0.319128 │ B │ 80 │
│ 5 │ 5 │ 0.142839 │ X │ 200 │
│ 6 │ 10 │ 0.1 │ C │ 20 │