Last active
January 6, 2016 14:31
-
-
Save 2bbb/24395df49f027c75c11e to your computer and use it in GitHub Desktop.
linear regression study
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "ofMain.h" | |
| namespace linear_regression { | |
| using default_value_type = float; | |
| template <std::size_t num, typename value_type = default_value_type> | |
| struct model { | |
| using record = std::array<value_type, num>; | |
| using result = value_type; | |
| using datum = std::pair<record, result>; | |
| using data = std::vector<datum>; | |
| using offset = value_type; | |
| using weight = std::array<value_type, num>; | |
| using parameter = std::pair<offset, weight>; | |
| static inline result prediction(const parameter &p, const datum &m) { | |
| result sum{p.first}; | |
| for(std::size_t i = 0; i < m.first.size(); i++) sum += p.second[i] * m.first[i]; | |
| return sum; | |
| } | |
| static inline result error(const parameter &p, const datum &m) { | |
| return pow(m.second - prediction(p, m), static_cast<value_type>(2.0f)); | |
| } | |
| static inline result objective(const parameter &p, const data &d) { | |
| result sum{0.0}; | |
| std::for_each(d.begin(), d.end(), [&](datum &m){ sum += error(p, m); }); | |
| return sum; | |
| } | |
| static inline result d_offset(const parameter &p, const datum &m) { | |
| return 2.0 * (prediction(p, m) - m.second); | |
| } | |
| static inline result d_record(const parameter &p, const datum &m, std::size_t index) { | |
| return 2.0 * m.first[index] * (prediction(p, m) - m.second); | |
| } | |
| static inline parameter step(const parameter &p, const data &d, float scale = 0.01f) { | |
| const datum &m = d[rand() % d.size()]; | |
| parameter p0{p}; | |
| p0.first -= d_offset(p, m) * scale; | |
| for(std::size_t i = 0; i < p0.second.size(); i++) p0.second[i] -= d_record(p, m, i) * scale; | |
| return p0; | |
| } | |
| }; | |
| }; | |
| class ofApp : public ofBaseApp { | |
| using model = linear_regression::model<1>; | |
| model::data data; | |
| model::parameter p; | |
| public: | |
| void setup() { | |
| p = {ofRandom(1.0f), {ofRandom(1.0f)}}; | |
| float a = ofRandom(-1.0f, 1.0f), b = ofRandom(0.5f); | |
| for(std::size_t i = 0; i < 1000; i++) { | |
| model::datum d; | |
| d.first[0] = ofRandom(1.0f); | |
| d.second = a * (d.first[0] + ofRandom(-0.03, 0.03)) + b; | |
| data.push_back(d); | |
| } | |
| } | |
| void update() { | |
| p = model::step(p, data); | |
| } | |
| void draw() { | |
| ofTranslate(0, ofGetHeight()); | |
| ofScale(1, -1); | |
| ofBackground(0, 0, 0); | |
| ofSetColor(255, 255, 255); | |
| for(auto &d : data) { | |
| ofDrawCircle(720 * d.first[0], 720 * d.second, 1); | |
| } | |
| ofSetColor(255, 0, 0); | |
| ofDrawLine(0, p.first * 720, 720, (p.first + p.second[0]) * 720); | |
| } | |
| }; | |
| int main() { | |
| ofSetupOpenGL(720, 720, OF_WINDOW); | |
| ofRunApp(new ofApp); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "ofMain.h" | |
| namespace linear_regression { | |
| using default_value_type = float; | |
| template <std::size_t num, typename value_type = default_value_type> | |
| struct model { | |
| using record = std::array<value_type, num>; | |
| using result = value_type; | |
| using datum = std::pair<record, result>; | |
| using data = std::vector<datum>; | |
| using offset = value_type; | |
| using weight = std::array<value_type, num>; | |
| using parameter = std::pair<offset, weight>; | |
| static inline result prediction(const parameter &p, const datum &m) { | |
| result sum{p.first}; | |
| for(std::size_t i = 0; i < m.first.size(); i++) sum += p.second[i] * m.first[i]; | |
| return sum; | |
| } | |
| static inline result error(const parameter &p, const datum &m) { | |
| return pow(m.second - prediction(p, m), static_cast<value_type>(2.0f)); | |
| } | |
| static inline result objective(const parameter &p, const data &d) { | |
| result sum{0.0}; | |
| std::for_each(d.begin(), d.end(), [&](datum &m){ sum += error(p, m); }); | |
| return sum; | |
| } | |
| static inline result d_offset(const parameter &p, const datum &m) { | |
| return 2.0 * (prediction(p, m) - m.second); | |
| } | |
| static inline result d_record(const parameter &p, const datum &m, std::size_t index) { | |
| return 2.0 * m.first[index] * (prediction(p, m) - m.second); | |
| } | |
| static inline parameter step(const parameter &p, const data &d, float scale = 0.01f) { | |
| const datum &m = d[rand() % d.size()]; | |
| parameter p0{p}; | |
| p0.first -= d_offset(p, m) * scale; | |
| for(std::size_t i = 0; i < p0.second.size(); i++) p0.second[i] -= d_record(p, m, i) * scale; | |
| return p0; | |
| } | |
| }; | |
| }; | |
| class ofApp3D : public ofBaseApp { | |
| using model = linear_regression::model<2>; | |
| model::data data; | |
| model::parameter p; | |
| unsigned long long startFrame{0}; | |
| float fov{30}; | |
| ofEasyCam cam; | |
| ofVec3f target; | |
| public: | |
| void setup() { | |
| p = {ofRandom(1.0f), {ofRandom(1.0f), ofRandom(1.0f)}}; | |
| float a = ofRandom(-1.0f, 1.0f), b = ofRandom(-1.0f, 1.0f), c = ofRandom(0.5f); | |
| for(std::size_t i = 0; i < 1000; i++) { | |
| model::datum d; | |
| d.first[0] = ofRandom(-1.0f, 1.0f); | |
| d.first[1] = ofRandom(-1.0f, 1.0f); | |
| d.second = a * (d.first[0] + ofRandom(-0.1, 0.1)) + b * (d.first[1] + ofRandom(-0.1, 0.1)) + c; | |
| data.push_back(d); | |
| } | |
| cam.setFov(fov); | |
| cam.setTarget(ofVec3f(0, 0, 0)); | |
| } | |
| void update() { | |
| if(ofGetFrameNum() % 100 == 0) { | |
| float theta = ofRandom(M_PI * 2), phi = ofRandom(M_PI); | |
| target.set(cos(theta) * cos(phi) * 360.0f, sin(theta) * cos(phi) * 360.0f, sin(phi) * 360.0f); | |
| fov = ofRandom(30, 150); | |
| } else { | |
| cam.setFov(ofLerp(cam.getFov(), fov, 0.1f)); | |
| cam.setPosition(cam.getPosition().interpolate(target, 0.1f)); | |
| cam.setTarget(ofVec3f(0, 0, 0)); | |
| } | |
| p = model::step(p, data); | |
| } | |
| void draw() { | |
| cam.begin(); | |
| ofBackground(0, 0, 0); | |
| ofSetColor(255, 255, 255); | |
| ofEnableDepthTest(); | |
| for(auto &d : data) { | |
| ofDrawSphere(d.first[0] * 360, d.second * 360, d.first[1] * 360, 2); | |
| } | |
| for(int i = -36; i <= 36; i++) { | |
| ofSetColor(255, 0, 0); | |
| ofDrawLine(-360, 360 * (p.first - p.second[0] + p.second[1] * i / 36.0f), i * 10, | |
| 360, 360 * (p.first + p.second[0] + p.second[1] * i / 36.0f), i * 10); | |
| ofSetColor(0, 255, 0); | |
| ofDrawLine(i * 10, 360 * (p.first + p.second[0] * i / 36.0f - p.second[1]), -360, | |
| i * 10, 360 * (p.first + p.second[0] * i / 36.0f + p.second[1]), 360); | |
| } | |
| ofDisableDepthTest(); | |
| cam.end(); | |
| } | |
| void keyPressed(int key) { | |
| startFrame = ofGetFrameNum(); | |
| if(key == 'r') { | |
| data.clear(); | |
| setup(); | |
| } | |
| } | |
| }; | |
| int main() { | |
| ofSetupOpenGL(720, 720, OF_WINDOW); | |
| ofRunApp(new ofApp3D); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment