Simple Linear Regression in Python

Linear regression เป็นการโมเดลข้อมูลโดยใช้ความสัมพันธ์เชิงเส้นที่มีตัวแปรตาม 1 ตัว และตัวแปรอิสระตั้งแต่ 1 ตัวขึ้นไป สิ่งที่เราจะต้องทำคือหาสมการเชิงเส้นที่เหมาะสมกับข้อมูลนั้นๆ ในบล็อกนี้จะกล่าวถึงแค่ simple linear regression ซึ่ง จะมีตัวแปรอิสระแค่ 1 ตัว แล้วเราจะได้สมการเชิงเส้นดังนี้

y = a + bx

โดย y คือตัวแปรตาม (dependent variable) ส่วน x คือตัวแปรอิสระ (independent variable) ค่าสัมประสิทธิ์ (coefficient) a คือค่าของ y ตอนที่ x มีค่าเป็น 0 ดังนั้นเราสามารถเรียกได้ว่าเป็นจุดตัดแกน y หรือ y intercept นั่นเอง ส่วนค่าสัมประสิทธิ์ b คือความชัน (slope) ของเส้นตรงนั่น หรือค่าที่เปลี่ยนแปลงไปของ y เมื่อมีการเปลี่ยนแปลงที่ x ดูรูปข้างล่างนี้ประกอบ

สำหรับใครที่สนใจอยากรู้ว่าคำนวณอย่างไร ก็แนะนำให้อ่านการสอนของ Stefan Waner และการสอนของ Stephen Mak เพราะผมอ่านแล้วเข้าใจกว่าอ่านใน Wiki แหละ 😛

เอาล่ะ ไม่ต้องเขียนให้มากความ จัดโค้ดไปเลยดีกว่า ดาวน์โหลดได้ที่นี่ [Simple Linear Regression in Python] ข้างในจะประกอบไปด้วย 2 ไฟล์ดังนี้

  1. ไฟล์หลัก: main.py
  2. ไฟล์คลาส LinearRegression: linreg.py

โดยโปรแกรมจะคำนวณค่า a, b, coefficient of determination, coefficient of correlation, standard error of estimate, และ mean squared error of estimate ออกมาให้ครับ

โปรแกรมนี้เป็นโปรแกรมเกือบจะโปรแกรมแรกเลยที่เขียนด้วย Python เองเต็มๆ แบบว่าอยากทำงานและก็อยากศึกษาภาษาใหม่ไปด้วยในตัวก็เลยลองดู 🙂 เนื่องจากปกติเขียนแต่ภาษา C/C++ หรือ Java พอมาเขียน Python ก็เลยต้องเขียนไปบ่นไป ฮะๆ คิดว่าถ้าลองเขียนไปอีกสักพักน่าจะปรับตัวได้ แล้วก็ฝีมือในการเขียน Python ก็ยังอ่อนด้อยอยู่มาก ถ้าใครมีอะไรเพิ่มเติม ดุ ด่า เกี่ยวกับโค้ดก็ยินดีเลยครับ หรือจะเอาไปพัฒนาต่อก็ไม่ว่ากัน

ปล. โค้ดในบล็อกนี้แปลงมาจากโค้ด C++ ของ David C. Swaim II เกือบทั้งดุ้นเลยนะครับ หุหุ

การใช้ OpenCV สร้างกราฟ Histogram จากรูป

บล็อกนี้ผมขอเสนอวิธีใช้ฟังก์ชั่นจาก OpenCV สร้างกราฟ Histogram จากค่าสีที่ได้จากรูปที่เป็น Grayscale นะครับ ซึ่งก็สามารถนำไปประยุกต์ใช้กับรูปที่เป็น RGB หรือ HSV ได้เหมือนกันครับ

ก่อนอื่นเลย Histogram ของรูป คืออะไร.. มันก็คือกราฟที่เกิดจากการพลอตจำนวนของ pixel ที่ค่าสีนั้นๆ นั่นเอง แกน X คือค่าของสี ส่วนแกน Y คือจำนวนของ pixel (อ่านเพิ่มเติมได้ที่ Image histogram ครับ)

เมื่อเราทราบหลักการของการสร้าง Histogram จากรูปแล้ว เราก็มาดูที่โค้ดกันครับ เริ่มต้นเราก็ประกาศขนาดของ Histogram ครับ ให้มีขนาด 256 ช่อง (ค่าสีปกติจะมีค่าระหว่าง 0-255 ในที่นี้ผมจะให้ช่องหนึ่งคือค่าสีหนึ่งนะครับ ซึ่งค่านี้สามารถเปลี่ยนแปลงได้แล้วแต่งานครับ)

int bins = 256;
int hsize[] = { bins };

ในโค้ดของผมนี้ผมจะสร้าง Histogram ที่เป็น uniform นะครับ เราก็ต้องกำหนดขอบเขตของค่า x ซึ่งต้องกำหนดตาม format ดังนี้ครับ โดย ranges[] จะต้องมีจำนวน dimension เท่ากับจำนวนค่าที่เป็นคู่ที่เราประกาศไว้ (คู่ 0 กับ 255)

float xranges[] = { 0, 255 };
float* ranges[] = { xranges };

เนื่องจากรูปตัวอย่างเป็น RGB เราก็ต้องแปลงให้เป็น Grayscale ก่อนนะครับ โดย image ในที่นี้คือรูปที่เราโหลดมาตั้งแต่ต้นนะครับ

IplImage* gray = cvCreateImage( cvGetSize( image ), 8, 1 );
cvCvtColor( image, gray, CV_BGR2GRAY );

จากนั้นเราต้องสร้างเพลน (plane) เพื่อมาคำนวณกราฟกันครับ ในที่นี้มีแค่ 1

IplImage* planes[] = { gray };

แล้วเราก็คำนวณค่าของ Histogram ดังนี้ โดยค่า 1 ตัวแรกหมายถึง จำนวน dimension ครับ ส่วน CV_HIST_ARRAY หมายถึงให้ type เป็นชนิด array และค่า 1 ตัวสุดท้ายหมายถึงว่าเป็น uniform ครับ

CvHistogram* hist = cvCreateHist( 1, hsize, CV_HIST_ARRAY, ranges, 1 );
cvCalHist( planes, hist, 0, NULL );

ในการคำนวณโดยใช้ cvCalHist นั้น เราเซตค่าที่ 3 ว่าให้เป็น 1 แปลว่า ถ้าสมมุติว่าเราวนลูปอ่านค่าสีจากรูปมาเรื่อยๆ เราสามารถบวกค่า pixel เพิ่มได้ในกราฟ Histogram อันเดิมครับ แต่ถ้าเป็น 0 ก็แปลว่าไม่ต้องบวกเพิ่ม ส่วนค่าสุดท้าย ถ้าไม่ใช่ NULL เราจะนำแค่จุด pixel ที่ไม่ใช่ 0 และมีการ mask ไว้ในรูปมาคำนวณครับ

ขั้นตอนต่อไป เราก็ต้องสร้างรูปขึ้นมาเพื่อแสดงผลครับ ในที่นี้เรากำหนดให้มีความสูงแค่ 50 พอครับ

IplImage* imgHistogram = cvCreateImage( cvGetSize( bins, 50 ), 8, 1 );
cvRectangle( imgHistogram, cvPoint( 0, 0 ), cvPoint( 256, 50 ), CV_RGB( 255, 255, 255 ), -1 ); // ค่าสุดท้ายคือค่า thickness ครับ ถ้าเป็น -1 แสดงว่าให้เป็นค่าสูงสุดเลย (เพื่อที่ว่าเราจะระบายสีขาวให้เต็มสีเหลี่ยมเลยครับ)

ขั้นตอนสุดท้ายเราก็วาดกราฟครับ และแสดงผล วิธีการก็คือดึงค่าออกมาทีละค่านั่นเอง แต่เนื่องจากเราเซตความสูงไว้ที่ 50 เราจะต้อง normalize ด้วยนะครับ แต่การที่เราจะ normalize ได้เราต้องมีค่าสูงสุดของ Histogram ก่อนครับ หาได้ดังนี้

float max_value = 0, min_value = 0;
cvGetMinMaxHistValue( hist, &min_value, $max_value );

และสุดท้ายจริงๆ ก็ดังนี้ครับ

cvNamedWindow( "histogram", 1 );
for( int i = 0; i < bins; i++ ) {
  float value = cvQueryHistValue_1D( hist, i );
  int normalized = cvRound( value * 50 / max_value );
  cvLine( imgHistogram, cvPoint( i, 50 ), cvPoint( i, 50 - normalized ), CV_RGB( 0, 0, 0 ) );
}
cvShowImage( "histogram", imgHistogram );

หวังว่าจะเป็นจุดอ้างอิงสำหรับผู้ที่เริ่มต้นสนใจในด้าน Image Processing นะครับ

Source code: hist.cc

credit: Isaias Gonzalez (siderevs at gmail dot com)