JuliaでCSVを作成・更新してみた

# この記事について
JuliaでHTMLからデータを引っ張ってきて保存しようとした際に、CSV（というかDataFrame）の使い方がわからなかったので、まとめてみました。
あとCSV（というかDataFrame）の操作に関する日本語記事がなかなか見つからなかったので記事にしてみることにしました。

# 作業環境
Julia 1.0

# 使用したパッケージ
CSV
DataFrames

# コーディング
### 簡単なCSVファイルの読み込み
まずはCSVファイルを読み込んでみます。

```csv:sampleCSV.csv
"商品名","値段","在庫"
"トマト",100,50
"トウモロコシ",150,20
"スイカ",200,30
```
最初の行はヘッダーで、残りはデータ行です。
これを読み込んで出力してみます。

```Julia:TestCSV.jl
using CSV
using DataFrames

df = CSV.read("sampleCSV.csv", header=true, delim=',')
@show df
```
簡単に読み込んで出力するだけのソースコードです。
実行結果は以下の通りです。

```実行結果
3×3 DataFrames.DataFrame
│ Row │ 商品名       │ 値段   │ 在庫   │
│     │ String⍰      │ Int64⍰ │ Int64⍰ │
├─────┼──────────────┼────────┼────────┤
│ 1   │ トマト       │ 100    │ 50     │
│ 2   │ トウモロコシ │ 150    │ 20     │
│ 3   │ スイカ       │ 200    │ 30     │
DataFrames.DataFrame
```

### DataFrame型をちょっと見てみる
[DataFrameのスタートガイドページ](https://juliadata.github.io/DataFrames.jl/stable/man/getting_started.html)
DataFrameの中身は行列と同じように後に[x]というように記述すると値を取得することが出来ます（xは任意の値）。
ただ、私の混乱したことが取得してくる値です。

```Julia:DataFrameの動き
>>df
3×3 DataFrames.DataFrame
│ Row │ 商品名       │ 値段   │ 在庫   │
│     │ String⍰      │ Int64⍰ │ Int64⍰ │
├─────┼──────────────┼────────┼────────┤
│ 1   │ トマト       │ 100    │ 50     │
│ 2   │ トウモロコシ │ 150    │ 20     │
│ 3   │ スイカ       │ 200    │ 30     │
>>df[1]
3-element Array{Union{Missing, String},1}:
 "トマト"
 "トウモロコシ"
 "スイカ"
```

１行目が取得されるのではなく１列目が取得されます。
CSVでは行よりも列を取得することが多いからじゃないかなと思いつつ、慣れていくしかなさそうです。

### 内容を変更して保存してみる
####内容の更新
在庫の数を増やしてみます。

```Julia:更新
>>df[3] = df[3] * 10
3-element Array{Int64,1}:
 500
 200
 300
>>df
3×3 DataFrames.DataFrame
│ Row │ 商品名       │ 値段   │ 在庫  │
│     │ String⍰      │ Int64⍰ │ Int64 │
├─────┼──────────────┼────────┼───────┤
│ 1   │ トマト       │ 100    │ 500   │
│ 2   │ トウモロコシ │ 150    │ 200   │
│ 3   │ スイカ       │ 200    │ 300   │
```
列単位で取得してこれるので、こういった更新は便利ですね。

####内容の追加
続いてデータ行を増やしてみます。

```Julia:追加
>>push!(df,("カボチャ",250,100))
4×3 DataFrame
│ Row │ 商品名       │ 値段   │ 在庫  │
│     │ String⍰      │ Int64⍰ │ Int64 │
├─────┼──────────────┼────────┼───────┤
│ 1   │ トマト       │ 100    │ 500   │
│ 2   │ トウモロコシ │ 150    │ 200   │
│ 3   │ スイカ       │ 200    │ 300   │
│ 4   │ カボチャ     │ 250    │ 100   │
```

####内容の削除
増やしたデータ行を削除します。

```Julia:削除
>>deleterows!(df, 4)
3×3 DataFrame
│ Row │ 商品名       │ 値段   │ 在庫  │
│     │ String⍰      │ Int64⍰ │ Int64 │
├─────┼──────────────┼────────┼───────┤
│ 1   │ トマト       │ 100    │ 500   │
│ 2   │ トウモロコシ │ 150    │ 200   │
│ 3   │ スイカ       │ 200    │ 300   │
```

####内容のソート
在庫を使用してソートをしてみます。

```Julia:ソート
# 昇順
>>sort!(df,3)
3×3 DataFrame
│ Row │ 商品名       │ 値段   │ 在庫  │
│     │ String⍰      │ Int64⍰ │ Int64 │
├─────┼──────────────┼────────┼───────┤
│ 1   │ トウモロコシ │ 150    │ 200   │
│ 2   │ スイカ       │ 200    │ 300   │
│ 3   │ トマト       │ 100    │ 500   │

# 降順
>>sort!(df,3,rev=true)
3×3 DataFrame
│ Row │ 商品名       │ 値段   │ 在庫  │
│     │ String⍰      │ Int64⍰ │ Int64 │
├─────┼──────────────┼────────┼───────┤
│ 1   │ トマト       │ 100    │ 500   │
│ 2   │ スイカ       │ 200    │ 300   │
│ 3   │ トウモロコシ │ 150    │ 200   │
```

####内容の保存
今回変更した内容で保存をしてみます。

```Julia:
>>df |> CSV.write("outputCSV.csv",delim=',',writeheader=true)
"outputCSV.csv"
```

```csv:outputCSV.csv
商品名,値段,在庫
トマト,100,500
スイカ,200,300
トウモロコシ,150,200
```
在庫が10倍になっているのと、在庫の降順でソートされて保存されいます。

ガイドを読んでみると他にも機能がありそうなので読んでみてください。
今回はこれくらいできれば最低限かなと判断しました。

#### ここまでのソースコードまとめ

```julia:TestCSV.jl
using csv
using DataFrames

# ファイル読み込み
df = CSV.read("sample.csv",header=true,dlim=',')
@show df

# データ内容更新
df[3] = df[3] * 10
# データ更新
push!(df,("カボチャ",250,100))
# データ削除
deleterows!(df, 4)
# データ内容ソート
sort!(df,rev=true)

# データ保存
df |> CSV.write("outputCSV.csv",writeheader=true,dlim=',')
```

### ArrayをDataFrameに変換する
Array形式のデータ（↓）をDataFramesに入れます。

```Julia
>>l = [1 2 3;4 5 6;7 8 9]
3×3 Array{Int64,2}:
 1  2  3
 4  5  6
 7  8  9
>>df = DataFrames(l)
3×3 DataFrame
│ Row │ x1    │ x2    │ x3    │
│     │ Int64 │ Int64 │ Int64 │
├─────┼───────┼───────┼───────┤
│ 1   │ 1     │ 2     │ 3     │
│ 2   │ 4     │ 5     │ 6     │
│ 3   │ 7     │ 8     │ 9     │
```
これでとりあえずDataFrame型に変換することが出来ました。
しかしヘッダーがこのままだとよろしくないので、ヘッダーを変更します。
#### ヘッダー変更

```Julia:ヘッダー変更
# 一つだけ変更
>>rename!(df,(:x1 => :num1))
3×3 DataFrame
│ Row │ num1  │ x2    │ x3    │
│     │ Int64 │ Int64 │ Int64 │
├─────┼───────┼───────┼───────┤
│ 1   │ 1     │ 2     │ 3     │
│ 2   │ 4     │ 5     │ 6     │
│ 3   │ 7     │ 8     │ 9     │

# 複数を変更
rename!(df,f => t for (f,t) = zip([:x2,:x3],[:num2,:num3]))
3×3 DataFrame
│ Row │ num1  │ num2  │ num3  │
│     │ Int64 │ Int64 │ Int64 │
├─────┼───────┼───────┼───────┤
│ 1   │ 1     │ 2     │ 3     │
│ 2   │ 4     │ 5     │ 6     │
│ 3   │ 7     │ 8     │ 9     │
```
あとはこれをCSVとして保存すれば完了です。


####ここまでのコード

```Julia
using CSV
using DataFrames

l = [1 2 3;4 5 6;7 8 9]
df = DataFrame(l)
rename!(df,f => t for (f,t) = zip([:x1,:x2,:x3],[:num1,:num2,:num3]))

df |> CSV.write("outputCSV.csv",dlim=',',writeheader=true)
```
出力結果

```csv:outputCSV.csv
num1,num2,num3
1,2,3
4,5,6
7,8,9

```

# 次回
今回はCSVの作成方法についての記事を書いたので、次回こそはHTMLからデータを抜き出してCSVに保存する方法をやってみたいと思います。