เฉลยการบ้านสัปดาห์ที่แล้ว

ถ้าเรามีเวลาออมเงิน 20, 30, 40 ปี

  1. ถ้าผลตอบแทน = 0.08 (8%) ต่อปี และเราออมปีละ 100,000 บาท เราจะมีเงินตอนท้ายเท่าไร
  2. ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 และออมเงินปีละ 120,000 เราต้องหาผลตอบแทนเท่าไร
  3. ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 และได้ผลตอบแทนปีละ 10% เราต้องออมเงินปีละเท่าไร

ก่อนอื่นเราเอาฟังก์ชั่น solve/bisection4, future_value, total_future_value ที่เคยกำหนดไว้ในอดีตมาใช้สำหรับปัญหาเหล่านี้:

In [1]:
def bisection4(f,xmin, xmax):
    "พยายามหาค่า x ที่ทำให้ f(x)==0, xmin และ xmax คือช่วงที่เดาว่าคำตอบอยู่ในนั้น"
    
    tolerance = 1e-6  #ตั้งค่า tolerance ไว้ให้หยุดทำงาน
                      #จะหยุดทำงานเมื่อ xmin ห่างจาก xmax น้อยกว่า tolerance
    
    if xmin > xmax:   # จัดการให้ xmin น้อยกว่า xmax เสมอ
        xmin, xmax = xmax, xmin
    
    if f(xmin)*f(xmax) > 0:
        print("Bad xmin, xmax") #ถ้าฟังก์ชั่น f ไม่เปลี่ยนเครื่องหมายจากบวกไปลบหรือลบไปบวก
                              #ระหว่าง xmin และ xmax ก็ควรไปเดาใหม่ว่า xmin, xmax คืออะไร
        return None
    
    
    while xmax-xmin > tolerance: # ทำตรงนี้วนๆไปตราบใดท่ี xmin และ xmax ยังห่างกันกว่า tolerance
        
        #print(f"xmin, xmax = {xmin}, {xmax}\t f(xmin)*f(xmax) = {f(xmin)*f(xmax):.5f}")
        
        if f(xmin) == 0:
            return xmin
        
        if f(xmax) == 0:
            return xmax

        xmid = (xmin + xmax)/2    #หาจุดกลางระหว่าง xmin และ xmax
        if f(xmin)*f(xmid) < 0:   #ถ้าฟังก์ชั่นเปลี่ยนเครื่องหมายระหว่าง xmin กับจุดกลาง ก็ไปหาต่อในช่วงนี้
            xmin, xmax = xmin, xmid
        else:                     #ไม่งั้นก็หาต่อในช่วงจุดกลางถึง xmax
            xmin, xmax = xmid, xmax
            
    slope = (f(xmax)-f(xmin))/(xmax-xmin) 
    x = xmin + (0-f(xmin))/slope  # คำตอบที่ได้จะเทียบบัญญัติไตรยางค์ระหว่างจุด (xmin, f(xmin)) และ จุด (xmax, f(xmax))
    
    return x

solve = bisection4

def future_value(present_value, interest, periods):
    """คำนวณมูลค่าเงินในอนาคต (future value) 
    ถ้าเรารู้ค่าเงินปัจจุบัน (present value), 
    อัตราผลตอบแทนต่อปีหรือต่อเดือน (interest), 
    และจำนวนปีหรือเดือน (periods) ที่ออมเงินไว้ให้งอกเงย
    """
    return present_value * (1+interest) ** periods

def total_future_value(deposit, interest, n_periods):
    """คำนวณค่าเงินในอนาคตทั้งหมด ถ้าออมเงินเท่าๆกันทุกปี = deposit
    ด้วยผลตอบแทนต่อปี = interest (เช่น 5% = 0.05)
    เป็นจำนวนปีทั้งหมด = n_periods
    """
    sum = 0.0
    for i in range(1,n_periods+1):
        sum = sum + future_value(deposit, interest, i)
    return sum
In [2]:
# ข้อ 1
# ถ้าผลตอบแทน = 0.08 (8%) ต่อปี และเราออมปีละ 100,000 บาท เราจะมีเงินตอนท้ายเท่าไร
# สังเกต :,.0f ใน f-string (, แปลว่าใช้คอมม่ากั้นตัวเลขทุกสามหลัก และ .0 แปลว่าไม่แสดงทศนิยม)

print(f"20 years: {total_future_value(100_000, 0.08, 20):,.0f} บาท")
print(f"30 years: {total_future_value(100_000, 0.08, 30):,.0f} บาท")
print(f"40 years: {total_future_value(100_000, 0.08, 40):,.0f} บาท")
20 years: 4,942,292 บาท
30 years: 12,234,587 บาท
40 years: 27,978,104 บาท
In [3]:
# เราอาจจะให้คอมพิวเตอร์ทำงานซ้ำๆให้เราแทนที่เราจะทำเองด้วยมือ:
for y in (20,30,40):
    print(f"{y} years: {total_future_value(100_000, 0.08, y):,.0f} บาท")
20 years: 4,942,292 บาท
30 years: 12,234,587 บาท
40 years: 27,978,104 บาท
In [4]:
# ข้อ 2
# ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 บาท และออมเงินปีละ 120,000 เราต้องหาผลตอบแทนเท่าไร
# สำหรับ 20 ปี เรากำหนดฟังก์ชั่น fr20 ที่จะรับตัวแปรอัตราผลตอบแทน r 
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 20 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fr20, 0, 0.5) โดยเดาว่าคำตอบ r อยู่ระหว่าง 0 ถึง 0.5
# เพื่อหาค่า r ที่ทำให้ fr20(r) มีค่าเท่ากับ 0
# จะได้ r เท่ากับ 0.23 หรือ 23%

def fr20(r):
    return 40_000_000 - total_future_value(120000, r, 20)
solve(fr20, 0, 0.5)
Out[4]:
0.23063254839934963
In [5]:
# ข้อ 2
# สำหรับ 30 ปี เรากำหนดฟังก์ชั่น fr30 ที่จะรับตัวแปรอัตราผลตอบแทน r 
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 30 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fr30, 0, 0.5) โดยเดาว่าคำตอบ r อยู่ระหว่าง 0 ถึง 0.5
# เพื่อหาค่า r ที่ทำให้ fr30(r) มีค่าเท่ากับ 0
# จะได้ r เท่ากับ 0.13 หรือ 13%

def fr30(r):
    return 40_000_000 - total_future_value(120000, r, 30)
solve(fr30, 0, 0.5)
Out[5]:
0.1302971150054346
In [6]:
# ข้อ 2
# สำหรับ 40 ปี เรากำหนดฟังก์ชั่น fr40 ที่จะรับตัวแปรอัตราผลตอบแทน r 
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 40 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fr40, 0, 0.5) โดยเดาว่าคำตอบ r อยู่ระหว่าง 0 ถึง 0.5
# เพื่อหาค่า r ที่ทำให้ fr40(r) มีค่าเท่ากับ 0
# จะได้ r เท่ากับ 0.086 หรือ 8.6%

def fr40(r):
    return 40_000_000 - total_future_value(120000, r, 40)
solve(fr40, 0, 0.5)
Out[6]:
0.08639077047155595
In [7]:
# เราอาจจะสั่งให้คอมพิวเตอร์ทำงานซ้ำๆแทนเราได้:

print("ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 บาท และออมเงินปีละ 120,000")
for y in (20, 30, 40):
    def find_r(r):
        return 40_000_000 - total_future_value(120_000, r, y)
    r = solve(find_r,0, 0.5)
    print(f"สำหรับ {y} ปี เราต้องการอัตราผลตอบแทนต่อปี =  {r}\
    หรือประมาณ {100*r:.1f}%")
ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 บาท และออมเงินปีละ 120,000
สำหรับ 20 ปี เราต้องการอัตราผลตอบแทนต่อปี =  0.23063254839934963    หรือประมาณ 23.1%
สำหรับ 30 ปี เราต้องการอัตราผลตอบแทนต่อปี =  0.1302971150054346    หรือประมาณ 13.0%
สำหรับ 40 ปี เราต้องการอัตราผลตอบแทนต่อปี =  0.08639077047155595    หรือประมาณ 8.6%
In [8]:
# ข้อ 3
# ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 และได้ผลตอบแทนปีละ 10% เราต้องออมเงินปีละเท่าไร
# สำหรับ 20 ปี รากำหนดฟังก์ชั่น fd20 ที่จะรับตัวแปร deposit หรือเงินฝากประจำทุกปี 
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 20 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fd20,10_000, 1_000_000) โดยเดาว่าต้องฝากระหว่าง 10,000 ถึง 1,000,000 บาท
# เพื่อหาค่า deposite ที่ทำให้ fd20(deposit) มีค่าเท่ากับ 0
# จะได้ deposit เท่ากับ 634,895 บาท

def fd20(deposit):
    return 40_000_000 - total_future_value(deposit, 0.1, 20)
solve(fd20,10_000, 1_000_000)
Out[8]:
634895.4462743916
In [9]:
# ข้อ 3
# สำหรับ 30 ปี รากำหนดฟังก์ชั่น fd30 ที่จะรับตัวแปร deposit หรือเงินฝากประจำทุกปี 
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 30 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fd30,10_000, 1_000_000) โดยเดาว่าต้องฝากระหว่าง 10,000 ถึง 1,000,000 บาท
# เพื่อหาค่า deposite ที่ทำให้ fd30(deposit) มีค่าเท่ากับ 0
# จะได้ deposit เท่ากับ 221,064 บาท

def fd30(deposit):
    return 40_000_000 - total_future_value(deposit, 0.1, 30)
solve(fd30,10_000, 1_000_000)
Out[9]:
221063.57282305096
In [10]:
# ข้อ 3
# สำหรับ 40 ปี รากำหนดฟังก์ชั่น fd40 ที่จะรับตัวแปร deposit หรือเงินฝากประจำทุกปี 
# และจะให้ค่าเท่ากับ 0 ถ้าเงินรวมปีที่ 40 เท่ากับ 40,000,000 ล้านบาท
# ใช้ solve(fd40,10_000, 1_000_000) โดยเดาว่าต้องฝากระหว่าง 10,000 ถึง 1,000,000 บาท
# เพื่อหาค่า deposite ที่ทำให้ fd40(deposit) มีค่าเท่ากับ 0
# จะได้ deposit เท่ากับ 82,161 บาท
def fd40(deposit):
    return 40_000_000 - total_future_value(deposit, 0.1, 40)
solve(fd40,10_000, 1_000_000)
Out[10]:
82160.52415889046
In [11]:
# เราอาจจะสั่งให้คอมพิวเตอร์ทำงานซ้ำๆแทนเราได้:

print("ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 และได้ผลตอบแทนปีละ 10%")
for y in (20,30,40):
    def find_deposit(deposit):
        return 40_000_000 - total_future_value(deposit, 0.1, y)
    d = solve(find_deposit, 10_000, 1_000_000)
    print(f"ถ้าออม {y} ปี ต้องออมปีละ {d:,.0f} บาท")
ถ้าเราต้องการเงินตอนท้ายเท่ากับ 40,000,000 และได้ผลตอบแทนปีละ 10%
ถ้าออม 20 ปี ต้องออมปีละ 634,895 บาท
ถ้าออม 30 ปี ต้องออมปีละ 221,064 บาท
ถ้าออม 40 ปี ต้องออมปีละ 82,161 บาท

List Comprehension

อ่านเรื่องนี้ที่ Comprehending Python’s Comprehensions หรือดูที่ส่วน "การสร้างลิสต์จาก for" ที่หน้านี้

ลองใช้ list comprehension ดูเช่น

In [12]:
# ลิสต์ 0 ถึง 9
[k for k in range(0,10)]
Out[12]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [13]:
# ค่ายกกำลังสองของเลขตั้งแต่ 0 ถึง 10
[k**2 for k in range(0,11)]
Out[13]:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
In [14]:
# คู่ลำดับ (x, x**2) สำหรับ x ตั้งแต่ 0 ถึง 10
[(x, x**2) for x in range(0,11)]
Out[14]:
[(0, 0),
 (1, 1),
 (2, 4),
 (3, 9),
 (4, 16),
 (5, 25),
 (6, 36),
 (7, 49),
 (8, 64),
 (9, 81),
 (10, 100)]
In [15]:
# ค่ายกกำลังสองของเลขตั้งแต่ 0 ถึง 10 แต่เลือกเฉพาะที่ยกกำลังสองแล้วหาร 3 ลงตัว
[k**2 for k in range(0,11) if k**2 % 3 == 0]
Out[15]:
[0, 9, 36, 81]
In [16]:
# คู่ลำดับ (k, k**2) ของเลข k ตั้งแต่ 0 ถึง 10 แต่เลือกเฉพาะที่ยกกำลังสองแล้วหาร 3 ลงตัว
[(k,k**2) for k in range(0,11) if k**2 % 3 == 0]
Out[16]:
[(0, 0), (3, 9), (6, 36), (9, 81)]
In [17]:
# for ได้หลายครั้ง
[(i,j,k) for i in (0,1) for j in (0,1) for k in (0,1)]
Out[17]:
[(0, 0, 0),
 (0, 0, 1),
 (0, 1, 0),
 (0, 1, 1),
 (1, 0, 0),
 (1, 0, 1),
 (1, 1, 0),
 (1, 1, 1)]
In [18]:
# โยนเหรียญหัวก้อย (H, T) สามครั้งจะออกได้แบบไหนบ้าง
[(i, j, k) for i in ("H","T") for j in ("H","T") for k in ("H","T")]
Out[18]:
[('H', 'H', 'H'),
 ('H', 'H', 'T'),
 ('H', 'T', 'H'),
 ('H', 'T', 'T'),
 ('T', 'H', 'H'),
 ('T', 'H', 'T'),
 ('T', 'T', 'H'),
 ('T', 'T', 'T')]
In [19]:
# สร้างลิสต์ของเลขทศนิยม
[0.5*(k-5) for k in range(0,11)]
Out[19]:
[-2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5]
In [20]:
# สร้างลิสต์ของเลขทศนิยม ไม่ให้มี 0 อยู่ในลิสต์
[0.5*k-0.25 for k in range(-5,7)]
Out[20]:
[-2.75, -2.25, -1.75, -1.25, -0.75, -0.25, 0.25, 0.75, 1.25, 1.75, 2.25, 2.75]
In [21]:
# สร้างลิสต์ของเลขทศนิยม
[0.5*k for k in range(-5,6)]
Out[21]:
[-2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5]

เริ่มหัดใช้ Pyplot จาก Matplotlib เพื่อดูหน้าตากราฟต่างๆ

ให้พิมพ์ตามตัวอย่างใน Pyplot Tutorial แต่ให้ใส่ %matplotlib inline ไว้ใน Jupyter Notebook ด้วยเพื่อแสดงกราฟต่างๆใน notebook

In [22]:
%matplotlib inline
import matplotlib.pyplot as plt
In [23]:
# ข้อมูลที่เราจะวาดจะอยู่ในลิสต์สองอันที่ป้อนเข้าไปใน plt.plot(...)
# ลิสต์แรกคือแกนนอน ลิสต์ที่สองคือแกนตั้ง

plt.plot([1,2,3,4], [1, 8, 27, 64])
plt.ylabel('x^3')
plt.xlabel('x')
plt.show()
In [24]:
#เราสามารถใช้รูปแบบของ LaTeX เพื่อแสดงผลที่แกนให้ดูสวยงาม
#เนื่องจากคำสั่ง LaTeX จะมี \ เยอะ ไพธอนจะตีความ \ ว่าตามด้วยอะไรเป็นตัวอักษรต่างๆ
#เช่น \n จะถูกตีความว่าเป็นบรรทัดใหม่ (newline)
#ถ้าจะบอกให้ไพธอนอย่าพึ่งตีความอะไรให้ใช้ raw string ที่หน้าตาแบบ r"..."
#อ่านเรื่อง raw string ได้ที่ https://knowledge.kitchen/Raw_strings_in_Python

plt.plot([1,2,3,4],[1,4,9,16])
plt.ylabel(r'$y=x^2$')
plt.xlabel(r'$x$')
plt.show()
In [25]:
# เพิ่มจำนวนจุดให้กราฟดูสวยขึ้น

plt.plot([0, 0.5, 1, 1.5,2, 2.5,3,3.5,4],[0, 0.25, 1, 2.25, 4, 6.25, 9, 12.25, 16])
plt.ylabel(r'$y=x^2$')
plt.xlabel(r'$x$')
plt.show()
In [26]:
# ใช้ list comprehension สร้างข้อมูลสำหรับ x และ y

x = [0.1*k for k in range(0, 41)]
y = [k**2 for k in x]
plt.plot(x, y)
plt.ylabel(r'$y=x^2$')
plt.xlabel(r'$x$')
plt.grid(True)
plt.show()
In [27]:
# ถ้าความสัมพันธ์ของ y และ x ดูยุ่งยาก ให้กำหนดฟังก์ชั่นมาช่วย

x = [0.1*k for k in range(-100,100)]
def f(x):
    return x**3 - 2*x**2 + 10*x +5
y = [f(k) for k in x]

plt.plot(x, y)
plt.ylabel(r'$y=x^3- 2 x^2 + 10x + 5$')
plt.xlabel(r'$x$')
plt.grid(True)
plt.show()
In [28]:
# ซูมเข้าไปดูแถวๆ x = -2 ถึง 2
# เห็นว่ากราฟตัดแกน x ระหว่าง x = -1 และ 0

x = [0.1*k for k in range(-20,20)]
def f(x):
    return x**3 -2*x**2 + 10*x +5
y = [f(k) for k in x]

plt.plot(x, y)
plt.ylabel(r'$y=x^3-2 x^2 + 10x + 5$')
plt.xlabel(r'$x$')
plt.grid(True)
plt.show()
In [29]:
# ใช้ solve หาคำตอบว่าตัดแกน x ที่ไหน
# เดาว่า x อยู่ระหว่าง -1 และ 0
# ได้คำตอบประมาณ -0.45

solve(f,-1,0)
Out[29]:
-0.4503122847689626
In [30]:
# ลองวาดกราฟ y(x) = 1/x 
# ถ้า x เป็น 0 จะเกิดการหารด้วย 0 ขึ้น

x = [0.01*k for k in range(-200,200)]
def f(x):
    return 1/x
y = [f(k) for k in x]

plt.plot(x, y)
plt.ylabel(r'$y=\frac{1}{x}$')
plt.xlabel(r'$x$')
plt.grid(True)
plt.show()
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-30-bb01fceb637d> in <module>
      5 def f(x):
      6     return 1/x
----> 7 y = [f(k) for k in x]
      8 
      9 plt.plot(x, y)

<ipython-input-30-bb01fceb637d> in <listcomp>(.0)
      5 def f(x):
      6     return 1/x
----> 7 y = [f(k) for k in x]
      8 
      9 plt.plot(x, y)

<ipython-input-30-bb01fceb637d> in f(x)
      4 x = [0.01*k for k in range(-200,200)]
      5 def f(x):
----> 6     return 1/x
      7 y = [f(k) for k in x]
      8 

ZeroDivisionError: float division by zero
In [31]:
# ลองวาดกราฟ y(x) = 1/x 
# ถ้า x เป็น 0 จะเกิดการหารด้วย 0 ขึ้น
# แก้ไขโดยสร้างลิสต์ x ที่ไม่มี 0 อยู่ในนั้น
#  บรรทัด x = [0.01*k + 0.005 for k in range(-200,200)]
# เทียบกับ x = [0.01*k for k in range(-200,200)] ในตัวอย่างข้างบน

x = [0.01*k + 0.005 for k in range(-200,200)]
def f(x):
    return 1/x
y = [f(k) for k in x]

plt.plot(x, y)
plt.ylabel(r'$y=\frac{1}{x}$')
plt.xlabel(r'$x$')
plt.grid(True)
plt.show()
In [ ]: