บทความ
ไม่ว่าจะ ข่าวสาร บทสัมภาษณ์ และ Digital Skill บนสื่อ
มีให้คุณได้อ่านบทความดี ๆ มากมายแล้วที่นี่
โดย: Laris
|
รู้จัก Home Assistant (ตอนที่ 4)
สวัสดีค่ะท่านผู้อ่านทุกท่านวันนี้เราจะกลับมาพบกับ Home Assistant กันอีกครั้งนะคะ จากบทความก่อน เราเริ่มติดตั้งและปรับแต่งกันไปบ้างแล้ว อย่างเช่นพวกสวิตซ์ (Switch) เปิดปิดไฟต่างๆ มีใครพอจะนึกออกบ้างไหมคะว่าถ้าเรามีสวิตช์ หลอดไฟ หรือเซ็นเซอร์ จำนวนมากๆ มันจะเป็นเกิดเหตุการณ์ยังไง? ถ้าใครนึกไม่ออกลองดูภาพข้างล่างนี้ค่ะภาพตัวอย่างของ Sensor ที่ไม่มีกลุ่มค่ะเข้าใจเลยใช่ไหมคะว่าถ้าเรามีจำนวนอุปกรณ์มากๆ หรือถ้าเราต้องการจัดหมวดหมู่ของอุปกรณ์ โดยแบ่งกันไปเป็นห้อง หรือชั้นต่างๆ หากอุปกรณ์มีเยอะมากๆ ก็คงจะปวดหัวน่าดูเลยนะคะ Home Assistant Group Componentวันนี้เรามาเรียนรู้วิธีการจัดการเรื่องพวกนี้ด้วย Group กันนะคะ หน้าตาของ Group ก็จะหน้าตาประมาณนี้ค่ะ สวยงามตามท้องเรื่องตัวอย่างของ Home Assistant ที่มีการจัด Groupสำหรับบทความนี้ Group เป็นสิ่งที่จะมาช่วยเราแก้ปัญหาและอัพเกรดเลเวลของเราเพิ่มขึ้นค่ะ แต่เราจะต้องมารู้จัก Home Assistant เพิ่มขึ้นกันอีกนิดนะคะ ซึ่งสิ่งที่เราจะต้องเรียนรู้กันต่อไปก็คือ Entities, Groups และ Viewsค่ะเริ่มต้นสร้าง Groupก่อนที่เราจะสร้าง และเพิ่มอุปกรณ์เข้าไปใน Group นั้น เราต้องเข้าใจ Default groups กันก่อนนะคะ เดี๋ยวจะงงกันไปก่อน ว่าทำไมหลอดไฟ (Light) ของสวิตช์ (Switch) ของเราไปโผล่ใน Group ได้ยังไง?Default groupsใน Home Assistant จะมี Default Group ด้วย ซึ่งบาง Component จะสร้าง Group พิเศษขึ้นมาซึ่งทั้งหมดจะขึ้นต้นด้วยชื่อแบบนี้ group.all_ ซึ่งหน้าตาก็จะประมาณข้างล่างนี้ค่ะgroup.all_switchesgroup.all_lightsgroup.all_devicesgroup.all_scriptsGroup.all_automationsซึ่งเราสามารถดูได้จากกด Developer Tools → Statesแสดงข้อมูล Entity ทั้งหมดจากกลุ่ม Lightเมื่อเราใช้งาน Component ประเภทหลอดไฟ (Light) หรือประเภทสวิตช์ (Switch) มันจะถูกเพิ่มเข้าไปใน Group ประเภทของตัวเองอัตโนมัติ (Lights, Switches) แต่อาจจะเรียงลำดับไม่ถูกใจเรา ถ้าอยากให้จัดเรียงอยู่ตำแหน่งให้ได้ดั่งใจ ให้ใช้ order เข้ามาช่วยตาม Configuration ข้างล่างเลยนะคะhttps://gist.github.com/hassy-bloggy/bbc510167417755ecdd547366c95dc17การแสดงผลจาก Group Switchโดยปกติแล้วทุกๆ Group จะถูกเรียกมาให้แสดงในแท็ป HOME ค่ะ แต่หากว่าเรามีการสร้าง default_view และ view: true ภายใต้ Group จะถือว่าเราต้องการสร้างหน้า Home เองทั้งหมด (Override หน้า Home เดิม)เมื่อได้ข้อมูลดังนี้แล้วเราลองเล่นในแบบต่างๆ ตาม Configuration นี้ดูนะคะhttps://gist.github.com/hassy-bloggy/5beb3c0dd7acdc869728c8840f79a7d8ผลลัพธ์จะออกแบบมาเป็นหน้า Application ที่มี Tab โผล่มาอีก 2 อันคือ Room 1 และ Room 3 ส่วน Room 2 จะไม่แสดงเป็น Tab แต่จะแสดงเป็น Group ในหน้า Default View แทนอย่าเพิ่งงงนะคะ เรามาดูภาพกันดีกว่าค่ะ ซึ่งเราจะได้ผลลัพธ์ออกมาแบบนี้เมื่อเราปรับ Configuration ในส่วนที่เป็น default_view แล้วกำหนด view: truegroup: default_view: view: true icon: mdi:home entities: - group.room_2 - light.mock_laris_light_00a - light.mock_laris_light_00b - switch.laris_plug_00aUI แสดงผลตาม Configuration ของหน้า Homeหลังจากพูดถึงหน้า default_viewไปแล้ว เราก็จะมาดูค่า Configuration ของ แท็บ Room 1 กันบ้างนะคะ แทบจะเหมือนกันเลย เพียงแค่ตั้งค่า view: trueเพื่อให้แสดงเป็น Tab ขึ้นมาอีกหนึ่งอันข้างบนRoom 1: view: true entities: - light.mock_laris_light_00c - light.mock_laris_light_00d - switch.laris_plug_00bUI แสดงผลตาม Configuration ของหน้า Room 1จะเห็นว่าเราสามารถสร้าง Tab ใหม่ได้ง่ายๆ โดยการกำหนด view: trueเราก็จะได้หน้า หรือ Tab ใหม่ขึ้นมาเลยEntity Idแต่ทำมาถึงตรงนี้สงสัยกันมั้ยคะว่าจะเอาชื่อ Entity Id มาใส่ Configuration ได้จากที่ไหน?คำตอบอยู่ที่ไอคอน State <>หลังจากกดเข้ามาหน้า State แล้วเราจะพบกับ Entity Id ของทุกอุปกรณ์ใน Home Assistant ของเราค่ะหน้า Developer Tools → State แสดง Entity Id ของระบบในหน้า Developer Tools จะบอกชื่อ Friendly Name และ Entity Id เราก๊อบส่วนที่เป็น Entity Id มาใช้ได้เลยค่ะ เมื่อเอามาทำ Group เราก็จะได้ Configuration ออกมาประมาณนี้ (แบบข้างบนเลยค่ะ)group: default_view: view: true icon: mdi:home entities: - light.mock_laris_light_00a - light.mock_laris_light_00b - switch.laris_plug_00a - group.room_2 Room 1: view: true # icon: mdi:ninja entities: - switch.laris_plug_00b - light.mock_laris_light_00c - light.mock_laris_light_00d Room 2: view: false entities: - switch.laris_plug_00b - light.mock_laris_light_00c - light.mock_laris_light_00d Room 3: view: true entities: - group.room_2 - light.mock_laris_light_00aเป็นยังไงกันบ้างคะ หลังจากที่เราปรับแต่ง Group กันไปอย่างเข้มข้นแล้ว ตอนนี้ Smart Home App เราคงจะมีสีสัน และน่าสนใจมากขึ้นแล้วใช่ไหมคะคราวหน้าเราจะเริ่มไปลุยกันเรื่องอื่นกันบ้างแล้วนะคะ แล้วพบกันตอนหน้าค่ะ
โดย: Kan Ouivirach
|
สร้าง Machine Learning โมเดลมาทำ Image Recognition
Image Recogniton คือความสามารถของโปรแกรมในการระบุได้ว่าวัตถุ สถานที่ ผู้คน หรือข้อความต่างๆ ในรูปภาพ ว่าคืออะไร อยู่ที่ไหน ใครเป็นใคร และข้อความนั้นเขียนว่าอะไรถ้าเราอยากจะลองสร้าง (traditional) Machine Learning โมเดลขึ้นมาสักตัวหนึ่งเอามาทำ Image Recognition เราต้องทำอย่างไรบ้างนะ? ปกติแล้วเวลานำข้อมูลเข้าไปสอนโมเดล ข้อมูลนั้นๆ จะอยู่ในรูปแบบ Tabular เนอะ คือแบ่งเป็น Column แต่ละ Column ก็จะมีค่าตัวเลขต่างๆ ทีนี้ถ้าเรามีข้อมูลเป็นรูปภาพล่ะ?ไม่ต้องคิดมากเลยครับ เราก็แปลงรูปให้เป็นข้อมูลแบบ Tabular เลย เช่นถ้ารูปขนาด 2x2 เราก็แปลงให้เป็น Vector ขนาด 1x4 ตามรูปข้างล่างนี้เลยครับแปลงรูป 2x2 ให้เป็น Vector ขนาด 1x4โดยเราจะเอาแถวที่ 2 เป็นต้นไป ขึ้นมาต่อด้านหลังของแถวที่ 1 ไปเรื่อยๆ ครับ เท่านี้เราก็จะมีข้อมูแบบ Tabular ที่ Represent รูป 1 รูปแล้วเรียบร้อย 🎉ถ้ารูปมีขนาดไม่เท่ากัน? วิธีแก้คือเราต้องทำให้ขนาดของรูปทุกรูปเท่ากันก่อนก็พอ ทีนี้ก็แล้วแต่ว่าเราจะ Crop รูป หรือ Resize รูปครับผมเรามาลองเล่นกันบ้างดีกว่า จะได้เข้าใจมากขึ้นครับ เราจะนำข้อมูล Optical Recognition of Handwritten Digits จากเว็บ UCI Machine Learning Repository มาสร้างโมเดลกันPhoto by Green Chameleon on Unsplashโหลดข้อมูลมาก่อนครับimport pandas as pddigits_train = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/optdigits/optdigits.tra', header=None)digits_train.head()ข้อมูลที่ได้หน้าตาจะประมาณนี้ครับลักษณะข้อมูล Optical Recognition of Handwritten Digitsจะเห็นได้ว่า UCI ได้แปลงข้อมูลให้เรามาแล้ว แต่ถ้าเราจับข้อมูลมาเรียงกลับมาเป็นรูปขนาด 8x8 จะได้แบบนี้first_digit = digits_train.loc[0, :][:-1].values.reshape(8, 8)first_digitแปลงข้อมูล Tabular (Feature Vector) ให้กลับมาอยู่ในรูปขนาด 8x8ถ้าอยากเห็นเป็นรูปจริงๆ เราสามารถใช้ Matplotlib ช่วยได้ครับ%matplotlib inlineimport matplotlib.pyplot as pltplt.figure(1, figsize=(3, 3))plt.imshow(first_digit, cmap=plt.cm.gray_r, interpolation='nearest')plt.show()ใช้ Matplotlib ช่วยแสดงค่าจากอาเรย์ 8x8 ออกมาเป็นรูปภาพถึงแม้ว่าบทความนี้จะแปลงข้อมูลจาก Tabular เป็นรูปขนาด 8x8 แต่จริงๆ เราก็สามารถแปลงรูปขนาด 8x8 ให้อยู่ในรูปแบบของ Feature Vector ขนาด 1x64 ได้ไม่ยากครับ แปลงไปแปลงกลับไม่โกง 😝ทีนี้ขั้นตอนการสร้างโมเดล เราก็สามารถทำตามปกติได้เลยครับ เพราะข้อมูลอยู่ในรูปแบบของ Tabular แล้ว โค้ดทั้งหมดมีตามนี้เลยครับ 👇 (ใช้โมเดล SVM)import pandas as pdfrom sklearn import svmdigits_train = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/optdigits/optdigits.tra', header=None)X_train = digits_train.drop([64], axis=1)y_train = digits_train[64]clf = svm.SVC()clf.fit(X_train, y_train)digits_test = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/optdigits/optdigits.tes', header=None)X_test = digits_test.drop([64], axis=1)y_test = digits_test[64]y_pred_class = clf.predict(X_test)clf.score(X_test, y_test)เป็นอันเสร็จสิ้น ที่เหลือก็เป็นขั้นตอนการปรับให้โมเดลของเราเก่งขึ้นครับผม 😎
โดย: Laris
|
รู้จัก Home Assistant (ตอนที่ 3)
สวัสดีค่ะ หลังจากที่คราวที่แล้ว พูดถึง MQTT และ Home Assistant และ MQTT Connector กันไปบ้างแล้ว วันนี้เราจะมาพูดถึงในส่วนของการส่งข้อมูลจากอุปกรณ์ และนำไปแสดงผลใน Home Assistant กันนะคะหลังจากที่ทบทวนการปรับแต่งโค๊ดกันในส่วนข้อมูลของอุปกรณ์ และข้อมูล MQTT กันไปแล้ว คราวนี้เราจะมาเชื่อม Hardware ของเราเข้ากับ Home Assistant กันคะกลับมาที่ฝั่ง Arduino ให้เปิดตัวอย่าง basic_mqtt เพื่อเริ่มต้นทบทวนบทความที่ผ่านมากันนะคะFile → Examples → CMMC MQTT Connector → basic_mqttเริ่มจากทบทวนของเก่ากันก่อนให้เราใช้ Library CMMC MQTT Connector กันเหมือนเดิม แก้ Device Name และ MQTT และ Prefix กันก่อนค่ะ_config.h หน้าจอปรับแต่งข้อมูล MQTTหลังจากนั้นก็เข้า HomeAssistant เพื่อปรับแต่งค่า MQTT ให้เหมือนกันค่ะ เริ่มเข้าผ่านทางหน้า Configuration → Integrationsได้เลยเลือก MQTT และกด Configureปรับแต่งค่า Brokerหลังจากนั้นเราก็ไปปรับแต่งค่าใน configuration.yaml เพื่อให้รองรับการเปิด-ปิดหลอดไฟค่ะ โดยเราจะกำหนดค่าตามข้างล่างนี้คะsource codeหลังจากนั้น ก็เปิด HomeAssistant ขึ้นมาก็จะเจอ UI สำหรับเปิดปิดหลอดไฟโผล่ขึ้นมาค่ะ เท่านี้เราก็จะควบคุมอุปกรณ์ผ่านหน้าเว็ปกันได้แล้วนะคะการแสดงผลของ Home Assistant บน iOSลองสั่ง เปิด — ปิด ไฟกันดูก่อนค่ะ ซึ่งทางผู้เขียน จะใช้ mosquitto-clients เข้ามา monitor ข้อมูลที่วิ่งไปวิ่งมาระหว่าง อุปกรณ์ และ Broker ด้วยคำสั่งmosquitto_sub -t "MYAPP/#" -h broker.hivemq.com -vmosquitto_sub -t "MYAPP/#" -h broker.hivemq.com -vจะเห็นว่าเพียงไม่กี่ขั้นตอน เราก็สามารถเปิดปิดไฟผ่านแอปได้แล้วค่ะ ไม่ยากใช่มั้ยคะ ถ้าใครยังงงๆอยู่ เราค่อยๆไปกันเรื่อยๆนะคะ เดี๋ยวเราจะทำโจทย์ที่เป็นการประยุกต์ที่เห็นภาพขึ้นเรื่อยๆนะคะ คราวหน้าเรามาลองเล่นกับการจัด group และการแสดงผลค่าจาก Sensor กันค่ะ
โดย: Kan Ouivirach
|
ใช้ Pickle เซฟและโหลด ML โมเดลใน Scikit-Learn ไปใช้งานต่อ
คำถาม? เวลาที่เราสอนโมเดลเสร็จแล้ว อยากเอาโมเดลนี้ไปใช้งานต่อที่อื่น หรือเอาไป deploy ใช้บน server เพื่อใช้งานจริงๆ ต้องทำอย่างไร?คำถามนี้เจอค่อนข้างบ่อย เมื่อก่อนอาจจะยังไม่ค่อยมีคำถามนี้เพราะว่า Machine Learning ยังอยู่ฝั่ง Academia ซะเป็นส่วนใหญ่ แต่ปัจจุบันนี้ออกมาทางฝั่ง Industry เยอะมากแล้ว และแน่นอนว่าจะต้องมีการใช้งานโมเดลจริงๆ จังๆ ไม่ใช่แค่สอนโมเดล ดูผลการทดลองแล้วก็จบเนอะ 😎แน่นอนว่าเราไม่ควรไปสอนโมเดลอีกรอบบน server เพราะน่าใช้เวลานานมาก ถ้าเป็นโมเดลเล็กๆ ก็อาจจะใช้เวลา 2–3 วินาที แต่ในชีวิตจริง เราน่าจะใช้เวลาในการเทรนประมาณ 2–3 ชม. หรือ อาจจะเป็นอาทิตย์ก็เป็นได้ 😱บทความนี้จะมาสอนให้เราสามารถสอนโมเดลใน Scikit-Learn ครั้งเดียว แล้วเซฟไปใช้งานที่ไหนต่อก็ได้ครับ เรามาสร้างโมเดล K-means แบบง่ายๆ กันimport pandas as pdfrom sklearn import clusterdata = { 'data': [2, 3, 4, 10, 12, 20, 30, 11, 25]}df = pd.DataFrame(data)kmeans = cluster.KMeans(n_clusters=2)kmeans.fit(df)พอเสร็จแล้วเราจะได้ Centroid มาcentroids = kmeans.cluster_centers_print(centroids)จุด Centroid ที่ได้จาก K-meansถ้าเราอยากนำโมเดล (ตัวแปร kmeans) ไปใช้งานต่อ เราจะใช้ตัวช่วยที่ชื่อว่า Pickle ครับ วิธีใช้ก็ตามนี้import picklef = open('kmeans.pkl', 'wb')pickle.dump(kmeans, f)f.close()เราจะเปิดไฟล์มาเขียนให้เป็น Binary mode และสั่ง pickle.dump ครับ เสร็จแล้วเราก็จะได้ไฟล์ kmeans.pkl เอาไปใช้ที่ไหนก็ได้!!วิธีเอาไปใช้ก็เอาไฟล์นั้นขึ้นไปวางบน server ครับ หรือที่เราเรียกกันว่า Model Deployment นั่นแหละ ทีนี้การโหลดโมเดลขึ้นมาใช้งาน เราก็จะใช้ Pickle เช่นกัน ตามนี้ครับimport picklef = open('kmeans.pkl', 'rb')stored_kmeans = pickle.load(f)f.close()ยืนยันสักหน่อยว่าเราได้โมเดลเดียวกันprint(stored_kmeans.cluster_centers_)จุด Centroid ที่ได้จาก K-means ที่เราโหลดขึ้นมาใหม่น่าจะพอเห็นภาพกันนะครับ 😉
โดย: Pii
|
เกมกับบล็อคเชนในอนาคต
ช่วงนี้ตลาดเหรียญคริปโตมีการตื่นตัวมากเป็นพิเศษ จากการที่มีข่าวต่างๆของโปรเจคที่ทยอยเปิดตัวสร้างความมั่นใจให้ทั้งนักลงทุน นักพัฒนาและผู้บริโภคของวงการนี้ ปัจจุบันแนวคิดและคอนเซปต่างๆเกี่ยวกับการประยุกต์ใช้บล็อคเชนค่อยๆเริ่มเป็นรูปเป็นร่างมากขึ้นจากการที่มีนักพัฒนากระโดดร่วมลงมาศึกษาและพัฒนาแอพต่างๆบนบล็อคเชนมากขึ้นเรื่อยๆ อุตสาหกรรมเกมถือว่ามีข้อได้เปรียบในการรับเอาเทคโนโลยีใหม่ๆมาประยุคต์ใช้ได้เร็วกว่าอุตสาหกรรมอื่นๆมากไม่ใช่แต่เทคโนโลยีบล็อคเชน ปัจจุบันทั่วโลก(ปี 2561)อุตสาหกรรมเกมมีมูลค่ากว่า 4 พันล้านบาท ซึ่งตัวเลขนี้มีแนวโน้มสูงขึ้นได้อีกจากการที่มูลค่าของสิ่งของต่างๆที่ใช้หรือปรากฎในเกมจะกลายเป็นทรัพย์สินขึ้นมาจริงๆด้วยบล็อคเชนบล็อคเชนจะเปลี่ยนของที่มีในเกมให้กลายเป็นทรัพย์สินจริงๆ ซึ่งหมายความว่าสิ่งของอะไรก็ตามที่เรามีในเกม ของนั้นๆจะไม่สามารถถูกทำให้หายไปได้โดยคนอื่น(ขึ้นอยู่กับเงื่อนไขรายละเอียด) เช่น ผมมีดาบสีทองที่หายากมากๆในเกม ดาบของผมจะยังคงเป็นของผม แม้ว่าจะหยุดเล่นไป 10 ปี บล็อคเชนจะทำให้คุณสมบัติของดาบเล่มนั้นมีแค่เล่มเดียวในระบบ ก๊อปปี้คัดลอกไม่ได้ GM เสกมาใหม่ไม่ได้ ถ้ามีคนอื่นได้ดาบสีทองเหมือนกัน ระบบจะถือว่าเป็นดาบคนละเล่มกัน ของแต่ละชิ้นจะสามารถมีคุณสมบัติเป็นเอกลักษณ์มีชิ้นเดียวได้ สามารถซื้อขายส่งถ่ายให้คนอื่นได้เราอาจได้เห็นแนวคิดระบบเกมที่เปลี่ยนไป เช่น เกมการ์ดอย่าง Hearthstone สามารถซื้อขายระหว่างคนเล่นได้เหมือนกับการ์ดกระดาษจริงๆ โปเกมอนที่เราเลี้ยงหรือจับมาในเกมจะสามารถนำไปใช้เล่นต่อในภาคอื่นหรือเกมอื่นที่รองรับข้อมูลประเภทเดียวกันได้ โปเกมอนที่อยู่บนบล็อคเชนจะไม่หายไปกีต้าที่ใช้ในคอนเสิร์ตบนโลกออนไลน์จะสามารถนำไปประมูลขายได้(เพราะมีชิ้นเดียว)ไอเทมต่างๆในเกมแรกนาร็อคแม้ว่าปัจจุบันจะมีการซื้อขายด้วยเงินจริงอยู่แล้วหากใช้บล็อคเชนมาประกบ ไอเทมเหล่านั้นจะยิ่งมีมูลค่าสูงยิ่งขึ้น ด้วยการที่ไอเทมเหล่านั้นไม่สามารถถูกเสกหรือปั๊มออกมาได้ แม้จะเป็นเจ้าของเกมก็ตามสิ่งของต่างๆที่เคยเป็นเพียงข้อมูลที่ไม่มีมูลค่าเนื่องจากสามารถคัดลอกได้ไม่จำกัด จะถูกจำกัดและไม่สามารถคัดลอกได้ด้วยบล็อคเชน ทุกคนสามารถเชื่อถือเงื่อนไขของระบบได้ 100% บล็อคเชนจะค่อยๆผนวกควบรวมเอาโลกแห่งความจริงกับโลกดิจิตอลเข้าเป็นอันหนึ่งอันเดียวกัน ผ่านเงื่อนไขที่โปร่งใสที่เมื่อตั้งขึ้นแล้วไม่มีใครสามารถอยู่เหนือมันได้ ทุกคนที่อยู่ในระบบจะถูกบังคับให้อยู่บนเงื่อนไขเดียวกันอย่างแท้จริง
โดย: Kan Ouivirach
|
ปรับ Parameters ของโมเดล ML ด้วย GridSearchCV ใน Scikit-Learn
ปกติเวลาที่เราอยากจะปรับโมเดล หรือหา Parameters ที่ดีที่สุดของโมเดลที่เหมาะสมกับข้อมูลที่เรานำมาสอน เราจะใช้วิธี Cross Validation และกำหนดว่าเราจะ Vary ค่าต่างๆ ของ Parameters ของเราอย่างไร หน้าตาโค้ดของเราก็จะประมาณนี้from sklearn import datasetsfrom sklearn.model_selection import cross_val_scorefrom sklearn.neighbors import KNeighborsClassifieriris = datasets.load_iris()X = iris.datay = iris.targetknn = KNeighborsClassifier(n_neighbors=5)scores = cross_val_score(knn, X, y, cv=10, scoring='accuracy')print(scores)แล้วถ้าเราต้องการที่จะ Vary ค่าต่างๆ เราอาจจะใช้ Loop ได้ประมาณนี้from sklearn import datasetsfrom sklearn.model_selection import cross_val_scorefrom sklearn.neighbors import KNeighborsClassifieriris = datasets.load_iris()X = iris.datay = iris.targetn_neighbors = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]weights = ['uniform', 'distance']algorithms = ['auto', 'kd_tree']score_collection = []for n in n_neighbors: for w in weights: for a in algorithms: knn = KNeighborsClassifier(n_neighbors=n, weights=w, algorithm=a) scores = cross_val_score(knn, X, y, cv=10, scoring='accuracy') score_collection.append(scores) print(score_collection)แล้วถ้าเราอยากรู้ว่าค่า Parameters ชุดไหนที่ทำให้โมเดลเราได้ผลที่ดีที่สุด เราก็อาจจะต้องเก็บ Index ของแต่ละรอบไว้ และเขียนโค้ดเพื่อหาว่ารอบไหนที่ให้ผลที่ดีที่สุดให้ผลดีที่สุด แต่ถ้าเราใช้ GridSearchCV ก็จะได้ประมาณนี้from sklearn import datasetsfrom sklearn.model_selection import GridSearchCVfrom sklearn.neighbors import KNeighborsClassifieriris = datasets.load_iris()X = iris.datay = iris.targetparam_grid = dict( n_neighbors=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], weights=['uniform', 'distance'], algorithm=['auto', 'kd_tree'])knn = KNeighborsClassifier()clf = GridSearchCV(knn, param_grid=param_grid, cv=10)clf.fit(X, y)print(clf.best_params_)โค้ดเราดูเป็นระเบียบมากขึ้นเยอะ 😎 ถ้าเราอยากจะ Vary ค่า Parameter เพิ่ม เราก็แค่เพิ่มเข้าไปใน dict นั้นพอ ไม่ต้องไปเพิ่ม Loop แบบตัวอย่างด้านบนวิธี GridSearchCV ยังมีข้อดีอีกข้อคือ เราสามารถเอาผลลัพธ์ที่ได้ไปทำนายผลต่อได้ครับclf.predict([[3, 5, 4, 2],])ชีวิตสบายขึ้นไม่รู้กี่เท่า 😚ทีนี้ถ้าข้อมูลเราเยอะมากๆ การที่จะทำให้วิธีวนลูปวิธีแรกทำงานได้เร็วขึ้น หรือเอาไปแยก Process ทำงาน ก็อาจจะต้องเหนื่อยเขียนโค้ดปรับๆ กัน ทีนี้ทีม Databricks ได้พัฒนาต่อยอด GridSearchCV ให้สามารถมารันบน Apache Spark ได้databricks/spark-sklearnScikit-learn integration package for Apache Spark. Contribute to databricks/spark-sklearn development by creating an…github.comเราแค่แก้ตรง Import!! ไม่ต้องมาแก้โค้ดตรงส่วนที่เขียน GridSearchCV เลย เด็ดมาก! 🎉 ตามนี้เลยครับ โค้ดส่วนที่แก้ไขคือส่วนที่เป็นตัวหนาfrom sklearn import datasetsfrom spark_sklearn import GridSearchCVfrom sklearn.neighbors import KNeighborsClassifieriris = datasets.load_iris()X = iris.datay = iris.targetparam_grid = dict( n_neighbors=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], weights=['uniform', 'distance'], algorithm=['auto', 'kd_tree'])knn = KNeighborsClassifier()clf = GridSearchCV(knn, param_grid=param_grid, cv=10)clf.fit(X, y)print(clf.best_params_)Happy Tuning ครับ 🎉
โดย: Pii
|
บล็อคเชนกับการกระจายฐานข้อมูล(distributed ledgers)
เทคโนโลยีบล็อคเชนในความหมายสั้นๆก็คือการกระจายฐานข้อมูลที่เหมือนกันออกมาหลายจุด ครอบครองโดยหลายองค์กร เพื่อความโปร่ง สามารถตรวจสอบได้ง่าย(เพราะมีหลายชุดให้เทียบกัน) และมีความยืดหยุ่นสูง การประยุกต์ใช้บล็อคเชนจะทำให้เราไม่ต้องพึ่งพาและเชื่อใจให้องค์กรใดองค์กรหนึ่งดูแลรักษาข้อมูลสำคัญของเราและข้อมูลที่เกิดจากเราเหมือนแต่ก่อน เราจะสามารถเข้าถึงและควบคุมจัดการดูแลข้อมูลเหล่านี้ด้วยเราเองได้มากกว่าแต่ก่อนบล็อคเชนนั้นจริงๆแล้วมีแนวคิดมาจากฐานข้อมูลประเภทบัญชี(ledgers)ที่เราต่างรู้จักกันเป็นอย่างดี เช่น บัญชีธนาคาร บัญชีบัตรเครดิต และบัญชีรายรับรายจ่ายภาครัฐ ฐานข้อมูลบัญชีที่ถูกเก็บดูแลโดยองค์กรใดองค์กรหนึ่งเหล่านี้มีคุณสมบัติข้อดีหลายอย่าง เช่น การควบคุมคนที่จะเขียนข้อมูลเพิ่มลงในฐานข้อมูล(จำกัดสิทธิ์) ประสิทธิภาพและความเร็วในการเขียนและอ่านข้อมูล(รู้ว่าฐานข้อมูลตั้งอยู่ที่ไหน) และความสามารถในการควบคุมแก้ไขเข้าถึงข้อมูลเหล่านั้น เราเรียกการแก้ไขข้อมูลบัญชี 1 รายการว่า 1 transaction ข้อมูลในแต่ละ transaction จะต้องเขียน(insert)ให้ครบถ้วนเพื่อให้ตัวเลขทั้งหมดถูกต้อง transaction แต่ละอันจะต้องไม่ถูกแก้ไขหลังจากเขียนเสร็จไปแล้ว หรือถ้าสามารถแก้ไขได้จะต้องมีขั้นตอนตรวจสอบที่มีมาตรฐานมากเพียงพอ ปัจจุบันการกระจายฐานข้อมูลประเภทบัญชี(distributed ledgers)มีแนวโน้มเป็นที่นิยมมากขึ้นเรื่อยๆ ซึ่งฐานกระจายเหล่านี้ไม่ต้องพึ่งองค์กรใดองค์กรหนึ่งในการดูแลข้อมูลทั้งหมด องค์กรที่มีส่วนในการร่วมถือครองฐานข้อมูลเหล่านี้จะต้องตกลงเงื่อนไขในการใช้งานร่วมกัน เช่น การใช้ public/private key ในการสั่งเขียนข้อมูลเพิ่มลงในระบบ ซึ่งระบบก็จะรู้ว่าใครเป็นคนสั่งให้เขียนและคนๆนั้นมีสิทธิ์ที่จะเขียนหรือไม่ ระบบฐานกระจายนี้จะช่วยให้องค์กรที่มีส่วนร่วมสามารถเข้าถึงข้อมูลได้สะดวกรวดเร็วและประหยัดขึ้น(เทียบกับการต้องร้องขอเอาจากองค์กรอื่น) มีความน่าเชื่อถือมากขึ้น(ไม่ใช่นึกจะแก้ตัวเลขอะไรก็แก้ได้เลย) และปลอดภัยมากขึ้น(คนแฮกต้องแฮกหลายที่) อย่างไรก็ตามการอ่านข้อมูลล่าสุดจากระบบฐานกระจายดังกล่าวจะช้ากว่าฐานเดี่ยวมาก เพราะต้องคอยตรวจสอบจากฐานอื่นว่าข้อมูลตรงกันหรือไม่ และรวมไปถึงการที่ฐานแต่ละฐานจะได้รับข้อมูลล่าสุดจริงๆไม่พร้อมกันในทันที นิยามของการเป็นฐานกระจาย(distributed ledgers)อย่างแท้จริงคือการมีฐานที่แชร์ข้อมูลกันกระจายตัวอยู่ในพื้นที่ต่างๆทั่วโลก มีระบบตรวจสอบสิทธิ์คนเขียนข้อมูลตามข้อตกลงร่วม มีระบบแชร์ข้อมูลระหว่างฐานที่มีประสิทธิภาพ และมีระบบตรวจสอบความถูกต้อง(การเทียบข้อมูลระหว่างฐาน)ทางคณิตศาสตร์(cryptographic infrastructure)ที่มีประสิทธิภาพบล็อคเชนคือ ฐานกระจาย(distributed ledgers)รูปแบบหนึ่ง ที่มีการเก็บข้อมูล(data structure)แบบเฉพาะในชื่อ blockchain และใช้ข้อตกลงในการเขียนข้อมูลแบบ Prove of Work
โดย: Kan Ouivirach
|
มาเล่น Sentiment Analysis โดยใช้ Python กัน
How is it going? Positive, Neutral, or Negative?เกริ่นก่อน Sentiment Analysis เนี่ย มันคือกระบวนการที่เราสามารถบอกและแยกแยะอารมณ์ที่แสดงออกมาในข้อความหนึ่งๆ ซึ่งในข้อความนั้นๆ อาจจะออกมาเป็นแง่บวก (positive) แง่ลบ (negative) หรือแบบเฉยๆ (neutral) ก็ได้ปัญหาของเราคือ ถ้าเรามีข้อมูลประมาณด้านล่างนี้ เราจะเอาไปสร้างโมเดล Sentiment Analysis อย่างไร?ข้อมูล Feedback จากระบบหนึ่งเอ๊ะ ที่เราเรียนมาข้อมูลมันจะออกแนวแบ่งเป็น Column ไม่ใช่เหรอ แต่ละ Column คือ 1 Feature ไม่ใช่เหรอ แล้วถ้าเป็นข้อความแบบนี้เราจะทำอย่างไรดีนะ 🤔มีวิธี Preprocessing อยู่หลายแบบครับ แบบที่ง่ายๆ ที่เราจะมาลองกันในบทความนี้เรียกว่า Bag-of-words model ครับผม ขอเอาตัวอย่างจากใน Wiki มาอธิบายนะครับ ถ้าข้อความเราคือJohn likes to watch movies. Mary likes movies too.เราจะแปลงให้อยู่ในรูปแบบของ JSON ได้แบบนี้bag_of_words_1 = {"John": 1, "likes": 2, "to": 1, "watch": 1, "movies": 2, "Mary":1, "too": 1}สังเกตไหมว่าจริงๆ แล้วมันคือการนับคำนั่นเอง!! 😎 แล้วแต่ละ Key คือคำที่อยู่ในข้อความ และ Value คือจำนวนคำๆ นั้นในข้อความนั่นเอง ถ้ายังไม่คุ้น ลองมาดูในรูปแบบที่เราคุ้นเคยกันดีกว่าBag of Words จากข้อความ “John likes to watch movies. Mary likes movies too.”Key ใน JSON เราสามารถมองเป็นหัว Column ได้เลย ถ้ายังมึนๆ อยู่ ลองดูรูปด้านล่างนี้ครับ น่าจะช่วยให้เข้าใจมากขึ้น 👍รูป Bag of Words จาก https://slideplayer.com/slide/7073400/ทีนี้ปัญหาของเราก็จะอยู่ที่ว่าเราจะเลือกคำอะไรบ้างเอามาสร้างโมเดล ซึ่งตรงจุดนี้เป็นจุดที่ยากที่สุดครับ.. วิธีการเลือกคำนี่สามารถเป็นอีกศาสตร์หนึ่งได้เลย ศาสตร์นั้นคือ Natural language processing ครับผม ลองไปศึกษาเพิ่มเติมกันดูเนอะกลับมาที่ข้อมูลเราบ้าง เราจะใช้ตัวช่วยนับ CountVectorizer จาก Scikit-Learn ครับ ง่ายมาก! ตามนี้เลยimport pandas as pdfrom sklearn.feature_extraction.text import CountVectorizertext = [ 'Promptly answer to my request.', 'great turnaround time!', 'Fast response and great service!', 'As usual you took the request and completed in as few steps as possible and well done!', 'Very quick turnaround time and great communication. Thank you!', 'Really quick turnaround. Thanks!!', 'reduce the turn around time and increase/upgrade the interaction ability between the client and the pronto team during the building of the website.', 'Better turn around time for changes and updates. Better copywriting talents for web content rewrite requests.', 'Get back to us faster', 'Be more careful when fixing our site to not break the other coding on other pages', 'All of the information for this listing is already on the website that Pronto built. It is disappointing that this has taken so many tries to get right.', 'slow communication regarding SEO questions, emailing SEO team direct has been slower that going through my account rep- vague and incomplete answers wasting time', 'The time difference and language barrier are my main complaints. Otherwise our website looks great.', 'Process is way too slow. Working with another country seems to really slow things down alot.',]label = [ 'positive', 'positive', 'positive', 'positive', 'positive', 'positive', 'neutral', 'neutral', 'neutral', 'neutral', 'negative', 'negative', 'negative', 'negative',]df = pd.DataFrame(data={ 'text': text, 'label': label})vectorizer = CountVectorizer(stop_words='english')X_train = df.texty_train = df.labelX_train_vectorized = vectorizer.fit_transform(X_train)เพียงเท่านี้เราจะได้ข้อมูลของเราอยู่ในรูปแบบที่เราต้องการแล้ววววข้อมูลข้อความหลังจากที่ทำ Bag of Wordsถ้าเราอยากดูว่า CounterVectorizer เลือกคำอะไรมาให้เราบ้าง เราจะสั่งฟังก์ชั่น get_feature_names ตามนี้กับตัว vectorizer ของเราครับคำที่ CountVectorizer เลือกมาเท่านี้เราก็สามารถนำเข้าโมเดลของเราได้แล้วครับ จัดกันเลย~ ลอง Naive Bayes ละกัน# importfrom sklearn import naive_bayes# instantiateclf = naive_bayes.MultinomialNB()# fitclf.fit(X_train_vectorized, y_train)แล้วถ้าเราอยากจะลองทดสอบกับข้อความใหม่ เพื่อดูว่าจะเป็น Positive, Neutral หรือ Negative สิ่งที่เราต้องทำก่อนคือ เราต้องแปลงข้อความใหม่นั้นให้อยู่ใน Bag of Words แบบเดียวกับที่เราเอาเข้าไปสอนโมเดลของเราก่อนครับ ซึ่งวิธีการแปลงเราจะ “ต้อง” เอาตัว vectorizer ที่เราสร้างไว้กับข้อมูลที่ใช้สอนมาใช้ตรงนี้ครับ จุดนี้สำคัญเลย“เราแปลงข้อมูลที่เราใช้สอนด้วยวิธีไหน เราต้องแปลงข้อมูลที่เราจะใช้ทดสอบด้วยวิธีเดียวกัน”ทำได้ตามนี้ (ข้อความแรกเป็น Positive ข้อความที่ 2 เป็น Neutral ส่วนข้อความที่ 3 เป็น Negative)# positive, neutral, negativeX_test = [ 'Fast service! Thank you', 'wish it could have been resolved sooner as it was simple', 'Cannot get my website where I want because repeated requests are misunderstood, requests are simply not honored.',]X_test_vectorized = vectorizer.transform(X_test)ตัวแปร X_test_vectorized จะเป็นตัวแปรที่แปลงข้อความ 3 ข้อความนั้นให้อยู่ในรูปแบบของ Bag of Words ให้เรา ต่อจากนี้เราก็เอาไปทดสอบกับโมเดลของเราได้เลยโค้ดส่วนการสร้างโมเดล Sentiment Analysisเราเพิ่งจะสร้างโมเดลทำ Sentiment Analysis ไปเรียบร้อยแล้ว 🎉ผลที่ได้ออกมาก็ดูพอไปวัดไปวาได้ครับ แต่อย่าเพิ่งเชื่อถือมากไปนะ 😂 เราควรปรับโมเดลของเราให้ดีขึ้นเรื่อยๆ ทำให้น่าเชื่อถือมากขึ้น ข้อมูลเพิ่ม เลือกคำให้ดีขึ้น ทำ Cross Validation ทำ ฯลฯขอให้สนุกกับการทำ Sentiment Analysis ครับผม 😙
โดย: Laris
|
มารู้จัก MQTT Protocol กันดีกว่า (ตอนที่ 6)
หลังจากที่ได้ทำความรู้จักกับอีกหนึ่ง Feature ใน MQTT — LWT หรือ Last Will Testment กันไปแล้วนะคะ จะเห็นว่า LWT สามารถเข้ามาช่วยเราจัดการกับการปัญหาการเชื่อมต่อขาดๆหายๆได้อย่างไร แล้วถ้าเอามาจับคู่กับ Retained Message ก็จะยิ่งช่วยเพิ่มประสิทธิภาพให้กับ MQTT ขึ้นมาอีกเยอะเลยค่ะ และในบทความที่แล้วเราก็ยังค้างกันอยู่ที่ Keep Alive ค่ะ ว่าคืออะไร เกี่ยวข้องกับ LWT Message ยังไง วันนี้มาทำความรู้จักกันค่ะMQTT Keep Alive เป็นอีก Feature นึง ของ MQTT ค่ะ ซึ่งมีบทบาทสำคัญเลยสำหรับ Mobile Network ค่ะอย่างที่ทราบนะคะว่า MQTT ใช้การเชื่อมแต่แบบ TCP/IP ซึ่งมีความน่าเชื่อถือสูง มีการการันตีว่าการส่งข้อมูลจะถึงมือผู้รับแน่นอน ไม่มีผิดเพี้ยนแต่…..ในระหว่างการเชื่อมต่อนี้(ระหว่าง Broker และ Client) อาจจะมีฝ่ายใดฝ่ายนึงเกิดหลุด sync กันไปค่ะ (out of synchronization) อย่างเช่น ถ้าเกิดฝ่ายใดฝ่ายนึงเกิด crash ขึ้นมา ไม่สามารถทำงานได้ตามปกติค่ะ โดยที่อีกฝ่ายไม่สามารถรับรู้ได้เลยว่า อีกฝั่งนึงนั้นได้ตายไปแล้ว ก็จะยังคงส่งข้อความไปให้เรื่อยๆ และรอรับ ACK Message ซึ่งสภาวะแบบนี้ใน TCP จะเรียกว่า half-open connection ค่ะ ซึ่งถือว่าเป็นปัญหาสำคัญเลยคะดังนั้น MQTT จึงได้นำ Keep Alive เข้ามาช่วยแก้ปัญหา half-open connection ตรงนี้ค่ะ หรืออย่างน้อยก็สามารถบอกได้ว่าเกิดภาวะ half-open connection ขึ้น Keep Alive จะช่วยเชคและการันตีว่าการเชื่อมต่อระหว่าง Broker และ Client นั้นยังเปิดอยู่Client จะเป็นคนกำหนด ค่า Keep Alive ซึ่งจะกำหนดไว้ในช่วงเริ่มแรกที่ทำการขอเชื่อมต่อกับ Broker ค่านี้มีหน่วยเป็นวินาทีค่ะ (สามารถตั้งค่าได้มากสุด 18 ชั่วโม 12 นาที 15 วินาที หรือ 65535 วินาที ค่ะ) ซึ่งการที่ Client เป็นคนกำหนด Keep Alive เองจะช่วยให้ Client สามารถปรับค่า Keep Alive ให้ตรงกับความแรงของสัญญาณเนทเวิคของตัวเองได้หลังจากทำการเชื่อมต่อ ในระหว่างนี้หาก Client ไม่ทำการส่ง Control Message ใดๆ เช่น PUBLISH, PINGREQ, หรือ DISCONNECT ให้กับ Broker ​ไม่เกินระยะเวลาที่กำหนดใน Keep Alive ตัว Broker จะยังไม่ถือว่า Client ได้ตัดขาดการเชื่อมต่อไป ยังถือว่าการเชื่อมต่อกับ Client นี้ยังเปิดอยู่ แต่ Client จะต้องส่ง PINGREQ ไปให้ Broker นะค่ะ (ไม่ใช่หายไปเลยนะ) ซึ่ง Client จะส่ง PINGREQ เมื่อไหร่ก็ได้ค่ะ ซึ่ง Broker เองก็ต้องตอบกลับด้วย PINGRESP นะคะ เพื่อที่จะให้ Client มั่นใจว่า ​Broker เองก็อยังอยู่ดีค่ะ ยังมีการเชื่อมต่อกับ Client อยู่แต่สำหรับ Broker หากว่าไม่มี Message หรือว่า PINGREQ จาก Client ส่งมาภายใน 1.5 * Keep Alive Period แล้วละก็ Broker จะทำการ Disconnect ไปเลยค่ะ และจะส่ง LWT Message ให้ค่ะ(ถ้า Client ได้กำหนด LWT ไว้นะคะ)โดยปกติแล้วใน MQTT ถ้า Broker เจอว่ามี half-open connection ค้างอยู่ Broker จะจัดการด้วยสิ่งที่เรียกว่า Client Take-over ค่ะ นั่นคือ Broker จะทำการ Disconnect การเชื่อมต่อก่อนหน้านี้กับ Cleint ตัวนี้ หลังจากนั้นก็จะทำการเชื่อมต่อให้ Client ตัวนี้ใหม่ค่ะ เพื่อให้มั่นใจว่าปัญหา half-open connection นี้จะไม่เป็นอุปสรรคต่อ Client ที่ถูก Disconnect ไป แล้วต้องการอยากจะกลับมา Connect ใหม่ค่ะอ้างอิงจาก MQTT Essentials Part 10: Keep Alive and Client Take-Over
โดย: Kan Ouivirach
|
Visualize โมเดล Tree ใน Scikit-Learn
เวลาที่เราสร้างโมเดลประเภท Tree อย่างเช่น Decision Tree จะมีข้อดีอย่างหนึ่งคือโมเดลพวกนี้สามารถนำมาวาดรูปให้คนอ่านรู้เรื่องได้ (จริงๆ โมเดลอื่นก็วาดรูปได้นะ แต่ไม่ user friendly เท่ากับโมเดลประเภท Tree) ถ้าเราใช้ Scikit-Learn แล้วเราอยากจะดูว่าโมเดลเราหน้าตาเป็นแบบไหน เราจะทำอย่างไร?เริ่มด้วยการสร้างโมเดลแบบ Tree สักโมเดลหนึ่งมาก่อน ขอเป็น Decision Tree ละกันเนอะ เขียนโค้ดได้ตามนี้เลยfrom sklearn import tree, datasetsfrom sklearn.metrics import accuracy_scorefrom sklearn.model_selection import train_test_splitiris = datasets.load_iris()X, y = iris.data, iris.targetX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)clf = tree.DecisionTreeClassifier()clf.fit(X_train, y_train)y_pred = clf.predict(X_test)print(accuracy_score(y_test, y_pred))ทีนี้ใน Module ที่ชื่อ tree ที่เรา import มาตอนแรกจะมีฟังก์ชั่นชื่อ export_graphviz ครับ เราจะใช้ฟังก์ชั่นนี้แหละสร้าง Graph ออกมา โดยฟังก์ชั่นนี้ใช้ Graphviz ครับ ซึ่งใช้ไฟล์ DOT language ในการอธิบายหน้าตาของ Graphให้เราเขียนโค้ดเพิ่มเพื่อเรียกใช้ export_graphviz ตามนี้tree.export_graphviz(clf,out_file=’tree.dot’,feature_names=iris.feature_names,class_names=iris.target_names,filled=True,rounded=True)เราจะใส่โมเดลที่เราสอน (clf) เข้าไป ตั้งชื่อ output file ว่า tree.dot ในไฟล์นั้นจะมีชื่อ feature (feature_names=iris.feature_names) มีชื่อ class (class_names=iris.target_names) แต่ละโหนดจะมีสี (filled=True) แล้วก็แต่ละโหนดจะเป็นสี่เหลี่ยมมนๆ (rounded=True)หลังจากรันโค้ดด้านบนเสร็จเราก็จะได้ไฟล์ tree.dot ออกมา หน้าตาเนื้อหาในไฟล์ก็จะประมาณนี้รูปแสดงข้อมูลในไฟล์ tree.dotอ่านไม่ค่อยรู้เรื่องเนอะ >_< เรามาทำให้เป็นรูปกันดีกว่า ให้เราติดตั้ง Graphviz ก่อนครับ ถ้าเป็นเครื่อง Mac ก็สั่งbrew install graphvizแต่ถ้าใช้เครื่องแบบอื่นลองตามไปดูวิธีที่หน้า Download ได้เลยครับผม พอติดตั้งเสร็จ เราสามารถแปลงเป็นไฟล์ PNG โดยใช้คำสั่งdot -Tpng tree.dot -o tree.pngเปิดรูปมาดูควรจะเห็นตามรูปด้านล่างนี้เลยครับรูปโมเดล Decision Tree กับข้อมูล Irisทีนี้ใครที่ทำโมเดลประเภทนี้ก็สามารถเอารูปนี้ไปช่วยเรื่อง communication ได้แล้ว~ เด็ด!ถ้าใครอยากเห็นโค้ดเต็มๆ สามารถดูได้ที่ intro-to-machine-learning/tree.ipynb ครับ ;)

พบบทสัมภาษณ์ได้ที่นี่เร็ว ๆ นี้

พบDigital Skill บนสื่อ ได้ที่นี่เร็ว ๆ นี้

หมวดหมู่

พบหมวดหมู่ ได้ที่นี่เร็ว ๆ นี้

พบหมวดหมู่ ได้ที่นี่เร็ว ๆ นี้

Tags

พบคำสำคัญ ได้ที่นี่เร็ว ๆ นี้

พบคำสำคัญ ได้ที่นี่เร็ว ๆ นี้

พบคำสำคัญ ได้ที่นี่เร็ว ๆ นี้