1. Yusuke196

    No comment

    Yusuke196
Changes in body
Source | HTML | Preview
@@ -1,218 +1,218 @@
## はじめに
社内のメンバーを中心にした勉強会で[言語処理100本ノック](http://www.cl.ecei.tohoku.ac.jp/nlp100)を解いているのですが、その解答コードや、解く過程で便利だなと思った小技のまとめです。自分で調べたり検証したりした内容が多いですが、他の勉強会メンバーが共有してくれた情報も入っています。
-今回はUNIXコマンドの基礎についてまとめていきますが、先行する[@moriwoさん](https://qiita.com/moriwo/items/9d2a73a75f543e2ea6af)や[@segavvyさん](https://qiita.com/segavvy/items/fb50ba8097d59475f760)の記事でそこそこ詳しい解説がすでに書かれているので、この記事では解説の量を控えめにしたいと思います。以下を読んで分からない点があれば、上のリンクからお二方の記事なども見てみるのがおすすめです。
+今回はUNIXコマンドの基礎についてまとめていきますが、先行する[@moriwoさん](https://qiita.com/moriwo/items/9d2a73a75f543e2ea6af)や[@segavvyさん](https://qiita.com/segavvy/items/fb50ba8097d59475f760)の記事でかなり詳しい解説がすでに書かれているので、この記事での説明はさらっと控えめにしたいと思います。以下を読んで分からない点があれば、上のリンクからお二方の記事なども見てみるのがおすすめです。
## 環境
- macOS
- Python 3.8.1
- JupyterLab
## コード
### 10. 行数のカウント
```py:Python
def count_lines():
with open('hightemp.txt') as file:
return len(file.readlines())
count_lines()
```
```sh:UNIX
!wc -l hightemp.txt
```
UNIXコマンドの方が圧倒的に簡潔に書けました。ちなみに`wc`の前についている`!`は、JupyterLabやNotebookでUNIXコマンドを実行するときに使うものです(場合によって`!`なしでも動作します)。
### 11. タブをスペースに置換
```py:Python
def replace_tabs():
with open('hightemp.txt') as file:
return file.read().replace('\t', ' ')
print(replace_tabs())
```
```sh:UNIX
!cat hightemp.txt | sed $'s/\t/ /g'
```
-UNIXの`sed`では、`$`記号をつけないと`\t`がタブ記号として認識されないという注意点があります
+UNIXの`sed`について、`$`記号をつけないと`\t`がタブ記号として認識されないという点には注意が必要かなと思いました
### 12. 1列目をcol1.txtに,2列目をcol2.txtに保存
```py:Python
def separate_columns():
df = pd.read_csv('hightemp.txt', sep='\t', header=None)
df.iloc[:,0].to_csv('col1.txt', header=False, index=False)
df.iloc[:,1].to_csv('col2.txt', header=False, index=False)
separate_columns()
```
```sh:UNIX
!cut -f 1 hightemp.txt > col1_unix.txt
!cut -f 2 hightemp.txt > col2_unix.txt
```
### 13. col1.txtとcol2.txtをマージ
```py:Python
def merge_columns():
with open('col1.txt') as col1_file, open('col2.txt') as col2_file, \
open('merge.txt', mode='w') as new_file:
for col1_line, col2_line in zip(col1_file, col2_file):
new_file.write(f'{col1_line.rstrip()}\t{col2_line.rstrip()}\n')
merge_columns()
```
```sh:UNIX
!paste col[1-2].txt > merge_unix.txt
```
### 14. 先頭からN行を出力
```py:Python
def show_head():
n = int(input())
with open('hightemp.txt') as file:
for line in file.readlines()[:n]:
print(line.rstrip())
show_head()
```
```sh:UNIX
!head -3 hightemp.txt
```
Pythonについては、関数からリストを返すことにしたい場合、以下のように書くのもありかと思います。
```py:Python
def show_head():
n = int(input())
with open('hightemp.txt') as file:
return [line for line in file.readlines()[:n]]
print(*show_head())
```
UNIXではPythonのようにコマンドラインで整数を受け取ることが難しいのですが、`-`の後ろに整数を書くと何行分表示するか指定できます。応用的な使い方としては、`12`の解答の最後で
```sh:UNIX
!cat hightemp.txt | sed $'s/\t/ /g' | head -5
```
と書いて、最初の5行だけ表示することもできたりします。
### 15. 末尾のN行を出力
```py:Python
def show_tail():
n = int(input())
with open('hightemp.txt') as file:
- for line in file.readlines()[-n:]:
- print(line.rstrip())
+ return [line for line in file.readlines()[-n:]]
-show_tail()
+print(*show_tail())
```
```sh:UNIX
!tail -3 hightemp.txt
```
14とほぼ同じ。
### 16. ファイルをN分割する
```py:Python
import math
def split_file():
n = int(input())
with open('hightemp.txt') as file:
lines = file.readlines()
num = math.ceil(len(lines) / n)
for i in range(n):
with open('split{}.txt'.format(i + 1), mode='w') as new_file:
text = ''.join(lines[i * num:(i + 1) * num])
new_file.write(text)
split_file()
```
```sh:UNIX
!split -n 5 -d hightemp.txt split_unix
```
Linuxでは一般に`-n`コマンドが使えるようですが([@IT](https://www.atmarkit.co.jp/ait/articles/1711/24/news016.html))、自分のmacOS環境だと動作せず、このUNIXコマンドだけはColabで試しました。そうすると`split_unix00`から`split_unix04`まで5つのファイルができましたが、加えてそこに拡張子の`txt`をつけようとしたりすると、かなり面倒になりそうだと感じました。
[@moriwoさんの記事](https://qiita.com/moriwo/items/9d2a73a75f543e2ea6af#16-%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92n%E5%88%86%E5%89%B2%E3%81%99%E3%82%8B)では`awk`なども使った実装例が紹介されていますが、自分はPythonを使ったほうが読みやすいコードになるのかな、と思いました。
### 17. 1列目の文字列の異なり
```py:Python
import pandas as pd
def get_chars_set():
df = pd.read_csv('hightemp.txt', sep='\t', header=None)
return set(df.iloc[:, 0])
print(get_chars_set())
```
```sh:UNIX
!sort -u col1_unix.txt
```
並べ替えと重複除去の処理をパイプで繋いで、`!sort col1_unix.txt | uniq`とも書けます。
### 18. 各行を3コラム目の数値の降順にソート
```py:Python
def sort_rows():
df = pd.read_csv('hightemp.txt', sep='\t', header=None)
df.rename(columns={0: 'Prefect', 1: 'City', 2: 'Temp', 3: 'Date'}, inplace=True)
df.sort_values(by='Temp', inplace=True)
return df
sort_rows()
```
```sh:UNIX
!sort hightemp.txt -k 3
```
「逆順」という言葉の意味が、元の逆ということなのか降順ということなのか判然としませんが、後者の解釈で解いてみました。この問題については、UNIXコマンドだと短く書けるということを特に強く感じられますね。
### 19. 各行の1コラム目の文字列の出現頻度を求め,出現頻度の高い順に並べる
```py:Python
def count_freq():
df = pd.read_csv('hightemp.txt', sep='\t', header=None)
return df[0].value_counts()
count_freq()
```
```sh:UNIX
!cut -f 1 hightemp.txt | sort | uniq -c | sort -r
```
UNIXコマンドは少し長くなりましたが、まず1列目を切り出して(`cut -f 1`)、次にその出現頻度を求め(`sort | uniq -c`)、最後に出現頻度の逆順で並べる(`sort -r`)、という流れが分かりやすくなるように書いてみました。
ただ、pandasの`value_counts()`の優秀さも考えると、ここではPythonを使ったほうが分かりやすいかなという気がします。
## まとめ
+この章については以上ですが、間違いなどあったらコメントいただけると助かります。