tab 区切りファイルの読込み
java julia perl python r ruby
#+File Created:
#+Last Updated:
tab 区切りファイル読込み/書込みの各言語でのやりかたの違いを整理する.
参考:
配列操作の比較表: Ruby, Python, JavaScript, Perl, C++ - bkブログ
http://0xcc.net/blog/archives/000043.html
1 はじめに
私は普段の生活においては perl でプログラムを書いている.
ささっと書いて捨てちゃうことが多いが,
そのようなプログラムで最も多いぱたーんは以下のようなものである:
- 何か(tab 区切りとかの)ファイルを読込む.
- 何かやる(読み込んだデータを加工したり計算したりする).
- 別のファイルに結果等を書き出す.
Python を始めとした色んな言語をこれから学んでいくにあたって,
上記操作のやり方の違いををまずは見ていくのが自分にとっては一番しっくり来るかなぁと思ったのでまとめておく.
2 Perl
これが基準
1: use strict; 2: use warnings; 3: 4: my $ifile='input.txt'; 5: my $ofile='output.perl.txt'; 6: 7: # input 8: open my $fh,"<",$ifile; 9: my $cnt=0; 10: my @head; 11: my $data; 12: while(<$fh>) { 13: chomp; 14: my @bf=split(/\t/,$_); 15: # 様々な状況に対応できるように 16: unless($cnt) { # header 17: @head=@bf; 18: }else { # data 19: push(@{$data},\@bf); 20: } 21: $cnt++; 22: } 23: close $fh; 24: 25: # output 26: my $prnt; 27: $prnt=join("\t",@head)."\n"; 28: for my $d (@{$data}) { 29: $prnt.=join("\t",@{$d})."\n"; 30: } 31: open my $ofh,">",$ofile; 32: print $ofh $prnt; 33: close $ofh; 34: 35: print $prnt; # 標準出力にも書き出す場合
name age origin gender idata fdata type foo 10 jpn M 50 0.25 X bar 30 usa F 25 0.38 P hoge 10 jpn F 4 1 P fuga 40 eng M X fuga 35 F 9 0.1 X
header の名前を key にして hash の配列にしてもよい.
3 Python
python での注意点と参考 URL:
- タブ区切りのファイルを読む
- unless の代わりに not を使う
- 【python】unlessがないのでnotを使う | chat-blog
http://chat-rate.com/it/255
- 【python】unlessがないのでnotを使う | chat-blog
- 文字列を数値に変換する(めんどくさいなぁ…)
- Pythonメモ: 文字列を数値に変換する
http://yoshi-python.blogspot.jp/2009/09/blog-post_4656.html
- Pythonメモ: 文字列を数値に変換する
- 辞書オブジェクトの使い方
- Python - 辞書(ディクショナリ)の使い方 - ざっくりん雑記
http://azuuun-memorandum.hatenablog.com/entry/2015/05/01/075000
- Python - 辞書(ディクショナリ)の使い方 - ざっくりん雑記
- ファイルに書き込み
- Python: テキストファイルに書き込み – write()、writelines()メソッド
http://www.yukun.info/blog/2008/09/python-file-write-writelines.html
- Python: テキストファイルに書き込み – write()、writelines()メソッド
1: import sys 2: 3: ifile='input.txt' 4: ofile='output.python.txt' 5: 6: fh=open(ifile,'r') 7: # lines=fh.readlines() # 全部読み込んで lines に入れる場合. 8: 9: # input 10: # perl と同じ感じでかいてみる. 11: cnt=0 12: head=[] 13: data=[] 14: for li in fh: # li に 1 行毎(改行含む)が入ってくる 15: bf = li[:-1].split("\t") # 後ろの改行を取り除いて(li[:-1]) split 16: if not cnt: 17: head=bf 18: else: 19: data.append(bf) # push ではなく append 20: cnt+=1 21: fh.close 22: 23: # 文字列として入ってることを確認する. 24: #print(head) 25: #print(data) 26: 27: # hash の配列として入れてみる 28: # hashs[0]['name'] こんな感じで各々の要素にアクセスする. 29: hashs=[] 30: for dr in data: 31: hash={} 32: # print(dr) 33: # sys.exit(0) # ここで終わる時(for debug) 34: for j,d in enumerate(dr): 35: # j が 1 か 4 のときは, 整数として入れる 36: # j が 5 のときは, 浮動小数点として入れる. 面倒... 37: dk = d 38: if not d=='': 39: if j==1 or j==4: 40: dk = int(d) 41: elif j==5: # elsif ではなく elif 42: dk = float(d) 43: hash[head[j]]=dk 44: hashs.append(hash) 45: 46: #print(hashs) 47: #print(hashs[0]['name']) 48: 49: # output 50: ofh=open(ofile,'w') 51: prnt="\t".join(head)+"\n" 52: for d in data: 53: prnt+="\t".join(d)+"\n" 54: print(prnt) 55: ofh.write(prnt) 56: ofh.close()
name age origin gender idata fdata type foo 10 jpn M 50 0.25 X bar 30 usa F 25 0.38 P hoge 10 jpn F 4 1 P fuga 40 eng M X fuga 35 F 9 0.1 X
dataframe とか使う場合はまた別でまとめようと思うが, 一応書いておく.
import pandas as pd ifile='input.txt' ofile='output.pandas.txt' df = pd.read_csv(ifile,sep="\t",header=0) # 何かやる # 0 行目の 'name' 列を書き換え df.ix[0,'name'] = 'foo2' df.to_csv(ofile,sep="\t",index=False) print(df)
name age origin gender idata fdata type 0 foo2 10 jpn M 50.0 0.25 X 1 bar 30 usa F 25.0 0.38 P 2 hoge 10 jpn F 4.0 1.00 P 3 fuga 40 eng M NaN NaN X 4 fuga 35 NaN F 9.0 0.10 X
4 Julia
Julia での注意点と参考 URL:
全般的に, 型を意識する必要がある(? 全部 Any でいいのかなぁ)のでちょっと面倒くさい印象.
文字列は '' ではなく "" で囲わないといけない(Java と同じ)
and, or は && || (これも Java と同じ)
if 文は, if .. elseif .. end という感じで書く.
関数は function hoge(x) … end という感じで書く.
配列の添字は 1 から始まる.
二次元配列は arr[1,2] (1行2列目), 配列の配列は arr
hash の宣言: Dict{keyの型, value の型}()
主な型指定: Int64, Float64, ASCIIString, Any(何を入れてもいい型)
文字列連結は "." でも "+" でもなく, 何と "*" を使うらしい. 何で?
- 基本
- Juliaことはじめ - 0x00 nullbyte blog
http://nullbyte.hatenablog.com/entry/2015/05/27/013949
- Julia Language Programming (Julia の基礎知識)
http://www.geocities.jp/m_hiroi/light/julia01.html#abc02
- Juliaことはじめ - 0x00 nullbyte blog
- ファイルの開き方など
- Introducing Julia/Working with text files - Wikibooks, open books for an open world
https://en.wikibooks.org/wiki/Introducing_Julia/Working_with_text_files
- Juliaでファイル操作 | mwSoft
http://www.mwsoft.jp/programming/julia/file.html
- Julia でデータのセーブとロード - yomichi's blog
http://yomichi.hateblo.jp/entry/2015/12/19/014201
- <紙>さんLoG Julia 学習:ファイル入出力
http://jn1inl.blog77.fc2.com/blog-entry-2209.html
- Introducing Julia/Working with text files - Wikibooks, open books for an open world
- 型について
- Julia カテゴリーの記事一覧 - 0x00 nullbyte blog
http://nullbyte.hatenablog.com/archive/category/Julia
- Julia カテゴリーの記事一覧 - 0x00 nullbyte blog
- 配列など
- Learn Julia in Y Minutes
https://learnxinyminutes.com/docs/julia/
- Julia入門 配列 - 0x00 nullbyte blog
http://nullbyte.hatenablog.com/entry/2015/05/30/001107
- Julia の超入門(配列編) - 中野智文
http://blog.goo.ne.jp/nakano-tomofumi/e/135ed54502fd7a23d4b53fc3340240d2
- 光学設計者の学習メモ: Julia Array操作の基本をメモ。
http://retrofocus28.blogspot.jp/2014/11/julia-array.html
- Learn Julia in Y Minutes
- ハッシュ等
- Julia入門 辞書(ハッシュテーブル)、Set型について - 0x00 nullbyte blog
http://nullbyte.hatenablog.com/entry/2015/06/03/000106
- Julia入門 辞書(ハッシュテーブル)、Set型について - 0x00 nullbyte blog
- join
- 配列から文字列、文字列から配列への変換 (convert array to string, string to array) - MATLAB移民のためのJulia tips
http://julia.hatenablog.jp/entry/2016/04/17/144129
- 配列から文字列、文字列から配列への変換 (convert array to string, string to array) - MATLAB移民のためのJulia tips
- 文字列連結
- Julia の文字列結合演算が積 (*) である理由(他言語との比較) - Moriturus te saluto
http://dsng.hatenablog.com/entry/2014/07/03/214526
- Julia の文字列結合演算が積 (*) である理由(他言語との比較) - Moriturus te saluto
1: ifile="input.txt" 2: ofile="output.julia.txt" 3: 4: #fh=open(ifile,"r") 5: #str=readall(fh) # 一気に読み込む場合はこうする. 6: #print(str) 7: 8: head=[] #head=Array{Any,1}() 9: data=Array{Array{Any,1},1}() # 1x1 の, 配列の配列を作っておく. 10: # data=[][] これじゃダメらしい. 11: 12: # filehandle は以下のように書くのが普通のようだ 13: open(ifile,"r") do fh 14: cnt=0 15: for li in eachline(fh) # 1 行ずつ読んでいく 16: #print(li) 17: li = chomp(li) # 改行を取り除く 18: # li = rstrip(li,'\n') # 改行削除はこれでもいい 19: bf = split(li,"\t") # \t で split 20: # println(bf) 21: if cnt == 0 # 1 行目(header) 22: append!(head,bf) # head=bf ではエラーとなる. append! を使う 23: #for i in 1:length(bf) 24: # push!(head,bf[i]) 25: #end 26: else # 2 行目以降(でーた) 27: push!(data,bf) 28: end 29: cnt+=1 30: end 31: end 32: # close(fh) # 自動で閉じるので書かなくてもいいっぽい. 33: 34: # data[][] を hash の配列にしてみる. 35: hashs=[] 36: for dt in data 37: hash = Dict{Any,Any}() 38: for i in 1:length(dt) 39: hash[head[i]]=dt[i] 40: end 41: push!(hashs,hash) 42: end 43: 44: println(head) 45: #println(data) 46: #println(data[1][1]) 47: 48: println(head[1]) 49: println(hashs[1]["fdata"]) 50: println(hashs[2]["fdata"]) 51: # exit() プログラムを終わらせるとき 52: 53: # 型キャスト的なことは, parse(type,str) を用いる 54: itx = parse(Float64,hashs[1]["fdata"]) + parse(Float64,hashs[2]["fdata"]) 55: println(itx) 56: 57: # ファイル書き込み 58: open(ofile,"w") do fp 59: write(fp,join(head,"\t")*"\n") 60: for d in data 61: write(fp,join(d,"\t")*"\n") 62: end 63: end
Any["name","age","origin","gender","idata","fdata","type"] name 0.25 0.38 0.63
5 Ruby
Ruby での注意点と参考 URL:
- 基本
- 逆引きRuby - ファイルアクセス
http://bit.ly/2am8jkn
- 【Ruby】表示メソッドについて(print,puts,p) - TASK NOTES
http://www.task-notes.com/entry/20141109/1415520719
- 逆引きRuby - ファイルアクセス
- hash
- 【Ruby】配列とハッシュの基本的な使い方 - TASK NOTES
http://www.task-notes.com/entry/20141115/1416045573
- 【Ruby】配列とハッシュの基本的な使い方 - TASK NOTES
- 型キャスト(to_f)
- 数値クラスを変換する - 数値(Numeric)クラス - Ruby入門
http://www.rubylife.jp/ini/numeric_class/index2.html
- 数値クラスを変換する - 数値(Numeric)クラス - Ruby入門
- each_with_index (python の enumerate に相当)
- Python's enumerate in Ruby? - Stack Overflow
http://stackoverflow.com/questions/13936922/pythons-enumerate-in-ruby
- Python's enumerate in Ruby? - Stack Overflow
- join 等(文字列連結)
ruby の文字列連結は "+" あるいは "<<"
- Rubyの文字列連結に関して知っておくべきこと - Qiita
http://qiita.com/Kta-M/items/c7c2fb0b61b11d3a2c48
- Rubyの文字列連結に関して知っておくべきこと - Qiita
1: ifile='input.txt' 2: ofile='output.ruby.txt' 3: 4: fh=open(ifile,"r") 5: # str=fh.read # 一気に全部読み込む場合 6: cnt=0 7: head=[] # head=Array.new でも良い 8: data=[] 9: while li = fh.gets 10: #print li 11: li=li.chomp # 改行取り除き 12: bf=li.split("\t") # tab で split 13: #print(bf) 14: #exit 15: if cnt==0 16: head=bf 17: else 18: data.push(bf) 19: end 20: cnt+=1 21: end 22: fh.close 23: 24: print(head) 25: print("\n") 26: #print(data[0]) 27: #exit ここで終わるとき (for debug) 28: 29: # hash の配列にしてみる. 30: hashs=[] 31: for dr in data 32: hash={} 33: dr.each_with_index do |d,j| # enumerate 34: dk=d 35: if not d=='' 36: if j==1 or j==4 37: dk=d.to_i # 整数型へキャスト 38: elsif j==5 39: dk=d.to_f # 浮動小数点型へキャスト 40: end 41: end 42: hash[head[j]]=dk 43: end 44: hashs.push(hash) 45: end 46: 47: print(hashs[0]) 48: print("\n") 49: 50: itx = hashs[0]["fdata"] + hashs[1]["fdata"] 51: puts(itx) 52: 53: # file 書き出し 54: ofh=open(ofile,"w") 55: ofh.write(head.join("\t")+"\n") 56: for dt in data 57: str=dt.join("\t") 58: ofh.write(str+"\n") 59: end 60: ofh.close
["name", "age", "origin", "gender", "idata", "fdata", "type"] {"name"=>"foo", "age"=>10, "origin"=>"jpn", "gender"=>"M", "idata"=>50, "fdata"=>0.25, "type"=>"X"} 0.63
6 R
おまけ(1)
read.table でファイルを読むプログラムを一応作っておく.
R での注意点と参考 URL:
- read.table()
- R-Source 40. ファイルからデータを読み込む
http://cse.naro.affrc.go.jp/takezawa/r-tips/r/40.html
- R-Source 40. ファイルからデータを読み込む
- write.table() のパラメータ
- R: データ出力
http://www.is.titech.ac.jp/~mase/mase/html.jp/temp/write.table.jp.html
- R-Source 45. ファイルへのデータ出力
http://cse.naro.affrc.go.jp/takezawa/r-tips/r/45.html
- R: データ出力
1: ifile <- 'input.txt' 2: ofile <- 'output.R.txt' 3: 4: data <- read.table(ifile,sep="\t",head=T) 5: data 6: names(data) # header の名前 7: data['name'] # 列の取得 8: 9: # quote=F : "" を付けない 10: # append=F : 上書き 11: write.table(data,ofile,quote=F,sep="\t",col.names=T,row.names=F,append=F,na="")
name age origin gender idata fdata type 1 foo 10 jpn M 50 0.25 X 2 bar 30 usa F 25 0.38 P 3 hoge 10 jpn F 4 1.00 P 4 fuga 40 eng M NA NA X 5 fuga 35 F 9 0.10 X [1] "name" "age" "origin" "gender" "idata" "fdata" "type" name 1 foo 2 bar 3 hoge 4 fuga 5 fuga
7 Java
おまけ(2)
Java での注意点と参考 URL:
- join(Java8)
- あなたのJavaコードをスッキリさせる、地味に便利な新API 10選(前編) - Taste of Tech Topics
http://acro-engineer.hatenablog.com/entry/2014/03/12/112402
- あなたのJavaコードをスッキリさせる、地味に便利な新API 10選(前編) - Taste of Tech Topics
- 可変長の配列は List(ArrayList), hash は Map(HashMap) を用いるが何か面倒
push するために List という配列の拡張を使ったが, 何かイマイチな感じ.
- 【Java】配列・リスト・マップの使い方についての基本 - TASK NOTES
http://www.task-notes.com/entry/20140923/1411477102
- ArrayListクラス - コレクション(ArrayList) - Java入門
http://www.javadrive.jp/start/arraylist/index1.html
- 【Java】配列・リスト・マップの使い方についての基本 - TASK NOTES
- ファイル書き出し
- 便利な書き込み用クラス - テキストファイルの入出力 - Java入門
http://www.javadrive.jp/start/stream/index7.html
- 便利な書き込み用クラス - テキストファイルの入出力 - Java入門
- trim()
- 先頭又は最後の空白を取り除く(trim) - Stringクラス
http://www.javadrive.jp/start/string_class/index4.html
- 先頭又は最後の空白を取り除く(trim) - Stringクラス
- 拡張 for 文
- 【Java】for文と拡張for文の違い - Qiita
http://qiita.com/Mocacamo/items/290457f9d378ad80ddba
- 【Java】for文と拡張for文の違い - Qiita
1: import java.io.File; 2: import java.io.FileReader; 3: import java.io.BufferedReader; 4: import java.util.HashMap; 5: import java.util.Map; 6: import java.util.List; 7: import java.util.ArrayList; 8: import java.io.FileWriter; 9: import java.io.BufferedWriter; 10: import java.io.PrintWriter; 11: public class fread { 12: public static void main(String[] args) { 13: String ifile="input.txt"; 14: String ofile="output.java.txt"; 15: 16: List<Map> data = new ArrayList(); 17: List<String> head = new ArrayList(); 18: try { 19: File file=new File(ifile); 20: BufferedReader br = new BufferedReader(new FileReader(file)); 21: int cnt=0; 22: String str; 23: while((str=br.readLine())!=null) { 24: String [] row=str.split("\t"); 25: if(cnt==0) { 26: for(String s : row) { // 何か気持ち悪いけど 27: head.add(s); 28: } 29: }else { 30: Map<String,String> hash = new HashMap(); 31: int i=0; 32: for(String s : head) { 33: hash.put(s,row[i++]); 34: } 35: data.add(hash); 36: } 37: cnt++; 38: } 39: }catch(Exception e) { 40: System.out.println(e); 41: } 42: System.out.println(String.join("\t",head)); 43: System.out.println(data.get(0).get("name")); 44: // System.exit(0); // 終わるとき 45: 46: // ファイル書き出し 47: try { 48: File ofh = new File(ofile); 49: FileWriter fw = new FileWriter(ofh); 50: BufferedWriter bw = new BufferedWriter(fw); 51: PrintWriter pw = new PrintWriter(bw); 52: String prnt=String.join("\t",head)+"\n"; 53: for(Map mp : data) { // 拡張 for 54: for(String s : head) { // 苦肉の策 55: prnt+=mp.get(s)+"\t"; 56: } 57: prnt.trim(); // 先頭, 最後の空白を取り除く 58: prnt+="\n"; 59: } 60: System.out.print(prnt); 61: pw.print(prnt); 62: pw.close(); 63: }catch(Exception e) { 64: System.out.println(e); 65: } 66: } 67: }
name age origin gender idata fdata type foo name age origin gender idata fdata type foo 10 jpn M 50 0.25 X bar 30 usa F 25 0.38 P hoge 10 jpn F 4 1 P fuga 40 eng M X fuga 35 F 9 0.1 X
8 かんそう
perl, python, ruby は似たような感じ.
ruby は書きやすかった. きっちりしてる感じ.
ruby に比べると python はやっぱり何か, 開きっぱなしで閉じてない感じがいまんとこしっくりこないんだけどなぁ.
常に何か忘れてるような, そんな一抹の不安を覚えたりします. 慣れればなんともないんでしょーか.
変数のスコープもよくわかんないし…
Julia も上記の言語と同じような感じでいけるのかなぁと思っていたのですが, 何かいちいち勝手が違う感じ.
こんな感じでうまくいくかな, という適当さが全然通用しなかった. python, ruby は適当にやっても何とかなったんだけど…
色々と調べることが多かった.
つーか文字列の連結が "*" って意味わかんないような… こういうの検索とかで探しにくいから困るんだよなぁ.
"." か "+" か, 最悪 "&" とか, わかりやすい感じにして欲しいなぁ… あるいは concat とか.
R, Java はおまけでやってみましたが, いまいちうまく比較できなかったのでやらなくてもよかったかも.