ไวยากรณ์ Python พื้นฐานที่ใช้บ่อยในวิทยาการข้อมูล

ช่วงสองวันนี้ผมได้อ่านหนังสือ Data Science from Scrach (ดาวน์โหลด PDF ได้ที่นี่) ซึ่งเป็นหนังสือแนะนำวิทยาการข้อมูลเบื้องต้นที่ยอดเยี่ยม อ่านเข้าใจง่ายและเข้าถึงได้ทุกคนครับ ในบทหนึ่งของหนังสือได้แนะนำไวยากรณ์พื้นฐานของ Python และไวยากรณ์ขั้นสูงที่ใช้บ่อยในวิทยาการข้อมูล ผมเห็นว่าคำอธิบายทำได้ดี กระชับและเข้าใจง่าย จึงขอแปลและรวบรวมไว้ที่นี่เพื่อเป็นบันทึกช่วยจำครับ
ไวยากรณ์ Python ที่ใช้บ่อยในวิทยาการข้อมูล (พื้นฐาน)
ไวยากรณ์ Python ที่ใช้บ่อยในวิทยาการข้อมูล (ขั้นสูง)

บทนี้จะเน้นการแนะนำไวยากรณ์และฟังก์ชันพื้นฐานของ Python ที่มีประโยชน์อย่างมากในการประมวลผลข้อมูล (อ้างอิงจาก Python 2.7)

รูปแบบการเว้นวรรค

ภาษาโปรแกรมหลายภาษาใช้เครื่องหมายวงเล็บปีกกาเพื่อควบคุมบล็อกโค้ด แต่ Python ใช้วิธีการย่อหน้า (indentation) แทน:

for i in [1, 2, 3, 4, 5]:  
    print i          # บรรทัดแรกของลูป "for i"  
    for j in [1, 2, 3, 4, 5]:  
        print j      # บรรทัดแรกของลูป "for j"  
        print i + j  # บรรทัดสุดท้ายของลูป "for j"  
    print i          # บรรทัดสุดท้ายของลูป "for i"  
print "done looping"  

สิ่งนี้ทำให้โค้ด Python อ่านง่ายมาก แต่ก็หมายความว่าคุณต้องให้ความสำคัญกับรูปแบบการจัดวางโค้ดอยู่เสมอ ช่องว่างภายในวงเล็บจะถูกละเว้น ซึ่งมีประโยชน์เมื่อเขียนนิพจน์ที่ยาวๆ:

long_winded_computation = (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20)  

และยังช่วยให้โค้ดอ่านง่ายขึ้นด้วย:

list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]  
easier_to_read_list_of_lists = [ [1, 2, 3],  
                                 [4 ,5 ,6 ],  
                                 [7 ,8 ,9 ] ]  

คำสั่งหลายบรรทัด

สามารถใช้เครื่องหมายแบ็กสแลช (\) เพื่อเชื่อมต่อสองบรรทัดที่ถูกแบ่งออกจากกัน (วิธีนี้ไม่ค่อยนิยมใช้):

two_plus_three = 2 + \
                 3  

โมดูล (Modules)

ไม่ว่าจะเป็นโมดูลที่มาพร้อมกับ Python หรือโมดูลบุคคลที่สามที่คุณดาวน์โหลดมา คุณจำเป็นต้องนำเข้า (import) โมดูลเหล่านั้นด้วยตนเองก่อนจึงจะสามารถใช้งานได้

  1. นำเข้าโมดูลทั้งหมดโดยตรงแบบง่ายๆ:
import re  
my_regex = re.compile("[0-9]+", re.I)  

โมดูล re ที่นำเข้าในที่นี้ใช้สำหรับ Regular Expressions หลังจากนำเข้าโมดูลแล้ว คุณสามารถเรียกใช้ฟังก์ชันเฉพาะได้โดยตรงโดยใช้ชื่อโมดูลเป็นคำนำหน้า (เช่น re.)

  1. หากชื่อโมดูลที่คุณต้องการนำเข้าถูกใช้ไปแล้วในโค้ด คุณสามารถแมปโมดูลนั้นให้เป็นชื่ออื่นได้เมื่อนำเข้า:
import re as regex  
my_regex = regex.compile("[0-9]+", regex.I)  
  1. ถ้าคุณเป็นคนไม่ดี คุณสามารถนำเข้าโมดูลทั้งหมดเข้าสู่เนมสเปซปัจจุบันได้ ซึ่งอาจทำให้เกิดการเขียนทับตัวแปรที่คุณได้นิยามไว้แล้วโดยไม่ตั้งใจ:
match = 10  
from re import *  # โมดูล re มีฟังก์ชัน match  
print match       # แสดงผลฟังก์ชัน match  

แต่เนื่องจากคุณเป็นคนดี ผมเชื่อว่าคุณจะไม่ทำเช่นนั้น

การคำนวณเลขคณิต (Arithmetic)

Python 2.7 ใช้การหารแบบจำนวนเต็ม (integer division) เป็นค่าเริ่มต้น ดังนั้น $ 5 / 2 = 2 $ แต่บ่อยครั้งเราไม่ต้องการผลลัพธ์ที่เป็นจำนวนเต็ม จึงสามารถนำเข้าโมดูลนี้ได้:

from __future__ import division  

หลังจากนำเข้าแล้ว จะได้ $5 / 2 = 2.5$.
การหารแบบจำนวนเต็ม: $5 // 2 = 2$.

ฟังก์ชัน (Functions)

การนิยามฟังก์ชัน

ฟังก์ชันคือชุดคำสั่งที่มีหน้าที่รับอินพุต 0 ตัวขึ้นไป และส่งคืนเอาต์พุตตามที่กำหนด ใน Python เรานิยามฟังก์ชันโดยใช้ def ชื่อฟังก์ชัน(พารามิเตอร์):

def double(x):  
    """คุณสามารถเขียนคำอธิบายเกี่ยวกับฟังก์ชันได้ที่นี่  
    เช่น ฟังก์ชันนี้จะนำอินพุตมาคูณด้วย 2"""  
    # ส่วนนี้คือตัวฟังก์ชัน อย่าลืมย่อหน้าให้ถูกต้อง  
    return x * 2  

การใช้งานฟังก์ชัน

ใน Python ฟังก์ชันถือเป็น “First-Class Citizen” ซึ่งหมายความว่าเราสามารถกำหนดฟังก์ชันให้กับตัวแปร หรือส่งฟังก์ชันเป็นพารามิเตอร์ไปยังฟังก์ชันอื่นได้:

def apply_to_one(f):  
    """เรียกใช้ฟังก์ชัน f และส่ง 1 เป็นพารามิเตอร์ให้กับฟังก์ชัน"""  
    return f(1)  
my_double = double          # double ชี้ไปยังฟังก์ชันที่นิยามไว้ในหัวข้อก่อนหน้า  
x = apply_to_one(my_double) # x จะมีค่าเท่ากับ 2  

ฟังก์ชันนิรนาม (Lambda Functions)

เรายังสามารถสร้างฟังก์ชันนิรนาม (anonymous function) โดยใช้ lambda ได้อีกด้วย:

y = apply_to_one(lambda x: x + 4)     # มีค่าเท่ากับ 5  

สามารถกำหนด lambda ให้กับตัวแปรอื่นได้ แต่คนส่วนใหญ่แนะนำให้ใช้ def มากกว่า:

another_double = lambda x: 2 * x      # ไม่แนะนำ  
def another_double(x): return 2 * x   # วิธีที่แนะนำ  

เพิ่มเติม:

การส่งผ่านพารามิเตอร์ฟังก์ชัน

พารามิเตอร์ฟังก์ชันสามารถกำหนดค่าเริ่มต้นได้ หากเรียกใช้ฟังก์ชันโดยไม่ระบุพารามิเตอร์ จะใช้ค่าเริ่มต้น แต่ถ้าระบุพารามิเตอร์ จะใช้ค่าที่ส่งผ่านไป:

def my_print(message="my default message"):  
    print message  
my_print("hello")     # แสดงผล "hello"  
my_print()            # แสดงผล "my default message"  

บางครั้งการระบุพารามิเตอร์โดยใช้ชื่อพารามิเตอร์โดยตรงก็มีประโยชน์มากเช่นกัน:

def subtract(a=0, b=0):  
    return a - b  
subtract(10, 5)   # คืนค่า 5  
subtract(0, 5)    # คืนค่า -5  
subtract(b=5)     # เหมือนกับตัวอย่างก่อนหน้า คืนค่า -5  

สตริง (Strings)

สามารถใช้เครื่องหมายคำพูดเดี่ยว (’) หรือคู่ (”) เพื่อสร้างสตริงได้ (เครื่องหมายคำพูดต้องจับคู่กันเสมอ):

single_quoted_string = 'data science'  
double_quoted_string = "data science"  

ใช้เครื่องหมายแบ็กสแลช (\) เพื่อแสดงอักขระพิเศษ (escape character) เช่น:

tab_string = "\t"      # แสดงถึงอักขระแท็บ (tab)  
len(tab_string)        # มีค่าเท่ากับ 1  

เมื่อคุณต้องการใช้เครื่องหมายแบ็กสแลชเอง (เช่น สำหรับพาธใน Windows หรือ Regular Expressions) คุณสามารถกำหนดสตริงแบบดิบ (raw string) โดยใช้ r"" ได้:

not_tab_string = r"\t" # แสดงถึงอักขระ '\' และ 't'  
len(not_tab_string)    # มีค่าเท่ากับ 2  

ใช้เครื่องหมายคำพูดคู่สามตัวเพื่อสร้างสตริงหลายบรรทัด:

multi_line_string = """นี่คือบรรทัดแรก  
นี่คือบรรทัดที่สอง  
นี่คือบรรทัดที่สาม"""  

การจัดการข้อยกเว้น (Exception Handling)

เมื่อโปรแกรมเกิดข้อผิดพลาด Python จะสร้าง ข้อยกเว้น (exception) หากเราไม่จัดการกับมัน โปรแกรมจะหยุดการทำงาน การดักจับข้อยกเว้นสามารถทำได้โดยใช้คำสั่ง try และ except:

try:  
    print 0 / 0  
except ZeroDivisionError:  
    print "ไม่สามารถหารด้วย 0 ได้"  

แม้ว่าในภาษาโปรแกรมอื่น ๆ ข้อยกเว้นจะถูกมองว่าเป็นสิ่งที่ไม่ดี แต่ใน Python การจัดการข้อยกเว้นจำนวนมากจะทำให้โค้ดของคุณกระชับและสะอาดขึ้น

ลิสต์ (Lists)

การสร้างลิสต์

ลิสต์คือชุดข้อมูลที่มีการจัดเรียงลำดับอย่างง่าย และเป็นโครงสร้างข้อมูลพื้นฐานที่สุดใน Python (คล้ายกับ array ในภาษาอื่น แต่ลิสต์มีคุณสมบัติเพิ่มเติมบางอย่าง) การสร้างลิสต์:

integer_list = [1, 2, 3]  
heterogeneous_list = ["string", 0.1, True]  
list_of_lists = [ integer_list, heterogeneous_list, [] ]  
list_length = len(integer_list)   # มีค่าเท่ากับ 3  
list_sum = sum(integer_list)      # มีค่าเท่ากับ 6  

การเข้าถึงค่าในลิสต์

คุณสามารถเข้าถึงค่าในลิสต์โดยใช้อินเด็กซ์ในวงเล็บเหลี่ยม:

x = range(10)       # ลิสต์ x จะได้ค่าเป็น [0, 1, ..., 9]  
zero = x[0]         # มีค่าเท่ากับ 0, ลิสต์จะเริ่มต้นที่อินเด็กซ์ 0  
one = x[1]          # มีค่าเท่ากับ 1  
nine = x[-1]        # มีค่าเท่ากับ 9, คือสมาชิกตัวสุดท้ายในลิสต์  
eight = x[-2]       # มีค่าเท่ากับ 8, คือสมาชิกตัวที่สองจากท้ายในลิสต์  
x[0] = -1           # ตอนนี้ลิสต์ x จะเป็น [-1, 1, 2, 3, ..., 9]  

การแบ่งส่วนลิสต์ (Slicing)

สามารถแบ่งส่วนลิสต์โดยใช้วงเล็บเหลี่ยมได้:

first_three = x[:3]                  # [-1, 1, 2]  
three_to_end = x[3:]                 # [3, 4, ..., 9]  
one_to_four = x[1:5]                 # [1, 2, 3, 4]  
last_three = x[-3:]                  # [7, 8, 9]  
without_first_and_last = x[1:-1]     # [1, 2, ..., 8]  
copy_of_x = x[:]                     # [-1, 1, 2, ..., 9]  

สามารถใช้ in เพื่อตรวจสอบว่ามีสมาชิกอยู่ในลิสต์หรือไม่:

1 in [1, 2, 3]        # True  
0 in [1, 2, 3]        # False  

วิธีการค้นหาสมาชิกแบบนี้มีประสิทธิภาพต่ำ ควรใช้ก็ต่อเมื่อลิสต์มีขนาดเล็กมาก หรือคุณไม่ใส่ใจเรื่องเวลาในการค้นหา

การรวมลิสต์

ใน Python การรวมลิสต์สองรายการเข้าด้วยกันทำได้ง่ายมาก:

x = [1, 2, 3]  
x.extend([4, 5, 6])   # ตอนนี้ x จะเป็น [1,2,3,4,5,6]  

หากคุณไม่ต้องการแก้ไขลิสต์ x เดิม คุณสามารถใช้โอเปอเรเตอร์ ’+’ เพื่อสร้างลิสต์ใหม่ได้:

x = [1, 2, 3]  
y = x + [4, 5, 6]     # ตอนนี้ y จะเป็น [1, 2, 3, 4, 5, 6]; x ไม่มีการเปลี่ยนแปลง  

มักจะใช้วิธีนี้ในการเพิ่มสมาชิกทีละหนึ่งตัวในลิสต์:

x = [1, 2, 3]  
x.append(0)           # ตอนนี้ x จะเป็น [1, 2, 3, 0]  
y = x[-1]             # มีค่าเท่ากับ 0  
z = len(x)            # มีค่าเท่ากับ 4  

การแยกส่วนลิสต์ (Unpacking)

หากคุณทราบจำนวนสมาชิกในลิสต์ การแยกส่วนลิสต์นั้นทำได้ง่ายมาก:

x, y = [1, 2]         # ตอนนี้ x = 1, y = 2  

หากจำนวนสมาชิกทั้งสองข้างของสมการไม่ตรงกัน คุณจะได้รับข้อผิดพลาด ValueError ดังนั้น เราจึงมักใช้เครื่องหมายขีดล่าง (underscore) เพื่อเก็บส่วนที่เหลือของลิสต์:

_, y = [1, 2]         # ตอนนี้ y == 2, โดยไม่สนใจสมาชิกตัวแรก  

ทูเพิล (Tuples)

ลิสต์และทูเพิลมีความคล้ายคลึงกัน ข้อแตกต่างเพียงอย่างเดียวคือ สมาชิกในทูเพิลไม่สามารถเปลี่ยนแปลงได้

การสร้างทูเพิล

สามารถสร้างทูเพิลโดยใช้วงเล็บกลม หรือไม่ใช้วงเล็บเลยก็ได้:

my_tuple = (1, 2)  
other_tuple = 3, 4  
my_list[1] = 3        # ตอนนี้ my_list จะเป็น [1, 3]  
try:  
    my_tuple[1] = 3  
except TypeError:  
    print "ไม่สามารถแก้ไขทูเพิลได้"  

การใช้ทูเพิลทำให้การรับค่าคืนหลายค่าจากฟังก์ชันทำได้สะดวกมาก:

def sum_and_product(x, y):  
    return (x + y),(x * y)  
sp = sum_and_product(2, 3)    # มีค่าเท่ากับ (5, 6)  
s, p = sum_and_product(5, 10) # s = 15, p = 50  

ทูเพิล (และลิสต์) รองรับการกำหนดค่าหลายสมาชิกพร้อมกัน:

x, y = 1, 2       # ตอนนี้ x = 1, y = 2  
x, y = y, x       # การสลับค่าระหว่างสองตัวแปรใน Python; ตอนนี้ x = 2, y = 1  

พจนานุกรม (Dictionaries)

การสร้างพจนานุกรม

โครงสร้างข้อมูลพื้นฐานอีกอย่างใน Python คือพจนานุกรม (dictionary) ซึ่งช่วยให้คุณสามารถเข้าถึงค่า (value) ที่ต้องการได้อย่างรวดเร็วผ่านคีย์ (key) ที่เกี่ยวข้อง:

empty_dict = {}                       # การนิยามพจนานุกรมว่างเปล่าแบบ Pythonic  
empty_dict2 = dict()                  # การนิยามพจนานุกรมว่างเปล่าแบบไม่ค่อย Pythonic  
grades = { "Joel" : 80, "Tim" : 95 }  # การจัดเก็บพจนานุกรม  

การค้นหาข้อมูลในพจนานุกรม

คุณสามารถใช้คีย์ในวงเล็บเหลี่ยมเพื่อค้นหาค่าที่เกี่ยวข้องได้:

joels_grade = grades["Joel"]          # มีค่าเท่ากับ 80  

หากคีย์ที่ต้องการค้นหาไม่อยู่ในพจนานุกรม จะเกิด KeyError:

try:  
    kates_grade = grades["Kate"]  
except KeyError:  
    print "ไม่มีคะแนนสำหรับ Kate!"  

สามารถใช้ in เพื่อตรวจสอบว่าคีย์อยู่ในพจนานุกรมหรือไม่:

joel_has_grade = "Joel" in grades     # True  
kate_has_grade = "Kate" in grades     # False  

พจนานุกรมมีเมธอดที่สามารถคืนค่าเริ่มต้นได้ ซึ่งเมื่อคีย์ที่ต้องการค้นหาไม่อยู่ในพจนานุกรม จะคืนค่าเริ่มต้นที่กำหนดไว้ (แทนที่จะเกิดข้อยกเว้น):

joels_grade = grades.get("Joel", 0)   # มีค่าเท่ากับ 80  
kates_grade = grades.get("Kate", 0)   # มีค่าเท่ากับ 0  
no_ones_grade = grades.get("No One")  # คืนค่าเริ่มต้นเป็น None  

การแก้ไขพจนานุกรม

สามารถใช้วงเล็บเหลี่ยมเพื่อสร้างหรือแก้ไขคู่คีย์-ค่าในพจนานุกรมได้:

grades["Tim"] = 99                    # แทนที่ค่าเดิม  
grades["Kate"] = 100                  # เพิ่มคู่คีย์-ค่าใหม่  
num_students = len(grades)            # มีค่าเท่ากับ 3  

เราจะใช้พจนานุกรมในลักษณะนี้บ่อยครั้งเพื่อแสดงโครงสร้างของข้อมูล:

tweet = {  
    "user" : "joelgrus",  
    "text" : "Data Science is Awesome",  
    "retweet_count" : 100,  
    "hashtags" : ["#data", "#science", "#datascience", "#awesome", "#yolo"]  
}  

นอกจากการค้นหาคีย์เฉพาะแล้ว เรายังสามารถดำเนินการกับคีย์ทั้งหมดได้ดังนี้:

tweet_keys = tweet.keys()             # ได้ลิสต์ของคีย์  
tweet_values = tweet.values()         # ได้ลิสต์ของค่า  
tweet_items = tweet.items()           # ได้ทูเพิล (คีย์, ค่า)  
"user" in tweet_keys                  # คืนค่า True, เป็นการค้นหาด้วย in ในลิสต์ซึ่งมีประสิทธิภาพต่ำกว่า  
"user" in tweet                       # วิธีที่ Pythonic กว่า, เป็นการค้นหาด้วย in ในพจนานุกรมซึ่งมีประสิทธิภาพสูง  
"joelgrus" in tweet_values            # True  

คีย์ในพจนานุกรมจะต้องไม่ซ้ำกัน และลิสต์ไม่สามารถใช้เป็นคีย์ในพจนานุกรมได้ หากคุณต้องการคีย์ที่มีหลายส่วน คุณสามารถใช้ทูเพิล หรือแปลงคีย์ให้เป็นสตริงด้วยวิธีใดวิธีหนึ่ง

พจนานุกรมดีฟอลต์ (defaultdict)

หากคุณกำลังพยายามนับความถี่ของแต่ละคำที่ปรากฏในเอกสาร วิธีที่ชัดเจนคือการสร้างพจนานุกรม โดยให้คำเป็นคีย์และความถี่เป็นค่า จากนั้นวนลูปผ่านเอกสาร หากเจอคำที่เคยปรากฏแล้วก็เพิ่มค่าความถี่ในพจนานุกรมนั้น 1 หากเจอคำที่ไม่เคยปรากฏก็เพิ่มคู่คีย์-ค่าใหม่เข้าไปในพจนานุกรม:

word_counts = {}  
for word in document:  
    if word in word_counts:  
        word_counts[word] += 1  
    else:  
        word_counts[word] = 1  

แน่นอน คุณยังสามารถใช้วิธี ‘ลองดูก่อนแล้วค่อยจัดการ’ เพื่อจัดการกับคีย์ที่หายไปล่วงหน้าได้ดังนี้:

word_counts = {}  
for word in document:  
    try:  
        word_counts[word] += 1  
    except KeyError:  
        word_counts[word] = 1  

วิธีที่สามคือการใช้เมธอด get ซึ่งเมธอดนี้ทำงานได้ดีเยี่ยมในการจัดการกับคีย์ที่หายไป:

word_counts = {}  
for word in document:  
    previous_count = word_counts.get(word, 0)  
    word_counts[word] = previous_count + 1  

พจนานุกรมดีฟอลต์ (defaultdict) ทำงานเหมือนพจนานุกรมทั่วไป ข้อแตกต่างเพียงอย่างเดียวคือ เมื่อคุณพยายามค้นหาคีย์ที่ไม่มีอยู่ในพจนานุกรม พจนานุกรมดีฟอลต์จะใช้คีย์ที่คุณให้มาเพื่อสร้างคู่คีย์-ค่าใหม่โดยอัตโนมัติ ในการใช้พจนานุกรมดีฟอลต์ คุณต้องนำเข้าไลบรารี collections:

from collections import defaultdict  
word_counts = defaultdict(int)        # int() สร้างค่า 0  
for word in document:  
    word_counts[word] += 1  

พจนานุกรมดีฟอลต์ยังใช้งานได้ดีกับลิสต์ พจนานุกรมทั่วไป หรือแม้แต่ฟังก์ชันที่คุณกำหนดเอง:

dd_list = defaultdict(list)           # list() สร้างลิสต์ว่างเปล่า  
dd_list[2].append(1)                  # ตอนนี้ dd_list จะเป็น {2: [1]}  
dd_dict = defaultdict(dict)           # dict() สร้างพจนานุกรมว่างเปล่า  
dd_dict["Joel"]["City"] = "Seattle"   # ตอนนี้ dd_dict จะมีเนื้อหาเป็น { "Joel" : { "City" : "Seattle"}}  
dd_pair = defaultdict(lambda: [0, 0]) # สร้างพจนานุกรมที่มีค่าสำหรับคีย์เป็นลิสต์  
dd_pair[2][1] = 1                     # ตอนนี้ dd_pair จะมีเนื้อหาเป็น {2: [0,1]}  

วิธีนี้มีประโยชน์มาก ทำให้ในอนาคตเมื่อเราต้องการดึงค่าจากพจนานุกรม เราไม่จำเป็นต้องตรวจสอบว่าคีย์นั้นมีอยู่หรือไม่

ตัวนับ (Counter)

Counter สามารถแปลงกลุ่มค่าให้เป็นวัตถุที่มีลักษณะคล้ายพจนานุกรมได้โดยตรง โดยที่คีย์จะเป็นสมาชิกในกลุ่มนั้น และค่าที่เกี่ยวข้องคือจำนวนครั้งที่สมาชิกนั้นปรากฏขึ้น ซึ่งมักใช้บ่อยในการสร้างฮิสโตแกรม:

from collections import Counter  
c = Counter([0, 1, 2, 0]) # c (ประมาณ) เท่ากับ { 0 : 2, 1 : 1, 2 : 1 }  

ด้วยวิธีนี้ เราก็จะมีวิธีที่สะดวกสบายในการนับความถี่ของคำ:

word_counts = Counter(document)  

Counter ยังมีเมธอดที่ใช้บ่อยมากคือ most_common ซึ่งสามารถดึงคำที่มีความถี่สูงสุดและจำนวนครั้งที่ปรากฏได้โดยตรง:

# แสดงผลคำที่มีความถี่สูงสุด 10 อันดับแรกพร้อมจำนวนนับ  
for word, count in word_counts.most_common(10):  
    print word, count  

เซ็ต (Sets)

โครงสร้างข้อมูลอีกประเภทหนึ่งใน Python คือเซ็ต (set) ซึ่งเป็นชุดของสมาชิกที่ไม่ซ้ำกัน
สามารถสร้างเซ็ตและเพิ่มสมาชิกเข้าไปได้ดังนี้:

s = set()  
s.add(1)          # s คือ { 1 }  
s.add(2)          # s คือ { 1, 2 }  
s.add(2)          # s คือ { 1, 2 }  
x = len(s)        # มีค่าเท่ากับ 2  
y = 2 in s        # มีค่าเป็น True  
z = 3 in s        # มีค่าเป็น False  

เหตุผลหลักสองประการในการใช้เซ็ต:

ประการแรก การดำเนินการ in ในเซ็ตมีประสิทธิภาพสูงมาก เมื่อจำนวนสมาชิกในชุดข้อมูลมีขนาดใหญ่มาก การค้นหาสมาชิกในรูปแบบของเซ็ตย่อมเหมาะสมกว่าลิสต์อย่างเห็นได้ชัด:

stopwords_list = ["a","an","at"] + hundreds_of_other_words + ["yet", "you"]  
"zip" in stopwords_list               # ล้มเหลว, ต้องตรวจสอบสมาชิกแต่ละตัว  
stopwords_set = set(stopwords_list)  
"zip" in stopwords_set                # ค้นหาสำเร็จ และรวดเร็วมาก  

ประการที่สอง การใช้เซ็ตเพื่อดึงสมาชิกที่ไม่ซ้ำกันจากชุดข้อมูลทำได้สะดวกมาก:

item_list = [1, 2, 3, 1, 2, 3]  
num_items = len(item_list)            # 6  
item_set = set(item_list)             # {1, 2, 3}  
num_distinct_items = len(item_set)    # 3  
distinct_item_list = list(item_set)   # [1, 2, 3]  

แต่ในความเป็นจริง ความถี่ในการใช้เซ็ตก็ยังไม่สูงเท่าพจนานุกรมและลิสต์

คำสั่งเงื่อนไข

ในภาษาโปรแกรมส่วนใหญ่ คุณสามารถใช้ if เพื่อสร้างเงื่อนไขได้ดังนี้:

if 1 > 2:  
    message = "if only 1 were greater than two…"  
elif 1 > 3:  
    message = "elif stands for 'else if'"  
else:  
    message = "when all else fails use else (if you want to)"  

คุณยังสามารถเขียนคำสั่งเงื่อนไขในบรรทัดเดียวได้ดังนี้ แต่วิธีนี้ไม่ค่อยนิยมใช้:

parity = "even" if x % 2 == 0 else "odd"  

คำสั่งวนซ้ำ

ลูป while

ลูป while ใน Python:

x = 0  
while x < 10:  
    print x, "is less than 10"  
    x += 1  

ลูป for

ที่นิยมใช้มากกว่าคือลูป for-in:

for x in range(10):  
    print x, "is less than 10"  

นิพจน์ตรรกะที่ซับซ้อนขึ้นสามารถใช้คำสั่ง continue และ break ได้:

for x in range(10):  
    if x == 3:  
        continue          # ข้ามไปรอบการทำงานถัดไปทันที  
    if x == 5:  
        break             # ออกจากลูปทั้งหมด  
    print x  

ผลลัพธ์ที่ได้คือ 0, 1, 2 และ 4

ค่าความจริง (Truthiness)

ตัวแปรบูลีน (Booleans) ใน Python มีการใช้งานคล้ายกับภาษาอื่น ๆ ข้อแตกต่างเพียงอย่างเดียวคือตัวอักษรแรกต้องเป็นตัวพิมพ์ใหญ่เสมอ:

one_is_less_than_two = 1 < 2      # เป็น True  
true_equals_false = True == False # เป็น False  

Python ใช้ None เพื่อแสดงว่าไม่มีค่า คล้ายกับ null ในภาษาอื่น ๆ:

x = None  
print x == None        # แสดงผล True, แต่ไม่ค่อยสวยงาม  
print x is None        # แสดงผล True, ดูดีกว่า  

Python อนุญาตให้คุณใช้ค่าอื่น ๆ แทนค่าบูลีนได้ โดยค่าต่อไปนี้ทั้งหมดถือว่าเทียบเท่ากับ False:

ในทำนองเดียวกัน ก็มีค่าที่เทียบเท่ากับ True อีกมากมาย ซึ่งทำให้คุณสะดวกในการตรวจสอบลิสต์ว่าง สตริงว่าง หรือพจนานุกรมว่าง เป็นต้น

แน่นอนว่า หากคุณไม่สามารถคาดการณ์ผลลัพธ์ได้ อาจเกิดข้อผิดพลาดระหว่างการใช้งาน:

s = some_function_that_returns_a_string()  
if s:  
    first_char = s[0]  
else:  
    first_char = ""  

วิธีที่ง่ายกว่าและให้ผลลัพธ์เดียวกันกับวิธีข้างต้นคือ:

first_char = s and s[0]  

หากค่าแรกเป็นจริง จะคืนค่าที่สอง มิฉะนั้นจะคืนค่าแรก

ในทำนองเดียวกัน หาก x อาจเป็นตัวเลขหรือเป็นค่าว่าง วิธีนี้จะช่วยให้ได้ x ที่เป็นตัวเลขอย่างแน่นอน:

safe_x = x or 0  

ใน Python ยังมีฟังก์ชัน all ซึ่งจะคืนค่า True เมื่อทุกสมาชิกเป็น True และฟังก์ชัน any ซึ่งจะคืนค่า True หากมีสมาชิกอย่างน้อยหนึ่งตัวเป็น True ตัวอย่างเช่น สำหรับลิสต์ที่ทุกสมาชิกเป็น ‘จริง’ ฟังก์ชัน all จะคืนค่า True มิฉะนั้นจะคืนค่า False:

all([True, 1, { 3 }])       # True  
all([True, 1, {}])          # False, เพราะ {} เทียบเท่ากับ 'False'  
any([True, 1, {}])          # True  
all([])                     # True, เพราะไม่มีสมาชิกใดที่เทียบเท่ากับ 'False'  
any([])                     # False, เพราะไม่มีสมาชิกใดที่เทียบเท่ากับ 'True'  

อ่านเพิ่มเติม:
ไวยากรณ์ Python ที่ใช้บ่อยในวิทยาการข้อมูล (ขั้นสูง)