Port 53

明日のための技術メモ

言語処理100本ノック 2020 第2章 前半

nlp100.github.io

いきなり5月になって暑くなった。冷やし中華はじめたい気分。
第2章 UNIXコマンドの前半(10-14まで)解説書きます。
最初はwith openして書いてたけど、pandasに慣れたかったのでpandasを使ってみた。

第2章後半はこちら

目次

この章で使うファイル

タブ区切りでアメリカの赤ちゃんの名前、性別、人数、生まれた年が記録された
テキストファイル。

 $ head popular-names.txt 
Mary    F   7065    1880
Anna    F   2604    1880
Emma    F   2003    1880
Elizabeth   F   1939    1880
Minnie  F   1746    1880
Margaret    F   1578    1880
Ida F   1472    1880
Alice   F   1414    1880
Bertha  F   1320    1880
Sarah   F   1288    1880

10. 行数のカウント

f:id:saturn-glave:20200502222237p:plain

pandasでやると圧倒的に楽だった。

ポイント

  • pandasでのファイル読み込みは read_csv を使う
    • CSVファイルでなくてもOK
    • sep で区切り文字、ヘッダがない場合はheader=Noneを指定
  • pandas.DataFrameの行数を数える時は len(df) を使う

解答コマンド

wcコマンドの-lオプションで行数を数えられる

wc -l popular-names.txt

解答スクリプト

# coding:utf-8
import pandas as pd

df = pd.read_csv('./popular-names.txt', sep='\t', header=None)
print(df)

print(len(df))

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

f:id:saturn-glave:20200502222249p:plain

一行ずつ読み込んで、str.replace( '\t', ' ' ) もいいけど、ここはpandasで。

ポイント

  • pandasでのファイル書き込みは to_csv を使う
    • これもCSVファイルでなくてもOK
    • sep で区切り文字、ヘッダがない場合はheader=Noneを指定
    • インデックス(行番号)不要の場合、index=Noneを指定
  • pandas.DataFrameの行数を数える時は len(df) を使う

解答コマンド

catコマンド+trコマンドでやる場合はパイプで連結
私の環境はmacで、sedでtabの表現が'\t'では効かず、Tabをコピペしないと認識しない。
本筋とそれるので詳しくは参考記事で。

cat popular-names.txt  | tr '\t' ' ' > out.txt

タブを空白文字に変換するexpandコマンドでも実現可能。 -tオプションはtabを何文字の空白で置換するか指定する。
今回は1文字で揃えるように指定した。
デフォルトは8文字らしい。

expand -t 1 popular-names.txt > out.txt

www.atmarkit.co.jp

解答スクリプト

新しくファイルを書き出す時に、デリミタをスペース1つにしてあげるだけ。

# coding:utf-8
import pandas as pd

path = './popular-names.txt'

df = pd.read_csv(path, sep='\t', header=None)

print(df)

df.to_csv('./out.txt', sep=' ', header=None, index=None)

参考記事

note.nkmk.me

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

f:id:saturn-glave:20200502222304p:plain

DataFrameにして列を切り出してあげる問題。
もうここから愚直に実装する気をなくす。

ポイント

  • cutコマンドのデフォルトのデリミタはTab
  • pandas.DataFrameでカラム名を入れたい時、 df.columns = [カラム名のリスト] を使う
  • pandas.DataFrameでカラム名を指定し列を参照する時、 df['カラム名'] と書く

解答コマンド

cutコマンドでそれぞれの列を別々のファイルに書き出すだけ。
-fでフィールド(列)を指定する。ただし、1からスタート

cut -f 1 popular-names.txt
cut -f 2 popular-names.txt

解答スクリプト

なくてもよかったけど、カラム名を入れてあげた。
カラム名入れないままやる場合、例えば1列目がほしい時はdf[0]になる

# coding:utf-8
import pandas as pd

path = './popular-names.txt'

df = pd.read_csv(path, sep='\t', header=None)
df.columns = ['Name', 'Sex', 'Count', 'Year']


col1 = df['Name']
col2 = df['Sex']

col1.to_csv('./col1.txt', header=None, index=None)
col2.to_csv('./col2.txt', header=None, index=None)

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

f:id:saturn-glave:20200502222316p:plain

分解したら戻す。鉄則。(ちがう)

ポイント

  • pandas.DataFrame同士の結合は、 df.concat([df1, df2]) を使う
    • 縦方向に連結(UNION文イメージ)だと df.concat([df1, df2]) でOK
    • 列同士の連結だと、df.concat([df1, df2], axis=1)のようにaxis=1 がオプションで必要

解答コマンド

pasteコマンドで2つのファイルをくっつけて表示できる。

paste col1.txt col2.txt

解答スクリプト

# coding:utf-8
import pandas as pd

p1 = './col1.txt'
p2 = './col2.txt'

df1 = pd.read_csv(p1, sep='\t', header=None)
df2 = pd.read_csv(p2, sep='\t', header=None)

df = pd.concat([df1, df2], axis=1)

df.to_csv('merge.txt', sep='\t', header=None)

参考記事

note.nkmk.me

14. 先頭からN行を出力

f:id:saturn-glave:20200502222329p:plain

第1章 07で出てきた argparse再登場。引数を受け取るところを関数化しておく。

ポイント

  • argparseで引数を取った時、デフォルトはstr型
  • pandas.DataFrameから先頭のn行を取り出す時、スライスdf[:n]df.head(n) を使う

解答コマンド

最初の3行だけほしい時の場合。
headコマンドは-n オプションで表示したい行数を指定できる。
デフォルトは先頭10行が表示される。

head -n 3 popular-names.txt

解答スクリプト

引数はstr型で返ってくるので、intにキャストする。(最初それに気づかず地味にエラー出した人)

# coding:utf-8
import argparse
import pandas as pd


def arg():
    parser = argparse.ArgumentParser(description='自然数')
    parser.add_argument('n', help='num')
    args = parser.parse_args()
    return(args.n)


def main():
    path = './popular-names.txt'
    n = int(arg())
    df = pd.read_csv(path, sep='\t', header=None)
    print(df[:n])
    # print(df.head(n))


if __name__ == "__main__":
    main()

参考記事

note.nkmk.me

参考

qiita.com