Monday, September 13, 2010

Python Programming

Reverse complement สาย DNA ด้วย Python (ภาค 3)

ประพัฒน์ สุริยผล


มาถึงภาคสามของโปรแกรม reverse complement ครับ ครั้งนี้เราเหลืออีกหนึ่งฟังก์ชันที่หน้าตายังไม่เป็น Python สักเท่าไหร่ ก็คือฟังก์ชัน complement ดังด้านล่าง

def complement(dna):

____result = ''

____for base in dna:

________if base == 'a':

____________result = result + 't'

________elif base == 't':

____________result = result + 'a'

________elif base == 'g':

____________result = result + 'c'

________elif base == 'c':

____________result = result + 'g'

________else:

____________result = result + 'n'

____return result


Dictionary


ขอให้เรามองในส่วนของ if และ elif ก่อนนะครับ จะเห็นว่าดูยาวและซ้ำซ้อน ถ้าหากดูให้ดีเงื่อนไขในการเปรียบเทียบคล้ายกันมาก สิ่งที่ทำคือตรวจสอบว่าตัวแปร base มีค่าเป็นอะไร แล้วนำ nucleotide ที่ complementary กับเบสตัวนั้นไปต่อท้ายตัวแปร result การทำงานในลักษณะนี้ เหมาะกับรูปแบบ dictionary ของ Python มาก


เรามาดูกันสักนิดว่า dictionary ของ Python ทำงานอย่างไร เริ่มต้นด้วยการประกาศว่าตัวแปรนี้คือ dictionary ดังนี้

dic = {}

ให้สังเกตว่าการประกาศตัวแปร dictionary จะคล้ายกับการประกาศตัวแปร list แต่ว่าใช้สัญลักษณ์ {} แทนที่จะเป็น [] แบบ list


การใช้การตัวแปร dictionary ทำได้โดยกำหนดให้ข้อมูลสองส่วนคือ key กับ value เหมือนกับเวลาเราเปิด dictionary เราก็ต้องไปหาคำศัพท์เพื่อที่จะทราบคำแปล คำศัพท์ที่เราจะใช้ค้นหา นั่นคือ key ส่วนคำแปลที่เราต้องการทราบก็คือ value นั่นเอง มาดูตัวอย่างกัน

>>> dic = {}

>>> dic['one']=1

>>> dic['two']=2

>>> dic['three']=3


เรากำหนดค่าคำศัพท์หรือ key เอาไว้สามค่า โดย key เป็นคำศัพท์ภาษาอังกฤษ และคำแปลคือตัวเลขที่เป็นค่าของคำศัพท์นั้น ให่้สังเกตรูปแบบการกำหนดค่า dictionary ว่า ตัว key จะอยู่หลังชื่อตัวแปรโดยมีสัญลักษณ์ [] คร่อม (ไม่ใช่ {}) และตัว value จะอยู่หลังเครื่องหมาย = อาจจะดูยุ่งยากสักนิด แต่ว่าใช้ไปไม่นานก็จะคุ้นเคย และกลายเป็นเรื่องธรรมชาติไป


จากนั้นเราสามารถนำตัวแปร dictionary มาใช้ได้ ดังนี้ครับ


>>> dic['one']

1

>>> dic['two']

2


เราสามารถเรียกคำแปรมาใช้ได้ในรูปแบบที่คล้ายกับการกำหนดค่า


หากเรากำหนดค่าใหม่ให้กับ key ที่มีอยู่แล้ว ค่านั้นจะไปแทนที่ค่าเก่า แต่ถ้าหาก key นั้นยังไม่เคยมีอยู่ key และ value อันใหม่ก็จะถูกเพิ่มเข้าไป ลองดูตัวอย่างนะครับ ผมจะแทนที่ค่าเก่าของ key 'two' และจะเพิ่ม key 'four' เข้าไป


>>> dic['two']=20

>>> dic['four']=4


แล้วลองเรียกมาใช้งานดู


>>> dic['two']

20

>>> dic['two']+dic['four']

24


ค่า value ของ dictionary นั้น สามารถเป็นอะไรก็ได้ จะเป็นตัวเลข ตัวอักษร หรืออะไรก็ตามที่เราสามารถใส่ลงไปในตัวแปร แต่สำหรับค่าที่ใช้เป็น key นั้นจะมีข้อจำกัดอยู่ว่า ค่านั้นจะต้องเปลี่ยนแปลงไม่ได้ (immutable) ซึ่งในทางปฏิบัติจะแปลได้ว่า เราไม่สามารถใช้ list เป็น key ของ dictionary ได้


ลองมาดูตัวอย่างประกอบความเข้าใจนะครับ


>>> dic = {}

>>> dic[1] = 10

>>> dic[1]

10

>>> dic['a'] = 'ant'

>>> dic['a']

'ant'

>>> dic[[1,2]] = 10

Traceback (most recent call last):

File "", line 1, in

TypeError: unhashable type: 'list'


จะเห็นว่า เราใช้ key เป็นตัวเลขก็ได้ ตัวอักษรก็ได้ แต่ใช้ list ไม่ได้ ตัวอย่างสุดท้าย เราพยายามจะใส่ list [1,2] เพื่อเป็น key แต่ Python ไม่ยอม


เหตุผลหลักคือถ้าเรายอมให้ list เป็น key ได้ dictionary ก็จะมีโอกาสเพี้ยน และทำงานผิดพลาดโดยที่เราไม่รู้ตัวได้


List และเรื่องที่เรามักจะทำผิดพลาด


ลองมาดูตัวอย่างว่า list อาจจะทำให้เราสับสนได้อย่างไรนะครับ


>>> a = [1,2]

>>> b = [3,4]

>>> c = [a, b]

>>> c

[[1, 2], [3, 4]]

>>> a = [5,6]

>>> c

[[1, 2], [3, 4]]

>>> a

[5, 6]


ตัวอย่างนี้ ระบบทำงานได้อย่างที่เราต้องการ เราสร้าง list ขึ้นมา 2 ตัว คือ a และ b จากนั้น เราสร้างตัวแปร c ซึ่งเป็น list ของตัวแปร a และ b


เมื่อเราดูว่าตัวแปร c มีอะไรอยู่ข้างในบ้าง จะพบว่ามีค่าเป็น [[1, 2], [3, 4]] ตามที่เราคาดไว้

เมื่อเราเปลี่ยนตัวแปร a ให้เป็น list [5, 6] เราก็ไม่คาดว่าตัวแปร c จะมีการเปลี่ยนแปลงอะไร เพราะเราได้กำหนดค่าให้ c เท่ากับ a และ b ไปแล้ว และเมื่อเราเปลี่ยนแปลง a เราไม่ได้ไปกำหนดค่าของ c ใหม่ ซึ่งจากที่เราลองพิมพ์ค่าออกมาดูหลังจากเปลี่ยนแปลงค่าของ a เราก็พบว่าเป็นเช่นนั้น ตัวแปร c ยังคงค่าเดิมอยู่ และตัวแปร a ก็เปลี่ยนค่าไปตามที่เราต้องการ


คราวนี้มาลองดูตัวอย่างข้างล่างกัน


>>> a = [1,2]

>>> b = [3,4]

>>> c = [a, b]

>>> c

[[1, 2], [3, 4]]

>>> a[0] = 5

>>> c

[[5, 2], [3, 4]]

>>> a

[5, 2]


เกิดอะไรขึ้น!!! เมื่อเราเปลี่ยนค่าแรกของ list ในตัวแปร a ค่านั้นไปเปลี่ยนอยู่ในตัวแปร c ด้วย ดังจะเห็นได้ว่า เมื่อเรากำหนด a[0] = 5 แล้วดูค่าในตัวแปร c ค่าเดิมที่เคยเป็นเลข 1 ก็พลอยเปลี่ยนเป็นเลข 5 ด้วย คำอธิบายจะค่อนข้างยุ่งยาก ผมขอยกยอดไปอธิบายในครั้งต่อๆ ไป เมื่อผมจะเล่าเรื่องการจัดการหน่วยความจำกับตัวแปรนะครับ


Tuple = List ที่เปลี่ยนแปลงไม่ได้


เรามาดูวิธีแก้ปัญหาข้างต้นก่อนนะครับ สิ่งที่เราต้องการคือเราไม่ต้องการให้มีการแก้ไขค่าใน list ถ้าจะแก้ไข ก็คือต้องเปลี่ยนใหม่หมดทั้ง list เลย ซึ่ง python มีคำตอบให้แล้วคือ tuple ดังตัวอย่างครับ


>>> a = (1,2)

>>> b = (3,4)

>>> c = (a,b)

>>> c

((1, 2), (3, 4))

>>> a

(1, 2)

>>> a = (5,6)

>>> c

((1, 2), (3, 4))

>>> a

(5, 6)


จากตัวอย่างนี้ จะเห็นว่า เราสามารถใช้ tuple แทนตัวแปร list ได้เลย การสร้าง tuple ก็เขียนเหมือน list เพียงแต่เปลี่ยนสัญลักษณ์จาก [] เป็น () เท่านั้น


>>> a = (1,2)

>>> b = (3,4)

>>> c = (a,b)

>>> c

((1, 2), (3, 4))

>>> a[0] = 5

Traceback (most recent call last):

File "", line 1, in

TypeError: 'tuple' object does not support item assignment


จากตัวอย่างนี้ จะเห็นว่า python ไม่อนุญาตให้เราแก้ไขค่าในตัวแปร tuple เพราะฉะนั้นจะไม่เกิดปัญหาที่เราเจอแบบ list ข้างต้น เพราะ python ไม่ยอมให้เราทำ


ย้อนกลับมาที่ dictionary นะครับ ที่เรากล่าวมายืดยาว ก็เพื่อจะบอกว่า เราไม่สามารถใช้ list เป็น key ของ dictionary ได้ แต่เราสามารถใช้ tuple แทนได้ครับ ดังตัวอย่าง


>>> dic[(1, 2)] = 10

>>> dic[(1, 2)]

10


อันที่จริง เรื่องนี้ออกจะนอกเรื่องไปนิด เพราะครั้งนี้ เราไม่จำเป็นต้องใช้ tuple เป็น key เราใช้เพียงตัวอักษรเท่านั้น แต่อยากจะเพิ่มเติมเพื่อให้ข้อมูลครบถ้วนมากขึ้น


การ declare dictionary พร้อมค่าเริ่มต้น


โดยปกติ เราจะสร้างตัวแปร dictionary เปล่าๆ แล้วค่อยใส่ค่า key และ value ในภายหลัง แต่เราสามารถใส่ค่าเริ่มต้นตอนสร้างตัวแปรได้เลย ดังตัวอย่าง


>>> complementary_dict = {'a':'t', 't':'a','g':'c','c':'g'}

>>> complementary_dict['a']

't'

>>> complementary_dict['g']

'c'

เราทำได้โดยใส่ค่า key และ value แยกกันด้วยเครื่องหมายโคลอน (:) และแยกแต่ละชุดด้วยเครื่องหมายคอมม่า (,)


มาถึงจุดนี้ เราก็พร้อมที่จะเปลี่ยนจากการใช้ if เป็นใช้ dictionary แทนแล้ว


function complement ก็จะมีหน้าตาเป็นอย่างนี้

def complement(dna):

____complementary_dict = {'a':'t', 't':'a', 'g':'c', 'c':'g'}

____result = ''

____for base in dna:

________result = result + complementary_dict[base]

____return result

เราจะจบไว้ที่ตรงนี้ก่อนนะครับ อันที่จริง function complement ยังไปตามสไตล์ python ได้ต่ออีก ซึ่งเราจะมาว่ากันต่อครั้งหน้่าครับ


ครั้งนี้เราได้เรียนรู้เกี่ยวกับ dictionary และเพิ่มเติมในส่วนของ list อีกพอสมควร ผมแนะนำให้หาข้อมูลเพิ่มใน help manual ที่มาพร้อมกับ python และหาข้อมูลเพิ่มเติมจาก Internet ครับ จะได้ความรู้มากขึ้น แล้วพบกันฉบับหน้าครับ

No comments:

Post a Comment