ページ 11

複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 08:07
by こ~ふぃ
どうもこんにちわ、こ~ふぃと申します。
早速なのですが、質問です。
現在、1ファイルあたり、小数が195個格納されているtxtファイルとcsvファイルを所持しています。
このファイルが、何十個かあり、その距離演算をして、
file01に総合的に一番距離の近いファイルを導き出すという
cプログラムを組みたいのです。

|file01|file02|・・・|file n|
-------+------+------+------+------+
第1項目| 1.13 | 2.58|・・・|
第2項目|-3.55 | 6.88|・・・|
・   ・   ・
  ・   ・   ・
  ・   ・   ・
第195項目

こんな感じのイメージで、file01の第1項目とfile02の第1項目と・・・と比較していきたいのです。
そして、第195項目まで、比較し、一番file01に距離が近いものを調べます。
#include <stdio.h>
int main(void)
{
FILE *fp;
int i;
double num;

fp = fopen( "test.txt", "r" );

for(i = 0; i <= 194; i++)
{
fscanf( fp, "%lf", &num );

printf( "%lf\n", num);
}
fclose( fp );
return 0;
}
このように、テキスト読み出しはでき、距離の計算も問題はないと思うのですが、
第1項は、file02がfile01に距離が近かった。
第2項は、file03がfile01に距離が近かったのように、
第195項までの区別は、どうやってすればよいのでしょうか?
自分の考えでは、
第1項は、file02がfile01に対して一番距離が近いので点数を付与して、
ということを第195項までして、最終的に一番点数の高いファイルを返せばできるのではないかと
思っているのですが、その点数のための引数をどうやって設定すればいいのかがわかりません。
ご指南のほどよろしくお願いします。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 08:53
by non
ファイルの内容を最初に全部読み込んで、配列または構造体に入れてはいけないのですか?
仮にそれがOKだとしたら、あなたがわからないのは
1 ファイルから配列へのデータの読み込み。
2 配列の各行から差の最小値の求め方
どっちですか?

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 09:02
by こ~ふぃ
nonさんさっそくのご回答ありがとうございます。
私がわからないのは、
構造体や配列への入れ方もしくは、読み込みです。

配列の各行からの差の最小値の求め方は、配列の番号などを間違えなければ、
普通の引数と同じ扱いで計算できると思っています。
もし、この考えで間違っていたら、再びご教授願います。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 10:01
by TOMONORI
ちょっとすみません。
C言語限定ですか?C++などの他の言語は駄目ですか?

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 11:45
by こ~ふぃ
TOMONORIさん
ご回答ありがとうございます。

私は、現在C言語しか学んでおらず、ほかの言語だとまったくわからないため、
できればC言語で回答をお願いします。

勝手なことを言ってすいません。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 12:22
by non
ファイルからの読み込みとなると、前にも他のスレッドにもありましたが、
ファイル名をどうするかという事になります。
そこで、再び質問です。
ファイル名は(拡張子はtxtとcsvということでしたが)規則性がありますか?
例えば、test01.txtなどのように一連番号がついているなど。
それとも、指定しているフォルダにあるファイル全部という事ですか?

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 12:31
by ibis
この規模だったらCでもC++でもほとんど差はないと思いますが・・・
C++ならstdioの代わりにiostreamを使用できますが、stdioでも十分ですし。


>構造体や配列への入れ方もしくは、読み込み

構造体の場合
scanf(フォーマット, &構造体.メンバ);

配列の場合
scanf(フォーマット, &配列[インデックス]);
または
scanf(フォーマット, 配列 + インデックス);

のような感じですね。
これで配列や構造体に直接読み込めます。


>第1項は、file02がfile01に対して一番距離が近いので点数を付与して、
>ということを第195項までして、最終的に一番点数の高いファイルを返せばできるのではないかと

ちょっと質問。
極端な例ですが、
file01が1,1,1,1,1,・・・(合計195)
file02が999,1,1,1,1,・・・(合計1193)
file03が2,2,2,2,2,・・・(合計390)
というような場合は、その比較方法ではfile03よりもfile02が近くなると思いますが、
それで大丈夫でしょうか?


比較方法が違いますが、サンプルを載せてみます。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 12:41
by こ~ふぃ
ファイルは、最初は全てtxtだったのですが、
csvのほうは私が、EXCELで使うために書き直したものです。

そして、ファイルに格納されている195個の数字というのは、人の声の特徴量でして、
その結果、ファイル名は、人の名前になっています。
(例 hanako.csv tarou.csvなど)
ですから、csvなどで、フォルダを分けてはいるものの、フォルダ名に規則性はありません。

指定しているフォルダ全部と言ったほうがいいと思います。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 13:09
by non
ファイル名に規則性がないとすると、方法は2つです。
一つは、ibisさんがサンプルを載せているように、ファイル名の一覧を作ることです。
これは、面倒ですが、プログラムは簡単です。
もう一つは、フォルダ内を検索することです。
これには_findfirstなどの関数を使います。(ただし、Windowsだという前提で説明してます)
ググってみてください。
例えば、
http://www5c.biglobe.ne.jp/~ecb/c/12_11.html
などです。
調べた上でわからないことを質問してください。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 13:25
by こ~ふぃ
ibisさんありがとうございます。

このfileに格納されている数字は、人間個人の声の特徴量であるため、
そこまで突飛な量は出てこないと思うので、この比較で十分いけると思います。

私は、この全数比較は、第一段階で、
この後に分散を使った形でもあらわしたいと思っています。

全てのfileの第1項の分散を求め、分散が1以上ならば、file01第1項に±σ/2(σ=標準偏差)の範囲をとって、
その中に入るfileに得点を付与する。
例えば、
第1項の分散が3.55なら、file01第1項にたいして、±σ/2の範囲をとってfile03とfile05が入っていたらその二つのファイルに+1点とし、
第2項の分散が0.74なら、計算をせずに、第3項の計算に移り、
第3項の分散が2.77なら、file01第3項にたいして、±σ/2の範囲をとってfile03とfile04が入っていたらその二つのファイルに+1点とし、



と、繰り返し、最終的にfile03が2点を獲得し、一番得点が高いのでfile01に近いのはfile03のような結果を出したいのです。
精度は、多分速度とトレードオフになると想像がつくので、
あまり、精度は、気にしていません。
この考えでは、そこまでひどく精度が落ちることもないと思うのですが。
ただ、配列にファイル読み込みもできない人物の妄想なので、
お手をお借りできればと思っています。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 13:29
by こ~ふぃ
nonさん回答ありがとうございます。
ワイルドカードってはじめて聞きました。
色々ググってみます。
まだ、それについてわからないことだらけなので、
なるべく調べてから質問したいと思います。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 13:39
by non
了解です。
こ~ふぃさんの環境がわからないので、まずはサンプルが動くか確かめてください。
場合によっては、_findfirstではなく、finfirstのように先頭のアンダーバーを取らないと
動かないコンパイラもあると思います。
BCCやVC++なら大丈夫。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 15:25
by こ~ふぃ
ibisさんのサンプルを使ってプログラムを動かしたところ、

7[main] program 8632 _cygtls::handle_exceptions: Error while dumping state
(probably corrupted stak) Segmenttation fault (core dumped)

というエラーとprogram.exe.stackdumpというファイルが生成されました。

Exception: STATUS_ACCESS_VIOLATION at eip=610EA750
eax=00000000 ebx=0022C5C8 ecx=00000000 edx=00000000 esi=611021A0 edi=0040152C
ebp=0022C598 esp=0022AFD0 program=c:\Documents and Settings\Guest\My Documents\home\speech\hmm1\hmmtxt\csv\kensaku3.exe, pid 8632, thread main
cs=001B ds=0023 es=0023 fs=003B gs=0000 ss=0023
Stack trace:
Frame Function Args
0022C598 610EA750 (0022D008, 00000000, 00403146, 0022C5C8)
0022C5B8 610E78C9 (00000000, 00403146, 0022CCD0, 0040107E)
0022CCE8 610935A8 (00000001, 6116B6F0, 006B0090, 0022CC70)
0022CD98 610060D8 (00000000, 0022CDD0, 61005450, 0022CDD0)
61005450 61004416 (0000009C, A02404C7, E8611021, FFFFFF48)
7 [main] kensaku3 8632 _cygtls::handle_exceptions: Error while dumping state (probably corrupted stack)

という中身なのですが、これは、何かアクセスしてはいけないメモリを配列で使っているということは、
調べてわかったのですが、根本的な解決策がいまだに見つかりません。
どのようにしたらよろしいのでしょうか?

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 16:09
by ibis
対象ファイルが無い状態で実行するとエラーでますよ。
アクセス違反だったら、多分ファイルポインタが無効なのではないかと思います。

ちなみにこちらの環境で
(bccでコンパイルして、同一フォルダに対象ファイル(区切り文字は改行)を用意して)
実行したら正常に動きました。

ループでの配列アクセスの上限と下限は定数を使ってますので、
これは環境によって変わる(エラーだったり、そうでなかったり)ということは無いと思うのですが。

まぁ動かなければ、これは無視してくださってもかまいませんよ。


>まずはサンプルが動くか確かめてください。
とありますが、これは私が挙げたサンプルではなくて、nonさんが載せてるリンク先にあるサンプルのことだと思いますよ。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 17:07
by こ~ふぃ
ibisさん回答ありがとうございます。
対応ファイルも作ってやったところ出たのが、先ほどのエラーです。
今度は、
cvsファイルを20個ほど用意し、
突っ込んでみましたが、先ほどのエラーでした。

しかし、cvsファイルを4個まで減らしたところ正常に動きました。
いったいどういうことなのでしょうか?

nonさんのサンプルも動いたのですが、
なにぶんワイルドカードがはじめて聞くものなので、試行錯誤中といったところです。
その間に、このエラーをどうにかできないものかと考えています。

あと、ファイルポインタが向こうというのはどういうことですか?

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 17:27
by non
>なにぶんワイルドカードがはじめて聞くものなので、試行錯誤中といったところです。

ワイルドカード自体はそんなに難しい話ではありませんが・・・

2つの検索種類があるので、
最初は *.txtで検索し、
次に *.csvで検索するというように2回に分けます。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月13日(火) 18:04
by non
わかりやすいように無駄なモノを極力省きました。
#include <stdio.h>
#include <string.h>
#include <io.h>

char f_name[100][20];//ファイルの最大を100個、文字数を20文字までにしました。
int f_no=0;

void find_file( char *filename ){
	struct _finddata_t c_file;
	long   hFile;

	if( (hFile = _findfirst( filename, &c_file )) !=-1 ){
		strcpy(f_name[f_no++],c_file.name);
		while( _findnext( hFile, &c_file ) == 0 )
			strcpy(f_name[f_no++],c_file.name);
		_findclose( hFile );
	}
}
int main(void)
{
	int i;
	find_file("*.txt");
	find_file("*.csv");
	for(i=0;i<f_no;++i)
		puts(f_name);
	return 0;
}

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月14日(水) 16:30
by ibis
とりあえず、ちょっと改良したものを添付します。
これならどうでしょうか?

>あと、ファイルポインタが向こうというのはどういうことですか?
ファイルを開くのに失敗した場合はファイルポインタの値がNULLになります。
その為、値がNULLのファイルポインタは無効ということです。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月14日(水) 17:13
by こ~ふぃ
nonさん懇切丁寧な回答ありがとうございました!!
おかげで、ファイルの検索はできるようになりました。
なので、単純な全数検索でのファイル比較は解決するこ 
とができました。
どうもありがとうございました。

あとは、もうひとつの方法である分散をもちいた方法を考えています。

全てのfileの第1項の分散を求め、file01の第1項が分散が5以上ならば、file01第1項に±σ(σ=標準偏差)の範囲をとって、 その中に入るfileに得点を付与する。
例えば、
第1項の分散が5.22なら、file01第1項を中心に±σの範囲をとってfile03とfile05が入っていたらその二つのファイルに+1点とし、
第2項の分散が0.74なら、計算をせずに、第3項の計算に移り、
第3項の分散が12.45なら、file01第3項にたいして、±σ/2の範囲をとってfile03とfile04が入っていたらその二つのファイルに+1点とし、



と、繰り返し、最終的にfile03が2点を獲得し、一番得点が高いのでfile01に近いのはfile03のような結果を出したいのです。
精度は、多分計算速度とトレードオフになると想像しています。

先ほどの、全数検索で比較する方法では、

double file[195]

for(n =0 ; n<= ファイル数 ; n++){
fp = fpoen(files[n],"r");
for(i=0; i<=194;i++){
fscanf(fp,"%lf",&file);
距離計算
   }
fclose(fp);
}

みたいな感じで計算していたため、file毎の第1項同士の分散などの計算ができずに困っています。
そもそも、ファイルを2次元配列で入れ込んだほうがよいのでしょうか?

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月14日(水) 17:37
by non
ファイルのデータを入れる配列は
double file_data[195][f_no];
のような2次元配列にして、加工しない生データをファイルから格納し、
必要に応じて
例えば距離を入れる配列や、分散を入れる配列、得点を入れる配列を用意した方が
いいでしょう。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月15日(木) 01:17
by こ~ふぃ
返信遅れながら失礼します。

ibisさん
改訂版のファイルありがとうございます。
こちらは、ファイル数を増やしてもエラーが出ずに、動作しました。
このファイルを元に、各項ごとの分散(file01からfile nの第1項の分散、第2項の分散といった具合)を計算しようと、試行錯誤したのですが、できませんでした。

nonさん
アドバイスありがとうございます。
2次元配列がわからないなりに、色々調べて書いてみたのですが、ファイルが開けないなどといわれたり、coredumpというエラーが起きたりして、配列にファイルデータを格納できずに困っています。
↓が書いてみたものです。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char *files[/url] = {"open.txt", "open_yanagawa.txt", "open_kayama.txt", "open_eiji.txt", "open_shouta.txt",

"open_okuhara.txt", "open1.txt", "open_new1.txt", "open_fuse1.txt", "open_nakamura1.txt", "open_kensei1.txt",

"open_oomori1.txt", "open_yanagawa1.txt", "open_eiji1.txt", "open_shouta1.txt", "open_okuhara1.txt"};

#define NUMBER_OF_FILES (sizeof(files) / sizeof(char*))

int main(void)
{

FILE *fp;
double file_data[195][NUMBER_OF_FILES];
int i, j, k;

// open
for(i = 0; i <= NUMBER_OF_FILES; i++)
{
fp = fopen(files, "r");
if(fp == NULL)
{
printf("file open failuer\n");
return 1;
}
for(j = 0; j <= 194; j++)
{
fscanf(fp, "%lf", &file_data[j]);
}
}

// display
for(i=0;i<NUMBER_OF_FILES;i++)
{
for(j=0;j<194;j++)
{
printf("%d番目ファイル %d項目 %lf\n",file_data[j]);
}
}

// close
fclose(fp);

return 0;

}

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月15日(木) 08:45
by non
fopenとfcloseは対で使います。
fcloseの場所を考えてください。

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月15日(木) 10:26
by non
サンプルとして、ファイルデータを読み込み、平均を求めて、csvファイルを出力するようにしました。
実行したら、data.csvを開いて確認してください。再度、実行するときは、data.csvを削除して行うように
しないと、このファイルも読んじゃいます。入力データのフォルダと出力データのフォルダを分けるべき
ですが、プログラムがわかりにくくなるので、自分でしてください。
現状では、すべてカレントフォルダを見に行きます。
同様な方法で、分散でも得点でもできると思います。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <io.h>

#define NUMBER_OF_FILES 100

char f_name[NUMBER_OF_FILES][20];//ファイルの最大を100個、文字数を20文字までにしました。
int f_no=0;
double file_data[195][NUMBER_OF_FILES];//生データ格納用
double ave_data[195]; //平均

void find_file( char *filename ){
	struct _finddata_t c_file;
	long   hFile;

	if( (hFile = _findfirst( filename, &c_file )) !=-1 ){
		strcpy(f_name[f_no++],c_file.name);
		while( _findnext( hFile, &c_file ) == 0 )
			strcpy(f_name[f_no++],c_file.name);
		_findclose( hFile );
	}
}
void f_load(int no,char *filename)
{
	FILE *fp;
	int i;
	fp = fopen(filename, "r");
	for(i = 0; i < 195; i ++){
		fscanf(fp, "%lf", &file_data[no]);
	}
	fclose(fp);

}
void ave(void)
{
	int i,j;
	double work;
	for(i=0;i<195;i++){
		work=0.0;
		for(j=0;j<f_no;j++)
			work+=file_data[j];
		ave_data=work/f_no;
	}
}
void f_out(void)
{
	FILE *fp;
	int i,j;
	if((fp = fopen("data.csv", "w"))==NULL){
		printf("ファイルオープンエラー");
		exit(1);
	}
	fprintf(fp,"\"項目\"");
	for(i=0;i<f_no;i++)
		fprintf(fp,",\"%s\"",f_name);
	fprintf(fp,",\"平均\"");
	fprintf(fp,"\n");
	for(i=0;i<195;++i){
		fprintf(fp,"%d",i);
		for(j=0;j<f_no;++j)
			fprintf(fp,",%lf",file_data[j]);
		fprintf(fp,",%lf",ave_data);
		fprintf(fp,"\n");
	}
	fclose(fp);
	printf("data.csvに出力しました\n");
}
int main(void)
{
	int i;
	//ファイルの検索
	find_file("*.txt"); 
	find_file("*.csv");
	//データの読み込み
	for(i=0;i<f_no;++i)
		f_load(i,f_name);
	//平均
	ave();
	//CSVファイル出力
	f_out(); 
	return 0;
}

Re:複数のtxtファイルやcsvファイルを比較したいのですが。

Posted: 2009年1月19日(月) 02:08
by こ~ふぃ
nonさん返信ありがとうございます。
お教えいただいたプログラムも問題なく動きました!
分散などの得点もやってみます。

タイトルの比較の部分が解決したので解決とします。
ご協力いただいた皆さんありがとうございます。
また質問した際にはよろしくお願いします