감동, 마음이 움직이는 것

[log binning] c++ 코드와 python코드 본문

Tips (Utility, Computer Language, and etc.)

[log binning] c++ 코드와 python코드

Struggler J. 2016. 6. 27. 12:40

http://exactitude.tistory.com/378을 토대로 log-binning하는 코드를 만들어보았다. 

개인적으로 length로 normalize하는 방법이 맞다고 생각해서 length로 normalize하는 방법만 구현해 보았다. 

해보고 나서 알게 된건데 length로 normalize하는 경우 마지막 point가 있는 점이 밑으로 내려가게 된다.

왜냐면 데이터 포인트가 찍힌 maximum값이 마지막 bin size보다 작기 때문이다.

이걸 correction하려고 마지막 bin size는 data의 maximum x값을 사용하려고 했으나 이것도 bias가 있긴 매 한가지인것 같아 그냥 두었다. 일단 알고만 있자. 


먼저 input으로 열이 2개 있는 interevent.d라는 파일을 사용했다. 각 행은 (x, f(x))를 의미한다. 

파일을 읽고 log binning을 한 뒤 log_binning_interval.d 라는 output file을 뱉어내도록 했다. 


코드는 다음과 같다. 

(1) c++코드 //개인적으로 파일 읽는건 fscanf가 더 친숙하고 쓸 때는 c++ library가 더 편해서 섞어서 쓰고 있다. 

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include <string.h>

#include <string>

#include <iostream>

#include <fstream>

#include <vector>

#include <map>

using namespace std;

void Count_row(char* fname, int* row);


int main(int argc, char** argv)

{

// cout << "#for discrete interval and x>1, input data format : (int)x, (int)f(x))\n";

int base = 2;

int idx, row;

double x, y;

map<int, double> m;

map<int, double>::iterator iter;

char fname[200] = "interevent.d";

Count_row(fname, &row);

FILE *fp = fopen(fname, "r");



//read data

for(int i=0; i<row; i++)

{

fscanf(fp, "%lf %lf", &x, &y);

if(x<1) cout << "x is smaller than 1\n";

idx = log(x)/log(base);

if(m.find(idx)!=m.end()) m[idx] += y;

else m[idx] = y;

}



//write

double len;

ofstream log("log_binning_interval.d");

for(iter = m.begin(); iter!=m.end(); iter++)

{

idx = iter->first;

x = 0.5*pow(base, idx)*(base + 1.);

len = pow(base, idx)*(base - 1.);

log << x << "\t" << (iter->second)/len << endl;

//cout << x << "\t" << (iter->second)/len << endl;

}


return 0;

}



void Count_row(char* fname, int* row)

{

int N = 0;

ifstream in(fname);

string unused;

string s;

while ( getline(in, unused) )

{

if(N==1) { s=unused; }

++N;

}

*row = N;

//cout << *row << endl;

}


(2) Python //확실히 짧고 예외처리도 편하다. 얘는 input data가 꼭 two column이 아니더라도 된다. 

#-*-encoding:utf-8 -*-

import re

import sys

import math


bin = {}

base =2 


#read

f = open('interevent.d','r')

for line in f.readlines():

elem = re.split(" |\t|\n", line)

idx = int(math.log(int(elem[0]), base))

if idx in bin:

bin[idx] += int(elem[1])

else: 

bin[idx] = int(elem[1])

f.close()



#write

out = open("log_binning_interval.d", 'w')

for i in sorted(bin.keys()):

x = 0.5*pow(base, i)*(base + 1.);

len = pow(base, i)*(base - 1.);

out.write("%f %f\n" % (x, bin[i]/len))

out.close()


interevent.d

interval.eps

log_binning.cpp

log_binning.py

log_binning_interval.d