例えばこんな財務データファイルがある。
ファイル名はSheet1a.csvで保存。
売上高列に続く数字は "116,861,000,000円 "。
つまり、金額がカンマで区切られてしまっている。これだとCSVの各項目(フィールド)の区切りのカンマなのか金額のカンマなのか、区別がつかない。これだと処理しづらい。
※ 国税庁も「財務諸表では金額の区切りに半角文字のカンマを使うな」と注意している。
一括処理に困るのだろう。
vimで開いてホールドバッファ機能で無理やり直すという手はある。
:%s/\("[0-9]\{3},[0-9]\{3},[0-9]\{3} "\),/\1,/g
これだとなんか違う。
数字カンマで区切られた3桁ごとにホールドしないと。
こうか。
:%s/\"\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3",/g
これだとうまくいくけど
例えば16行目の "1,119,000,000 " は直せていない(金額カンマの数が多いから)
数字のパターン分、手作業で繰り返してやるとうまくいく。
:%s/\"\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
:%s/\"\([0-9]\{1}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
:%s/\"\([0-9]\{2}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
が、手間が多いし間違いのモト。なかなかに面倒くさい。
一番てっとり早く直すには、いったんExcelで開いて「タブ区切りのCSV」として保存してから、金額のカンマを取り去るのが一番早いだろう。
しかしExcelを使うとなんか負けた気がする。シェル(bashとawk)またはPython3でやりたい。
まずはPython3で試す。pandasを使う。
>>> import pandas as pd
>>>
>>> pytable = pd.read_csv('Sheet1a.csv', encoding="utf8")
>>>
>>> pytable.head()
>>>
>>> pytable.tail()
csvファイルをpandasのデータフレームとして読み込んだ。
これの「営業利益」列だけ、金額のカンマを取り去ってみる。
str.replaceメソッドを使うとできるようだ(データフレームのメソッドか?)
>>> pytable.営業利益.str.replace(',', '')
で、これを全ての金額列にやるにはどうするんだ?
for文で回せばいいように思えるが、金額ではない列もあるから、「もし金額列だったら」または「列の訂正が NNN,NNN,NNNだったら」というif文が必要になる。
bashで(やりたいコードの)イメージを書くとこんな感じ。
これをPython3でやる必要がある。Python3でのfor文での回し方と、if文での正規表現のしかたを調べないといけない。あとでやる。
課題
・そもそもpandasのデータフレームなんだから、各列が数値データか文字列かを判定して「数値だったら一括して文字列の置き換え(金額カンマを無くす)」のような機能が(データフレームの)関数なりメソッドとしてありそうなものだ。調べる。
・財務諸表の金額はバカでかい。売上高で "116,861,000,000円 "てことは116億円てことだ(新自由主義が闊歩して大企業は好きなように儲けてやがる。国民は非正規ばかりで貧しくなっているわけだが)。
先ほど読み込んだデータフレームで売上高の列を表示してみると
>>> pytable.売上高
全ての行で金額のカンマの数は3個ある(例えば8の行でもカンマは3個ある)。
営業利益の列はこう。
>>> pytable.営業利益
こちらは、例えば8の行では金額のカンマは2個しかない。
つまり、列によって金額を区切るカンマが3個だったり2個だったりする。
先ほどの
>>> pytable.純利益.str.replace(',', '')
を使えば、3個だろうが2個だろうが一気に置き換えしてくれるけど、仮にこれを正規表現で実装しようとしたら、どうやればいいのか?
bashでやるとしたらイメージはこんな感じ?
ダメやな。カンマの数が不定だからこれだとキャプチャできない。これも調べる必要ある。
CSVはシンプルだけど奥深い。実務で一番使うからだと思う。手に覚えさせて一瞬で処理できるようにしたい。
※ vimのホールドバッファ機能で数字列のカンマを全部取り去るとこうなった。
かなり苦労はある。
: 17 w Sheet1b.csv
: 18 q!
: 19 %s/\"-\([0-9]\{2}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 20 %s/\"-\([0-9]\{1}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 21 %s/\"-\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 22 %s/\"-\([0-9]\{1}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 23 %s/\"-\([0-9]\{2}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 24 %s/\"-\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 25 %s/\"\([0-9]\{1}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 26 %s/\"\([0-9]\{2}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 27 %s/\"\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 28 k
: 29 %s/\"\([0-9]\{1}\),([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 30 %s/\"\([0-9]\{1}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 31 %s/\"\([0-9]\{2}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 32 %s/\"\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4",/g
: 33 %s/\"\([0-9]\{1}\),\"\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4\5",/g
: 34 %s/\"\([0-9]\{1}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4\5",/g
: 35 %s/\"\([0-9]\{2}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4\5",/g
: 36 %s/\"\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3\4\5",/g
: 37 w
: 38 %s/\"\([0-9]\{1}\),\([0-9]\{3}\).\([0-9]\{2}\) ",/"\1\2.\3",/g
: 39 %s/\"\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3",/g
: 40 %s/\"\([0-9]\{2}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3",/g
: 41 %s/\"\([0-9]\{1}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"\1\2\3",/g
: 42 %s/\"-\([0-9]\{1}\),\([0-9]\{3}\).\([0-9]\{2}\) ",/"-\1\2.\3",/g
: 43 %s/\"-\([0-9]\{1}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"-\1\2\3\4",/g
: 44 %s/\"-\([0-9]\{2}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"-\1\2\3\4",/g
: 45 %s/\"-\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"-\1\2\3\4",/g
: 46 %s/\"-\([0-9]\{3}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"-\1\2\3",/g
: 47 %s/\"-\([0-9]\{2}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"-\1\2\3",/g
: 48 %s/\"-\([0-9]\{1}\),\([0-9]\{3}\),\([0-9]\{3}\) ",/"-\1\2\3",/g
しかし、カンマさえ消えればあとはawkでも扱える。例えばこう。
$ cat Sheet1b.csv | awk -F, 'BEGIN{OFS=","}{print $2,$10,$11}' | more
Python3で統計量(describeメソッド)もしてみる。
>>> pytable = pd.read_csv('Sheet1b.csv', encoding="utf8")
>>>
>>> pytable.describe()
これは正しく動いた気がする。
countが58997で、bashの cat | wc と同じ数字だし。
いいぞ。手が覚えてきた。