なまもの備忘録

気になったことをつらつらと書いていきます

(C++)大きさ不明の2次元配列データを2次元vectorに読み込む方法

3/22 17:10

大きさの分からない2次元配列データを2次元vectorに格納する方法がいくら調べても見つからなかったので、分からないなりに調べつつコードを作成してみた。
下記のコードであれば、データが数値のcsvファイルならなんでも読み込めるはず。

2017/10/20
久しぶりにコードを見返したところ、いくつか気になった点があったので修正。

修正点
 任意の数値型のvectorに対してGetdata関数が適用できるようにした。
 using namespace std;を削除した。

2018/2/25
コードを見返したところ、いくつか気になった点が出てきたので修正。

修正点
 引数で指定したファイルが見つからない場合に例外を返却するよう修正。
 引数で受け取ったvectorに副作用でデータを格納するのではなく、関数の返り値として読み込みデータを返却するように変更。
 第2引数で空読みしたい行数を指定できるよう変更。
 ループ変数名と型(int->std::size_t)の修正。

2018/6/4
頂いたコメントを受けて修正。その他仕様に至らぬ点があったため修正。

修正点
 コメントへの返信に記載。
 csvファイルの末尾に空行がある際、dataの行数も空行分大きくなってしまう点を修正。
 csvファイルの各行末に","が存在する場合、行末のデータを重複して読み込んでしまう点を修正。

//大きさ不明の2次元配列データを2次元vectorに読み込むGetdata関数

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <exception>

template<typename Num_type>
std::vector<std::vector<Num_type> >
Getdata(std::string filename, std::size_t ignore_line_num = 0){
    std::ifstream reading_file;
    reading_file.open(filename, std::ios::in);
    if(!reading_file)
        throw std::invalid_argument(filename + std::string("could not be opened."));
    
    std::string reading_line_buffer;
    
    //最初のignore_line_num行を空読みする
    for(std::size_t line = 0; line < ignore_line_num; line++){
        getline(reading_file,reading_line_buffer);
        if(reading_file.eof()) break;
    }
        
    Num_type num;
    char comma;

    std::vector<std::vector<Num_type> > data;
        
    while(std::getline(reading_file, reading_line_buffer)){    
        if(reading_line_buffer.size() == 0) break;
	std::vector<Num_type> temp_data;
	std::istringstream is(reading_line_buffer);
	while(is >> num){
	    temp_data.push_back(num);
	    is >> comma;
	}
	data.push_back(temp_data);
    }

    return data;
}

//動作テスト                                                                      
int main(){
    //読み込みデータ格納先2次元vectorを用意する、今回の数値型はなんでも良い
    std::vector<std::vector<double> > data;

    std::string filename("test.csv");
    
    //Getdata関数を使う    
    //テンプレート引数として読み込みデータの型名を指定(今回はdouble)。
    //第1引数に読み込みたいファイルのカレントディレクトリからのパスを指定する
    std::cout << "reading " << filename << "..." << std::endl;
    data = Getdata<double>(filename);

    for(std::size_t line=0 ;line < data.size() ;line++){
	for(int column=0 ;column < data[line].size() ;column++){
	    std::cout << data[line][column] << " ";
	}
	std::cout << std::endl;
    }
    std::cout << std::endl;

    //最初のn行を読み飛ばす場合には第2引数にnを入れる
    std::size_t n = 3;
    std::cout << "reading " << filename << "..." << std::endl;
    data = Getdata<double>(filename,n);

    for(std::size_t line=0 ;line < data.size() ;line++){
	for(std::size_t column=0 ;column < data[line].size() ;column++){
	    std::cout << data[line][column] << " ";
	}
	std::cout << std::endl;
    }
    std::cout << std::endl;
    
    return 0;
}

C++でのファイルの入出力

2/25 17:28

C++でのファイルからの入力、ファイルへの出力の仕様がよく分からなくてもやもやする。検索をしてもどうもC仕様のやり方とC++仕様のやり方があるようで、この二つが混ざって出てくる上に痒いところに手が届かないサイトしかない。あまりにイライラするのでとりあえず今欲しい情報をまとめて調べて、後で忘れた時のために書いておくことにする。
ついでにフラフラとサイトを彷徨っていたら何やら良さそうなC++の本が紹介されていたのでメモ代わりに残しておくことにする。

Accelerated C++ - 効率的なプログラミングのための新しい定跡
Exceptional C++ - 47のクイズ形式によるプログラム問題と解法

まず、stdio.hのヘッダファイルを使った入出力の方法をまとめてみる。これはC言語関数辞典(http://www.c-tipsref.com/reference/stdio.html)に載っていたのでC言語様の入出力方法なのだろう。欲をいえば覚えることは減らしたいので文法は全てC++様のものにしたいのだが、面倒なので当分はこちらをまとめてこちらを使うことにする。
fopenでファイルを開いて、入出力関数でごにょごにょし、fcloseでファイルを閉じるのが一連の流れになる。
openの戻り値は事前に宣言したファイルポインタに入れる。これは、fopenが「開いたファイルの情報を持っているオブジェクト」のポインタを返す関数だからみたいだ。
ちなみにファイル型はstdio.hの中でtypedefによって定義されている型なので、stdio.hをincludeすれば宣言できる様になる。
つまり、test.dataを読み込もうとしたら

#include <stdio.h>
...
FILE * fp;
...
fp = fopen("test.data", "r");

のようなコードを書けば良い。この時、fopenの二つ目の引数の”r”は読出し専用モードで開くことを指定している。
このようなモード指定は他にもある。
f:id:purple-apple:20170205200133p:plain
(http://www.c-tipsref.com/reference/stdio/fopen.html)

今回僕が知りたいのは開いたファイルの情報を上書きするのではなく、その末尾に追加で情報を加える方法なのだが、”a”で指定できる追加書き込みがどうも欲しい機能を提供してくれそうだ。
write モードではファイルを消してしまう事になるので、ファイル を消さずに書き込みを行うには append モードを用いる。(http://www.wakhok.ac.jp/~kanayama/C/02/node165.html)とあるので、これでできそう。というか全部更新モードでいいじゃないか。まあエラーを吐かせたほうが云々というのはあるのだろうけど。

ちなみにファイルのクローズは

fclose(fp);

のように書くが、プログラム終了時にはオープンしたファイルは必ずクローズされるらしいので途中でモードを変更したい場合以外は特にする必要もないみたい。
ファイルからの情報の読み込みにはfscanfを使う。使う時は下のような感じ。

double one_data;
fscanf(fp,"%lf ",&one_data);
data[t][i] = one_data;

一つ目の変数で入力に使うオブジェクトのポインタを指定(これをストリーム(プログラム-入出力間のデータの流れ)をしていすると言うらしい)している。
二つ目の引数は書式文字列と言うらしい。

%[代入抑止文字][フィールド幅][長さ修飾子]変換指定子 ※[]内は省略可能

という形式で記述する。代入抑止文字の部分には、もしを書くと指定した文字が読み込まれずに破棄される。例えば、%2cとやると先頭の2文字が破棄されるらしい。
長さ修飾子については以下のような感じで、引数の型を指定している。なんで長さなのかは謎。知っている方いたら是非とも教えていただきたいです。
[f:id:purple-apple:20170205200351p:plain]
(https://ja.wikipedia.org/wiki/Scanf)
変換指定子については以下
[f:id:purple-apple:20170205200406p:plain]
(https://ja.wikipedia.org/wiki/Scanf)
読み取った引数を戻す際に変換を加えることができる。
3つ目の引数には適切な方の変数を入れて、以降この変数に入ったデータを扱う。

for(int t = 0; t < TIME; t++){
          for(int i = 0; i< CELL ;i++){
            fscanf(fp,"%lf ",&one_data);
            data[t][i] = one_data;
          }
        }

のように使用すると、fpがさすオブジェクトのデータを勝手に順々にスキャンしていってくれる。また、改行は特に意識されないみたい。
とりあえずこの辺まで調べて満足したので終わり。

3/18 C++仕様の入出力についても簡単にメモしておく。

#include <fstream>
//入力
std::ifstream ifs(“ファイルパス”); //ifsにファイルの内容が読み込まれる
std::getline(ifs,line);//lineにifsの内容を1行ずつ読み込む

//出力
std::ofstream ofs(“ファイルパス”);
off << “書き込みたい文字列等” << std::endl;

軽いプログラムの時はこっちのほうが楽そう。

OpenCVの環境構築を頑張ってみた(Mac)

TLでOpenCVの環境構築に苦戦している人がいたので、それに刺激されて僕の方も一度放棄したOpenCVの環境構築に再挑戦してみることにした。
とりあえず参考になりそうなサイトとして
http://stackoverflow.com/questions/24985713/opencv-undefined-symbols-for-architecture-x86-64-error
http://www.yasutomo57jp.com/2010/09/01/linuxopencvを入れて適当なコードをコンパイルするまで/ などを見つけたのでこれらを見つつ進めてみる。
とりあえずテストコードをネットから拾ってきてg++でコンパイルしたが、

Undefined symbols for architecture x86_64:
  "_cvCreateImage", referenced from:
    _main in testopencv-7eff1a.o
  "_cvDestroyAllWindows", referenced from:
      _main in testopencv-7eff1a.o
  "_cvGetSize", referenced from:
      _main in testopencv-7eff1a.o
  "_cvLoadImage", referenced from:
      _main in testopencv-7eff1a.o
  "_cvNamedWindow", referenced from:
      _main in testopencv-7eff1a.o
  "_cvReleaseImage", referenced from:
      _main in testopencv-7eff1a.o
  "_cvShowImage", referenced from:
      _main in testopencv-7eff1a.o
  "_cvSmooth", referenced from:
      _main in testopencv-7eff1a.o
  "_cvWaitKey", referenced from:
      _main in testopencv-7eff1a.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

こんな感じで弾かれてしまった。どうもリンクがうまくいっていないみたい?
「(1)cv.hなどのOpenCVのヘッダファイルが何処にあるのかの指定と,(2)libcvなどのOpenCVのライブラリが何処にあるのかの指定が必要です.」
とのことらしい。
まず,(1)のヘッダファイルについては

pkg-config --cflags opencv  

でリストアップ可能で、(2)のライブラリについても同様に

pkg-config --libs opencv  

を実行することでリストアップできるらしい。
この結果を

g++ -o main main.cpp -I/usr/include/opencv -L/usr/lib/opencv -lcv -lhighgui(この-o main main.cppというのは実行ファイルをmainという名前で作成するってことだろうか?)  

みたいな感じでg++の引数として渡してやれば良いらしい。
また

g++ -o main main.cpp `pkg-config --cflags opencv` `pkg-config --libs opencv`  

こう書けば実行時に勝手に後ろにつけたコマンドを実行して、その結果を引数として取ってくれるとか。
試してみるとうまく実行された。ちなみに同じディレクトリにMakefile(今回名前はGNUmakefileにしたがこれでないといけないかはよく分からない)を作成して

(ファイル名): (ファイル名).cpp
     g++ (ファイル名).cpp -o (希望の実行ファイル名) `pkg-config --cflags opencv` `pkg-config --libs opencv`  

と書き込んでおくと

make  

とコマンドを打つだけで実行ファイルを作ってくれる。これでひとまずは安心?か。OpenCV3の方がこれでうまくいくのかはよく分からない。

El Capitanで日本語の入力速度が我慢ならないほど落ちた場合の対処レポ

日記をつけている最中に変換の重さが気になり、直す作業をしながらログがてらにとっていた記録をそのままあげているので乱文、かつ序盤は問題を誤認識しています。

それと、今自分はrtdfファイルをテキストエディットで編集してに気をつけているのだが、これだとどうもある程度テキストファイルが重くなると書き込みに時間がかかるようになってしまうらしい。少し他の方法を模索しないといけない。いっその事全部livedoorブログに移転してしまおうか。
とりあえず緊急避難的に今日の分だけ別ファイルに写してみたのだが、それでも重い。
どうやら今開いているファイルが問題というわけではないらしい。
もしかしたらこのファイルを入れているディスクイメージに割り振っている容量が問題なのだろうか。
少し多めの容量を割り振ってディスクイメージを作り直してみよう。
それよりもデスクトップ保存してそれで変換の速さを見てみた方が良いか。
試してみたところ変換速度は速くならなかったのでおそらく原因はディスクイメージではない。

http://itea40.jp/technic/mac-troubles/remedy-character-input-of-mac-is-slow/

少しこのページに従って直してみる。
まずディスクのアクセス権の修復を試みようとしたのだが、El Capitanではそのようなことはできないらしい。なんでGUI変えちゃうの!!
ひとまず次の項目を試して見る。Font bookの重複をチェックしたところ、それはなさそうだった。
次に、「英字入力中のスペル自動変換やスペルチェックの設定を変更する」を試して見る。
とりあえずスペルの自動変換機能をオフにしてやってみる。しかしこれでも遅い。
とりあえずスペルの自動変換機能をオフにしてやってみる。しかしこれでも遅い。
とりあえずスペルの自動変換機能をオフにしてやってみる。しかしこれでも遅い。
ONとOFFで比べてみたが、大した差はなかったので自動変換が問題でもなさそうだ。
ライブ変換をOFFにして改めて入力を試みたが、やはり遅い。
バックグラウンドのアプリケーションも3つしかないので(Readcubu,canonのプリンターのやつ,iTuneHelper)たいして影響しているとは思えない。
アクティビティモニタから何が容量をくっているのか見てみると、日本語入力プログラムが凄まじい容量の(40~90パーセント)CPUを食いつぶしているのがわかった。
システム環境設定のアクセシビリティからコントラストを上げるを選択すると治るとかいう面白い記事があったので試してみたがこれはもちろんダメだった(http://kiririmode.hatenablog.jp/entry/20150907/1441551600)。
セーフブートで起動とかも面倒だけど試してみるべきか。
それより先に日本語入力システムを切り替えよう。
いや、その前にデスクトップをきれいにしてみよう。
デスクトップに出しっぱなしにしていたファイルを整理用のフォルダに分けてみたが、多少動きが改善されたように思う。ただやっぱり日本語入力プログラムは90%近くCPUをくっているしでどうもおかしい。
変換学習をリセットしたら元の速度に戻らないだろうか。
というわけで変換学習をリセットした状態で今打っているのだが、前よりも多少改善されたような気がする。CPUの方はどうなっているかというとまあ70%とか言ってしまっているので実はあまり変わっていないのかもしれないけど。今90%近くまで上がっていた。
やはり問題はあまり改善されていなさそう。ライブ変換は便利だから使いたいのだけど、こうも遅いとストレスがたまってしまう。
こういうものだと思って我慢して使うしかないのだろうか。Google日本語入力を入れて試してみようと思う。
その前に

https://medium.com/backstage-of-backspace/el-capitan日本語入力やめました-74ba62545d31#.kc5nl15ba

にセーフブートしてみるという手軽な方法が書いてあったのでこれを試してみることにする。

「1. Macをシステム終了します(システム終了できない場合は、電源ボタンを長押しで終了)
2. 電源ボタンを押します
3. 起動音が聞こえたらすぐに「shift」キーを押してそのままにします。
4. 画面に Apple ロゴが表示されたら「shift」キーを放します。 ログインウィンドウが表示されたら、ユーザ名とパスワードの入力をお願いいたします。 「セーフモード」というモードで起動してまいります。」

ということらしい。
というわけでセーフモードで起動してみた。日本語入力プログラムも10%以下のCPU消費と非常に快適に入力ができている。ライブ変換もONにしてみよう。
ONにしてみた。これでどうだろう。変換速度は僕のタイピング速度についてきてくれているので非常に快適だ。日本語入力プログラムは50%近くCPUを食っているが、遅さは気になるほどではない。
同じ文章をライブ変換なしで入力してみる。変換速度は僕のタイピングについてきてくれているので非常に快適だ。日本語入力プログラムは多くても15%程度しかCPUを食っていない。これなら問題はなさそうだ。
ちなみに記事を読んでいるとセーフモードで起動=セーフブートみたいだ。
セーフモードではたまに画面に白い横線のような、昔のテレビでありそうな画面の乱れが生じるのが気になるけど、特に他には問題はなさそう。
これで元の起動方法に戻してみよう。
どうやらセーフモードにしなければ画面の乱れはなくなるみたいだ。変換速度は元に戻っていて非常に快適に入力ができる。
ライブ変換をONにしてみよう。
ライブ変換をONにした状態で今入力しているが、とても快適に入力できている。
アクティビティモニタの方はかなり早めにタイピングをしてみているがそれでも50%を超えないのでどうやらこれでストレスを感じずにタイピングをできそうだ。セーフブートするのがいちばん有効な解決法みたい。

時間差で発症した流行性結膜炎の治る時期はどうなるのか

1/16 14:01

少し前から右目に結膜炎を患っていたのだが、今日左目も発症した。大して辛くない割には体の調子は劇的に変わるのでちょっと経過観察をしてみようと思う。
ちなみに、先ほど調べて知ったのだが、結膜とはまぶたの裏側を眼球の白目の上を透明に覆っている粘膜らしい。ずっと眼球の白目は強膜がむき出しになっていると思っていたので驚いた。
昨日夜に左目の下眼瞼の瞼結膜をめくったとき、いつもは出てくる白い部分がなくなっていたので、そのときにすでに充血は始まっていたみたいだ。
今朝起きたときに球結膜(白目の上を覆っている部分)に血管が浮き出始め、ものの数時間でもうかなり赤くなってきている。
面白そうだししばらく記録を取ってみよう。正月にいとこが結膜炎を患っていて(確か感染性結膜炎だとか言っていた)接触してから1週間弱で発症していることから、素人推測ではあるがウイルス性の流行性角結膜炎だと推測できる。
http://www.fujitaec.or.jp/ophthalmology/ketumakuen/のページによれば、

「症状:感染してから1~2週間おくれて症状があらわれます。 突然、目に何か入っているかのようにコロコロしたり、充血、まぶたの腫れ、たくさんの目やにや涙が出ます。10日ほどしてから角膜に炎症が起こり、目がかすむこともあります。
原因:アデノウィルス8型の感染で起こります。
経過:治るのに2~3週間かかります。角膜炎が起こった場合は、数ヵ月にわたってその痕が残ることがありますので、十分に治るまで眼科検診を受けて下さい。
感染の恐れ:伝染力が非常に強いので注意が必要です。」

となっている。
また、http://www.fujimotoganka.com/shikan_chicyo/adenovirus.htmlによると

「今のところアデノウイルスに効く抗ウイルス薬は無く、主に処方される点眼薬は二次的な細菌感染を防ぐ抗菌剤と過剰な炎症反応を抑える抗炎症剤です。」

とのことらしい(HPの信頼性についてはちゃんと検証しているわけではない)。
f:id:purple-apple:20170205192325j:plain
(http://rtcweb.rtc.riken.go.jp/DNA/sec/ade.html)
f:id:purple-apple:20170205192329j:plain
(http://lifehack.website/archives/463.html)
ちなみにアデノウイルスの形状は上の画像のような感じらしい(ちゃんと出どころを検証したわけではないです)。ファージとは少し違う。
免疫ができて治るのだとすれば、時間差を置いて発症した右目と左目はほぼ同時に治るということになるんだろうか。それだとありがたいけど。
ちなみに角膜炎になると後をひくらしいので休み明けに病院に行こう。怖い怖い。これだけ調べたら少し満足した。

15:09

免疫ができて治ると一言で言ってもその具体的な内容を全く理解していないので少し調べてまとめておく必要があるかもしれない。
ウイルスに対する防御の一つは、ウイルスに感染した細胞のMHCにウイルス分子の一部を提示し、それがT細胞、もしくはキラーT細胞に認識され、後者の場合はその細胞が傷害されて除去されるというものだ。これが獲得性免疫なのか自然免疫なのかはちょっとよく分からない。獲得免疫っぽくはないので自然免疫な気はするけど。(後から調べた結果、これは獲得性免疫の細胞性免疫に分類されることがわかった。)
それで、アデノウイルスによる結膜炎の症状を収束させるのは獲得免疫の方だろうから、そちらを少し整理してみよう。参考ページはここhttp://www.vaxxinova.co.jp/academic_info/immunology_001/
f:id:purple-apple:20170205192334g:plain
獲得性免疫は上記のように分類される。ウイルスに関する獲得性免疫の説明は以下のようになっている。

「体液性免疫
ウイルス感染に対する抗体の作用
● 中和抗体によりウイルスの体内伝播を阻害する系
抗体(特にIgG抗体)が直接ウイルス粒子に結合し、感受性細胞への接着を阻止することにより体内伝播を防ぎます。また分泌型抗体(IgA抗体)は、腸管や気道の粘膜表面でウイルスに結合して、ウイルスの侵入を阻止します。
● 抗体依存性細胞障害(ADCC)により排除する系
ウイルスが細胞内で増殖し、細胞表面にウイルス抗原が発現していれば、抗ウイルス抗体が付着します。抗体の付着したウイルス感染細胞に対しては、ナチュラルキラー(NK)細胞が結合し、細胞を破壊して排除します。
細胞性免疫
ウイルスの感染に対する免疫作用
●キラーT細胞によるウイルス感染細胞の排除
ウイルス感染細胞表面には本来の細胞膜抗原の他に、ウイルス由来の抗原が表出されています。キラーT細胞はこの抗原を認識し、感染細胞を破壊してウイルス増殖を阻止します。」
ということらしい。ウイルス感染細胞の除去だけでは症状を収束させることはできなさそうなので、おそらく「● 中和抗体によりウイルスの体内伝播を阻害する系」の確立が症状を収束させるのに重要なのだろう。特にこれを読む感じだとIgG抗体だろうか。確かものの本でIgG抗体ができるまでには少し時間がかかるだとか読んだ気がするが、どうだったか。
少し抗体の分類についても調べてみることにする。参考はhttp://www.ketsukyo.or.jp/plasma/globulin/glo_03.html
免疫グロブリンには、IgG、IgA、IgM、IgD、IgEの5種類があるみたいだ。
以下各抗体についての簡単な説明と図。
「1)IgG
血液中に最も多く含まれる免疫グロブリンです。分子量は約16万ダルトン、健常成人では血漿中に約1,200mg/dL含まれ、種々の抗原(細菌、ウイルスなど)に対する抗体を含んでいます。
(2)IgA
人の腸管、気道などの粘膜や初乳に多くあって、局所で細菌やウイルス感染の予防に役立っています。IgAは血液中ではY字型をしていますが、粘膜や初乳中ではY字構造が2つ結合した形をしています。
(3)IgM
私たちが細菌やウイルスに感染したとき、最初に作られる抗体です。そしてIgMが作られた後に、本格的にIgGが作られます。このため、血中のIgMを調べる事で今どんな感染症にかかっているかがわかります。IgMは5つのY字構造が互いに結合していて、Y字構造一つで出来ているIgGより効果的に病原体に結合すると考えられています。
(4)IgD
Y字型をしていますが、量的にも少なく、その役割はよくわかっていません。
(5)IgE
免疫グロブリンとしては最も量が少なく、喘息〔ぜんそく〕や花粉症などのアレルギーを起こす抗体です。
f:id:purple-apple:20170205192331j:plain

だそうで、IgGはできるまでに時間がかかる、という記憶はどうやら間違ってはいなさそう。これ以上のことはさらっと検索をかけてみた感じでてこなかったので、免疫多分免疫関係の教科書を読まないと分からないんだろうなあ。ただ、どうも時間差で発症したウイルス性の結膜炎は抗体さえできれば同時に治りそうというこはわかったので、個人的には満足。