C言語:クラスター分析(株価を解析)
前に上げたCのコードを使って株価をクラスター分析してみました。東証一部の2012の日足の終値データを元にしています。株価のデータは正規化されています。そして、前のクラスター分析のコードは距離の定義はユークリッド距離のみでしたが、今回は1からpearsonの相関係数引いたものを距離として定義しました。これは集合知プログラミングに書いてあるとおりです。
多くの株価が同じような変動をする中で4つほど明らかに違う動きをしている株価があることがわかります。分散して投資するならこの4つと他のモノという感じで投資してみてはいかがでしょうか。
前々からわかっていたことなのですが、今回のケースで用いた距離の定義は相関係数の良さを大いに殺していると思います。相関係数の符号が大切であるのにその効果を削除しているからです。株価についてはもっといいクラスタリグを用いたほうがいいかもしれません。
以下結果を示す。
clustering.c
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #define MAX 1000 //------------ struct data -------------- struct dataline{ double data; struct dataline *next; }; struct clust{ int num; double length; struct dataline *vec; struct clust *right; struct clust *left; }; struct line{ int point; struct line *next; }; struct intmat{ struct dataline *intlist; struct intmat *next; }; struct print_clust{ struct clust* data; struct print_clust* next; }; //------------ define function ------------ struct clust *clustalloc(void); struct print_clust *print_clustalloc(void); struct line *linealloc(void); struct clust *makeclust(struct clust **root,int i,int j,double length,int num); double length(struct clust *c1,struct clust *c2); void printclust(struct clust *root); void append(struct line *end,int point); void del(struct line *head,int point); struct dataline *makevec(struct dataline *list1,struct dataline *list2); struct dataline *intsplit(char *s1,int *num); struct dataline *intalloc(void); struct intmat *matalloc(void); struct intmat *readdata(int argc,char *argv[],int *datalength); double pointlength(struct dataline *list1,struct dataline *list2); double pearson(struct dataline *list1,struct dataline *list2); //------------------------------ int main(int argc,char *argv[]){ int num=0,i,datalength; struct clust *mat[MAX],*root,*head,*newc; struct line *lp,*rootline,*headline,*end,*lp2,*lp3,*start,*p; struct intmat *data,*headmat,*matp; struct dataline *pline; double min,d; int minpair[2]; root=clustalloc(); rootline=linealloc(); headline=NULL; data=readdata(argc,argv,&datalength); matp=data; i=0; while(matp!=NULL){ pline=matp->intlist; while(pline!=NULL){ pline=pline->next; } matp=matp->next; i++; } matp=data; for(num=0;num<argc-1;num++){ pline=matp->intlist; mat[num]=clustalloc(); mat[num]->num=num; mat[num]->length=0; mat[num]->vec=matp->intlist; mat[num]->right=mat[num]->left=NULL; lp=linealloc(); lp->next=headline; lp->point=num; headline=lp; while(pline!=NULL){ pline=pline->next; } matp=matp->next; } end=lp; while(lp!=NULL){ lp=lp->next; } lp=end; while(lp->next->next!=NULL){ min=pearson(mat[lp->point]->vec,mat[lp->next->point]->vec); //min=pointlength(mat[lp->point]->vec,mat[lp->next->point]->vec); minpair[0]=lp->point; minpair[1]=lp->next->point; lp2=lp; while(lp2!=NULL){ lp3=lp2->next; while(lp3!=NULL){ //d=pointlength(mat[lp2->point]->vec,mat[lp3->point]->vec); d=pearson(mat[lp2->point]->vec,mat[lp3->point]->vec); if(d<=min){ minpair[0]=lp2->point; minpair[1]=lp3->point; newc=makeclust(mat,minpair[0],minpair[1],d,num); min=d; } lp3=lp3->next; } lp2=lp2->next; } p=end; del(lp,minpair[0]); del(lp,minpair[1]); append(lp,num); mat[num]=newc; num++; } p=end; //root=makeclust(mat,p->point,p->next->point,pointlength(mat[p->point]->vec,mat[p->next->point]->vec),num); root=makeclust(mat,p->point,p->next->point,pearson(mat[p->point]->vec,mat[p->next->point]->vec),num); printclust(root); while(p!=NULL){ p=p->next; } return 0; } //--------------------- void printclust(struct clust *root){ static int num=0; struct clust *p; struct print_clust *pt,*head; p=root; head=NULL; if(p->right!=NULL){ printclust(p->right); pt=print_clustalloc(); pt->data=p; pt->next=head; head=pt; num++; } if(p->left!=NULL){ printclust(p->left); num++; } pt=head; while(pt!=NULL){ printf("%d %d %d %lf\n",pt->data->num,pt->data->left->num,pt->data->right->num,pt->data->length); pt=pt->next; } return; } void append(struct line *end,int point) { struct line *lp,*new,*lp2; new=linealloc(); new->point=point; lp=end; while(lp!=NULL){ lp2=lp; lp=lp->next; } lp2->next=new; } void del(struct line *head,int point){ struct line *p,*end,*old,*tp,*p2,*p3; p=head; while(p!=NULL){ if(p->point==point){ if(p==head){ p2=head; while(p2->next!=NULL){ p2->point=p2->next->point; p3=p2; p2=p2->next; } free(p3->next); p3->next=NULL; return ; } end=old->next; old->next=end->next; return; } old=p; p=p->next; } } struct clust *makeclust(struct clust **root,int i,int j,double length,int num){ struct clust *newclust; newclust=clustalloc(); newclust->num=num; newclust->right=root[i]; newclust->left=root[j]; newclust->vec=makevec(root[i]->vec,root[j]->vec); newclust->length=length; return newclust; } struct intmat *readdata(int argc,char *argv[],int *datalength) { struct intmat *data,*matp,*head; struct dataline *line,*p; int i; FILE *rfp; char buf[256]; head=NULL; for(i=1;i<argc;i++){ printf("%s ",argv[i]); if((rfp=fopen(argv[i],"r"))==NULL){ printf("%s is not readable\n",argv[i]); exit(1); } while(fgets(buf,256,rfp)!=NULL) line=intsplit(buf,datalength); p=line; data=matalloc(); data->next=head; data->intlist=line; head=data; } puts(""); return data; } double pearson(struct dataline *list1,struct dataline *list2) { double sum1=0,sum2=0,sum1q=0,sum2q=0,pSum=0,num=0,den; int len=0; struct dataline *p1,*p2; p1=list1; p2=list2; while(p1!=NULL){ sum1+=p1->data; sum2+=p2->data; sum1q+=pow(p1->data,2); sum2q+=pow(p2->data,2); pSum+=p1->data*p2->data; len++; p1=p1->next; p2=p2->next; } num=pSum-(sum1*sum2/len); den=sqrt((sum1q-pow(sum1,2)/len)*(sum2q-pow(sum2,2)/len)); if(den==0) return 0; return 1.0-num/den; } double pointlength(struct dataline *list1,struct dataline *list2) { double out=0; struct dataline *p1,*p2; p1=list1; p2=list2; while(p1!=NULL){ out+=pow(p1->data-p2->data,2); p1=p1->next; p2=p2->next; } return sqrt(out); } void split(char *s1){ char *temp; char *s2=" "; temp=strtok(s1,s2); while(temp!=NULL){ printf("%s\n",temp); temp=strtok(NULL,s2); } } struct dataline *intsplit(char *s1,int *num){ char *temp; char *s2=" "; int i; int j=0; struct dataline *p,*head; temp=strtok(s1,s2); head=NULL; while(temp!=NULL){ i=atoi(temp); temp=strtok(NULL,s2); p=intalloc(); p->next=head; p->data=i; head=p; j++; } *num=j; return p; } struct dataline *makevec(struct dataline *list1,struct dataline *list2){ struct dataline *out,*p,*p2,*head; p=list1; p2=list2; head=NULL; while(p!=NULL){ out=intalloc(); out->data=(p->data+p2->data)/2; out->next=head; head=out; p=p->next; p2=p2->next; } return head; } //-----memory allocate--------------------------------------- struct print_clust *print_clustalloc(void) { return (struct print_clust *)malloc(sizeof(struct print_clust)); } struct dataline *intalloc(void) { return (struct dataline *)malloc(sizeof(struct dataline)); } struct intmat *matalloc(void) { return (struct intmat *)malloc(sizeof(struct intmat)); } struct clust *clustalloc(void) { return (struct clust *)malloc(sizeof(struct clust)); } struct line *linealloc(void) { return (struct line *)malloc(sizeof(struct line)); }
print_cluster.py
#! /usr/bin/env python from PIL import Image,ImageDraw class bicluster: def __init__(self,left=None,right=None,distance=0.0,id=-1,num=0): self.left=left self.right=right self.distance=distance self.id=id self.num=num class drawcluster: def __init__(self): self.rfile=None self.names=[] self.filename=None self.data=[] self.datalength=0 self.num=0 def read(self,filename): self.filename=filename rfile=open(filename,"r") self.names=[ iname.split('.')[0] for iname in rfile.readline().split()] for line in rfile.readlines(): self.data.append(line.split()) self.datalength=len(self.data)*2 def transfrom_data(self): self.clusterdata=[bicluster() for i in range(len(self.data)*2+1)] for i in xrange(len(self.clusterdata)): self.clusterdata[i].num=i for i in range(len(self.data)): itemp=int(self.data[i][0]) self.clusterdata[itemp].id=itemp self.clusterdata[itemp].left=self.clusterdata[int(self.data[i][1])] self.clusterdata[itemp].right=self.clusterdata[int(self.data[i][2])] self.clusterdata[itemp].distance=float(self.data[i][3]) def getheight(self,clust): if clust.left==None and clust.right==None:return 1 return self.getheight(clust.left)+self.getheight(clust.right) def getdepth(self,clust): if clust.left==None and clust.right ==None:return 0 return max(self.getdepth(clust.left),self.getdepth(clust.right))+clust.distance def drawdendogram(self): clust=self.clusterdata[self.datalength] h=self.getheight(clust)*20 w=1200 depth=self.getdepth(clust) scaling=float(w-150)/depth jpeg="out.jpeg" img=Image.new('RGB',(w,h),(255,255,255)) draw=ImageDraw.Draw(img) draw.line((0,h/2,10,h/2),fill=(255,0,0)) self.drawnode(draw,clust,10,(h/2),scaling) img.save(jpeg,'JPEG') def drawnode(self,draw,clust,x,y,scaling): if clust.id >0: h1=self.getheight(clust.left)*20 h2=self.getheight(clust.right)*20 top=y-(h1+h2)/2 bottom=y+(h1+h2)/2 ll=clust.distance*scaling*0.9 draw.line((x,top+h1/2,x,bottom-h2/2),fill=(255,0,0)) draw.line((x,top+h1/2,x+ll,top+h1/2),fill=(255,0,0)) draw.line((x,bottom-h2/2,x+ll,bottom-h2/2),fill=(255,0,0)) self.drawnode(draw,clust.left,x+ll,top+h1/2,scaling) self.drawnode(draw,clust.right,x+ll,bottom-h2/2,scaling) else: text=self.names[clust.num] draw.text((x+5,y-7),text,(0,0,0)) self.num+=1 if __name__=="__main__": test=drawcluster() test.read("result.out") test.transfrom_data() test.drawdendogram()
実行例
./clustering.exe 1001.data 1002.data 1003.data >result.out python print_cluster.py