Julia で「言語処理100本ノック 2020(Rev 2)」--2

[言語処理100本ノック 2020(Rev 2)](https://nlp100.github.io/ja/)

## 10. 行数のカウント

行数をカウントせよ．確認にはwcコマンドを用いよ．

    > wc popular-names.txt 
        2780   11120   55026 popular-names.txt


```julia
using DataFrames, CSV
cd("/Users/foo/Desktop/Julia")
df = CSV.read("popular-names.txt", DataFrame, header=["name", "gender", "children", "year"])
size(df, 1)
```




    2780



データフレームを使わない解


```julia
lines = readlines("popular-names.txt")
length(lines)
```




    2780



## 11. タブをスペースに置換

タブ1文字につきスペース1文字に置換せよ．確認にはsedコマンド，trコマンド，もしくはexpandコマンドを用いよ．

    > sed -e 's/\t/ /g' popular-names.txt > working.txt
    > head -5 working.txt 
    Mary F 7065 1880
    Anna F 2604 1880
    Emma F 2003 1880
    Elizabeth F 1939 1880
    Minnie F 1746 1880



```julia
df = CSV.read("popular-names.txt", DataFrame, header=["name", "gender", "children", "year"])
CSV.write("spacedelimited.csv", df, writeheader=false, delim=' ')
```




    "spacedelimited.csv"



データフレームを使わない解


```julia
lines = readlines("popular-names.txt")
result = replace.(lines, r"\t"=>" ")
first(result, 5)
```




    5-element Vector{String}:
     "Mary F 7065 1880"
     "Anna F 2604 1880"
     "Emma F 2003 1880"
     "Elizabeth F 1939 1880"
     "Minnie F 1746 1880"



## 12. 1列目をcol1.txtに，2列目をcol2.txtに保存

各行の1列目だけを抜き出したものをcol1.txtに，2列目だけを抜き出したものをcol2.txtとしてファイルに保存せよ．確認にはcutコマンドを用いよ．

    > cut -f 1 popular-names.txt > col1.txt
    > head -5 col1.txt
    Mary
    Anna
    Emma
    Elizabeth
    Minnie
    
    > cut -f 2 popular-names.txt > col2.txt
    > head -5 col2.txt
    F
    F
    F
    F
    F


データフレームを使ってもできるが，注意が必要。

`df[:,["name"]]` の型は `DataFrame` であるが，`df.name` の型は `PooledVector{String15, UInt32, Vector{UInt32}}` というもの。

前者は当然 `CSV.write` で書き出すことができるが，後者はエラーになる（データフレームではないので）。

また，列名を書かないように指定する（`writeheader=false`）。


```julia
df = CSV.read("popular-names.txt", DataFrame, header=["name", "gender", "children", "year"]);
CSV.write("col1.csv", df[:,["name"]], writeheader=false)
CSV.write("col2.csv", df[:,["gender"]], writeheader=false);
```

データフレームを使わない解


```julia
lines = readlines("popular-names.txt")
str = reshape(vcat(split.(lines)...), (4, :))
```




    4×2780 Matrix{SubString{String}}:
     "Mary"  "Anna"  "Emma"  "Elizabeth"  …  "Elijah"  "Lucas"  "Mason"  "Logan"
     "F"     "F"     "F"     "F"             "M"       "M"      "M"      "M"
     "7065"  "2604"  "2003"  "1939"          "12886"   "12585"  "12435"  "12352"
     "1880"  "1880"  "1880"  "1880"          "2018"    "2018"   "2018"   "2018"




```julia
f1 = open("col1.csv", "w")
f2 = open("col2.csv", "w")
for i in 1:size(str, 2)
    write(f1, str[1, i], "\n")
    write(f2, str[2, i], "\n")
end
close(f1)
close(f2)
```

## 13. col1.txtとcol2.txtをマージ

12で作ったcol1.txtとcol2.txtを結合し，元のファイルの1列目と2列目をタブ区切りで並べたテキストファイルを作成せよ．確認にはpasteコマンドを用いよ．

    > paste col1.txt col2.txt > col1col2.txt
    > head -5 col1col2.txt 
    Mary	F
    Anna	F
    Emma	F
    Elizabeth	F
    Minnie	F



```julia
col1df = CSV.read("col1.txt", DataFrame, header=["name"])
col2df = CSV.read("col2.txt", DataFrame, header=["gender"])
CSV.write("catdf.csv", hcat(col1df, col2df), writeheader=false, delim='\t');
```

## 14. 先頭からN行を出力

自然数Nをコマンドライン引数などの手段で受け取り，入力のうち先頭のN行だけを表示せよ．確認にはheadコマンドを用いよ．

    > head -5 popular-names.txt 
    Mary	F	7065	1880
    Anna	F	2604	1880
    Emma	F	2003	1880
    Elizabeth	F	1939	1880
    Minnie	F	1746	1880


```julia
df = CSV.read("popular-names.txt", DataFrame, header=["name", "gender", "children", "year"])
first(df, 5)
```




<div class="data-frame"><p>5 rows × 4 columns</p><table class="data-frame"><thead><tr><th></th><th>name</th><th>gender</th><th>children</th><th>year</th></tr><tr><th></th><th title="String15">String15</th><th title="String1">String1</th><th title="Int64">Int64</th><th title="Int64">Int64</th></tr></thead><tbody><tr><th>1</th><td>Mary</td><td>F</td><td>7065</td><td>1880</td></tr><tr><th>2</th><td>Anna</td><td>F</td><td>2604</td><td>1880</td></tr><tr><th>3</th><td>Emma</td><td>F</td><td>2003</td><td>1880</td></tr><tr><th>4</th><td>Elizabeth</td><td>F</td><td>1939</td><td>1880</td></tr><tr><th>5</th><td>Minnie</td><td>F</td><td>1746</td><td>1880</td></tr></tbody></table></div>



## 15. 末尾のN行を出力

自然数Nをコマンドライン引数などの手段で受け取り，入力のうち末尾のN行だけを表示せよ．確認にはtailコマンドを用いよ．

    > tail -5 popular-names.txt
    Benjamin	M	13381	2018
    Elijah	M	12886	2018
    Lucas	M	12585	2018
    Mason	M	12435	2018
    Logan	M	12352	2018


```julia
df = CSV.read("popular-names.txt", DataFrame, header=["name", "gender", "children", "year"])
last(df, 5)
```




<div class="data-frame"><p>5 rows × 4 columns</p><table class="data-frame"><thead><tr><th></th><th>name</th><th>gender</th><th>children</th><th>year</th></tr><tr><th></th><th title="String15">String15</th><th title="String1">String1</th><th title="Int64">Int64</th><th title="Int64">Int64</th></tr></thead><tbody><tr><th>1</th><td>Benjamin</td><td>M</td><td>13381</td><td>2018</td></tr><tr><th>2</th><td>Elijah</td><td>M</td><td>12886</td><td>2018</td></tr><tr><th>3</th><td>Lucas</td><td>M</td><td>12585</td><td>2018</td></tr><tr><th>4</th><td>Mason</td><td>M</td><td>12435</td><td>2018</td></tr><tr><th>5</th><td>Logan</td><td>M</td><td>12352</td><td>2018</td></tr></tbody></table></div>



## 16. ファイルをN分割する

自然数Nをコマンドライン引数などの手段で受け取り，入力のファイルを行単位でN分割せよ．同様の処理をsplitコマンドで実現せよ．

    > split -d -l 500 popular-names.txt popname
    > head popname02
    Mary	F	64146	1930
    Betty	F	38234	1930
    Dorothy	F	30409	1930
    Helen	F	19914	1930
    Margaret	F	18354	1930
    Barbara	F	18281	1930
    Patricia	F	15751	1930
    Joan	F	15479	1930
    Doris	F	15464	1930
    Ruth	F	14940	1930


```julia
df = CSV.read("popular-names.txt", DataFrame, header=["name", "gender", "children", "year"])
n = 500
nlines = size(df, 1)
for i in 1:n:size(df, 1)
    CSV.write("catdf" * "$i" * ".csv", df[i:min(nlines, i+n), :], writeheader=false, delim='\t')
end
df2 = CSV.read("catdf2501.csv", DataFrame, header=["name", "gender", "children", "year"])
last(df2, 5)
```




<div class="data-frame"><p>5 rows × 4 columns</p><table class="data-frame"><thead><tr><th></th><th>name</th><th>gender</th><th>children</th><th>year</th></tr><tr><th></th><th title="String15">String15</th><th title="String1">String1</th><th title="Int64">Int64</th><th title="Int64">Int64</th></tr></thead><tbody><tr><th>1</th><td>Benjamin</td><td>M</td><td>13381</td><td>2018</td></tr><tr><th>2</th><td>Elijah</td><td>M</td><td>12886</td><td>2018</td></tr><tr><th>3</th><td>Lucas</td><td>M</td><td>12585</td><td>2018</td></tr><tr><th>4</th><td>Mason</td><td>M</td><td>12435</td><td>2018</td></tr><tr><th>5</th><td>Logan</td><td>M</td><td>12352</td><td>2018</td></tr></tbody></table></div>



## 17. １列目の文字列の異なり

1列目の文字列の種類（異なる文字列の集合）を求めよ．確認にはcut, sort, uniqコマンドを用いよ．

    > cut -f 1 popular-names.txt | sort | uniq |wc
         136     136     943


```julia
df = CSV.read("popular-names.txt", DataFrame, header=["name", "gender", "children", "year"])
length(Set(df.name))
```




    136



## 18. 各行を3コラム目の数値の降順にソート

各行を3コラム目の数値の逆順で整列せよ（注意: 各行の内容は変更せずに並び替えよ）．確認にはsortコマンドを用いよ（この問題はコマンドで実行した時の結果と合わなくてもよい）．

    > sort -k 3 -nsr popular-names.txt | head -5
    Linda	F	99689	1947
    Linda	F	96211	1948
    James	M	94757	1947
    Michael	M	92704	1957
    Robert	M	91640	1947
    
    > sort -k 3 -nsr popular-names.txt | tail -5
    Annie	F	1326	1881
    Bertha	F	1324	1881
    Bertha	F	1320	1880
    Alice	F	1308	1881
    Sarah	F	1288	1880



```julia
df = CSV.read("popular-names.txt", DataFrame, header=["name", "gender", "children", "year"])
sorted = sort(df, order(:children, rev=true))
first(sorted, 5)
```




<div class="data-frame"><p>5 rows × 4 columns</p><table class="data-frame"><thead><tr><th></th><th>name</th><th>gender</th><th>children</th><th>year</th></tr><tr><th></th><th title="String15">String15</th><th title="String1">String1</th><th title="Int64">Int64</th><th title="Int64">Int64</th></tr></thead><tbody><tr><th>1</th><td>Linda</td><td>F</td><td>99689</td><td>1947</td></tr><tr><th>2</th><td>Linda</td><td>F</td><td>96211</td><td>1948</td></tr><tr><th>3</th><td>James</td><td>M</td><td>94757</td><td>1947</td></tr><tr><th>4</th><td>Michael</td><td>M</td><td>92704</td><td>1957</td></tr><tr><th>5</th><td>Robert</td><td>M</td><td>91640</td><td>1947</td></tr></tbody></table></div>




```julia
last(sorted, 5)
```




<div class="data-frame"><p>5 rows × 4 columns</p><table class="data-frame"><thead><tr><th></th><th>name</th><th>gender</th><th>children</th><th>year</th></tr><tr><th></th><th title="String15">String15</th><th title="String1">String1</th><th title="Int64">Int64</th><th title="Int64">Int64</th></tr></thead><tbody><tr><th>1</th><td>Annie</td><td>F</td><td>1326</td><td>1881</td></tr><tr><th>2</th><td>Bertha</td><td>F</td><td>1324</td><td>1881</td></tr><tr><th>3</th><td>Bertha</td><td>F</td><td>1320</td><td>1880</td></tr><tr><th>4</th><td>Alice</td><td>F</td><td>1308</td><td>1881</td></tr><tr><th>5</th><td>Sarah</td><td>F</td><td>1288</td><td>1880</td></tr></tbody></table></div>



## 19. 各行の1コラム目の文字列の出現頻度を求め，出現頻度の高い順に並べる

各行の1列目の文字列の出現頻度を求め，その高い順に並べて表示せよ．確認にはcut, uniq, sortコマンドを用いよ．

    > cut -f1 popular-names.txt | sort | uniq -c | sort -rns | head -10
    118 James
    111 William
    108 John
    108 Robert
    92 Mary
    75 Charles
    74 Michael
    73 Elizabeth
    70 Joseph
    60 Margaret

    > cut -f1 popular-names.txt | sort | uniq -c | sort -rns | tail -10
    1 Julie
    1 Kelly
    1 Laura
    1 Lori
    1 Lucas
    1 Pamela
    1 Rachel
    1 Scott
    1 Tracy
    1 Walter


```julia
using FreqTables
sort(freqtable(df.name), rev=true)
```




    136-element Named Vector{Int64}
    Dim1          │ 
    ──────────────┼────
    "James"       │ 118
    "William"     │ 111
    "John"        │ 108
    "Robert"      │ 108
    "Mary"        │  92
    "Charles"     │  75
    "Michael"     │  74
    "Elizabeth"   │  73
    "Joseph"      │  70
    "Margaret"    │  60
    "George"      │  58
    ⋮                 ⋮
    "Crystal"     │   1
    "Julie"       │   1
    "Kelly"       │   1
    "Laura"       │   1
    "Lori"        │   1
    "Lucas"       │   1
    "Pamela"      │   1
    "Rachel"      │   1
    "Scott"       │   1
    "Tracy"       │   1
    "Walter"      │   1