---
title: "Machine Learning เรียนรู้อะไรจากข้อมูล"
description: "เริ่มจากแถวข้อมูล Feature และ Target แยกการพยากรณ์ตัวเลข การจำแนกกลุ่ม และการค้นหารูปแบบ พร้อมตัวอย่าง Python ที่ระบุเวลารู้ข้อมูล"
---

# Machine Learning เรียนรู้อะไรจากข้อมูล

<p class="lead">ถ้ามีตารางผลตอบแทนย้อนหลัง เราอาจอยากรู้ว่าเดือนหน้าจะได้ผลตอบแทนเท่าไร เดือนหน้าจะเป็นบวกหรือไม่ หรือสินทรัพย์ใดเคลื่อนไหวคล้ายกัน ทั้งสามคำถามใช้ข้อมูลการลงทุนได้เหมือนกัน แต่ต้องสร้างคำตอบและวัดความสำเร็จต่างกัน เราจะเริ่มจากตารางเล็ก ๆ เพื่อแยกคำถามเหล่านี้ก่อนเลือกโมเดล</p>

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

บทนี้ใช้ข้อมูลสมมติทั้งหมดเพื่อฝึกอ่านตารางและคำนวณ ไม่มีตัวเลขผลตอบแทนของหุ้นหรือกองทุนจริง โค้ดใช้ NumPy และ pandas รันเรียงจากต้นหน้าใน Notebook ใหม่ได้ หากยังไม่คุ้นกับ array และ DataFrame ให้อ่าน[พื้นฐาน Python สำหรับผลตอบแทน](returns.html#python-basics)ก่อน

<span id="ml-observations"></span>

## หนึ่งแถวคือสิ่งที่เราสังเกตหนึ่งครั้ง

เริ่มด้วยผลตอบแทนรายเดือนของสินทรัพย์สมมติหนึ่งตัว ตั้งแต่มกราคมถึงกันยายน 2021 หนึ่งแถวหมายถึงหนึ่งเดือนและใช้วันสิ้นเดือนเป็นชื่อแถว ตัวเลข 0.02 หมายถึงผลตอบแทน 2% ของเดือนนั้น ไม่ใช่ราคาสินทรัพย์

`pd.date_range` สร้างวันที่ต่อเนื่อง `periods=9` ให้เก้าวันที่ และ `freq="ME"` เลือกวันสิ้นเดือน `pd.Series` จับคู่ผลตอบแทนกับวันที่ ส่วน `.to_frame()` เปลี่ยน Series เป็นตารางหนึ่งคอลัมน์สำหรับแสดงผล

```python
import numpy as np
import pandas as pd

months = pd.date_range("2021-01-31", periods=9, freq="ME")
ml_returns = pd.Series(
    [0.02, -0.01, 0.03, -0.02, 0.01, -0.04, 0.02, 0.01, 0.03],
    index=months, name="return",
)
print(ml_returns.to_frame())
print("Number of monthly observations:", len(ml_returns))
```

เราได้ observations เก้าครั้ง เช่น มีนาคมให้ผลตอบแทน 3% และเมษายนให้ −2% ถ้าเปลี่ยนเป็นข้อมูลหลายหุ้น หนึ่งแถวอาจหมายถึงหุ้นหนึ่งตัวในเดือนหนึ่ง ต้องระบุหน่วยสังเกตให้ชัดก่อนแบ่งข้อมูล หุ้นหลายตัวในวันเดียวกันอาจรับข่าวเดียวกัน จึงไม่ควรนับว่าเป็นหลักฐานอิสระทั้งหมดเพียงเพราะมีหลายแถว

<span id="ml-features-target"></span>

## Feature เป็นข้อมูลเข้า ส่วน Target เป็นคำตอบที่ต้องการประมาณ

[Feature](glossary.html#feature) คือข้อมูลที่ส่งเข้าโมเดล เช่น ผลตอบแทนล่าสุดหรือความผันผวนย้อนหลัง ส่วน [target หรือ label](glossary.html#target-label) คือคำตอบที่ใช้ฝึกและตรวจโมเดล เช่น ผลตอบแทนเดือนถัดไป สัญลักษณ์ที่ใช้บ่อยคือ $X$ สำหรับตาราง features และ $y$ สำหรับ target

สำหรับคำถาม “หลังสิ้นเดือนนี้ เราจะพยากรณ์ผลตอบแทนเดือนหน้าอย่างไร” ลองสร้างสอง features คือผลตอบแทนเดือนล่าสุดกับ SD ของผลตอบแทนสามเดือนล่าสุด หน้าต่างสามเดือนรวมเดือนปัจจุบันที่เพิ่งจบแล้ว จึงใช้เฉพาะอดีตและปัจจุบัน ณ เวลาพยากรณ์ ส่วน target เป็นผลตอบแทนเดือนถัดไป

`.rolling(3).std(ddof=0)` เลื่อนหน้าต่างยาวสาม observations แล้วหาความผันผวนของตัวเลขในหน้าต่างโดยหาร variance ด้วย 3 นี่เป็นนิยาม feature ที่เราเลือกเพื่อสาธิต ไม่ได้อ้างว่าเป็นตัวประมาณ variance ที่ไม่มีอคติหรือเป็นการพยากรณ์ความเสี่ยงที่ดีที่สุด หน่วยยังเป็น SD ของผลตอบแทนรายเดือน

`.shift(-1)` นำค่าของแถวถัดไปมาใส่ที่แถวปัจจุบันเพื่อสร้าง target ในตารางย้อนหลัง การเลื่อนแบบนี้ใช้สร้างคำตอบสำหรับการฝึกได้ แต่ห้ามส่งคอลัมน์ที่เห็นอนาคตนี้เข้าไปเป็น feature

```python
feature_table = pd.DataFrame({
    "recent_return": ml_returns,
    "volatility_3m": ml_returns.rolling(3).std(ddof=0),
    "next_return": ml_returns.shift(-1),
})
feature_table["label_known_on"] = feature_table.index + pd.offsets.MonthEnd(1)
labeled_data = feature_table.dropna(
    subset=["recent_return", "volatility_3m", "next_return"]
)
print(labeled_data.round(4))
```

มกราคมและกุมภาพันธ์ยังไม่มีผลตอบแทนครบสามเดือน จึงมี `NaN` ใน feature ความผันผวน ส่วนกันยายนไม่มีผลตอบแทนเดือนตุลาคมในตาราง จึงมี `NaN` ใน target เราลบเฉพาะแถวที่ยังไม่ครบสำหรับการฝึกด้วย `.dropna(subset=...)` เหลือหกแถวตั้งแต่มีนาคมถึงสิงหาคม

แถวมีนาคมมี `recent_return=0.03`, `volatility_3m` ประมาณ 0.016997 หรือ 1.6997% และ `next_return=-0.02` วันที่ใน `label_known_on` คือ 30 เมษายน เพราะหลังสิ้นมีนาคมเรายังไม่รู้ผลตอบแทนเมษายน `pd.offsets.MonthEnd(1)` ใช้ขยับจากวันสิ้นเดือนหนึ่งไปวันสิ้นเดือนถัดไป

ตารางย้อนหลังที่ครบแล้วอาจทำให้อนาคตดูเหมือนเป็นข้อมูลที่มีมาตลอด คอลัมน์วันที่รู้ label ช่วยป้องกันความสับสนนี้ สำหรับข้อมูลประกาศเศรษฐกิจ ต้องใช้เวลาประกาศจริงและฉบับข้อมูลที่มีในวันนั้นด้วย การใส่วันที่อ้างอิงเดือนอย่างเดียวไม่พอถ้าประกาศภายหลังหรือมีการแก้ไขย้อนหลัง

<span id="ml-label-timing"></span>

## ณ วันฝึกโมเดล เรารู้คำตอบของแถวใดแล้ว

สมมติว่าฝึกโมเดลหลังสิ้นวันที่ 30 มิถุนายน 2021 เรารู้ผลตอบแทนถึงเดือนมิถุนายน แต่ target ของแถวมิถุนายนคือผลตอบแทนกรกฎาคม ซึ่งยังไม่เกิด จึงใช้แถวมีนาคม เมษายน และพฤษภาคมเป็นตัวอย่างที่มีคำตอบครบได้ ส่วน features ของมิถุนายนพร้อมสำหรับใช้พยากรณ์กรกฎาคม

เงื่อนไข `label_known_on <= cutoff` สร้างชุดค่า `True/False` แล้ว `.loc[...]` เลือกเฉพาะแถวที่เป็น `True` เราเก็บ `cutoff` เป็นวันที่ด้วย `pd.Timestamp` เพื่อเปรียบเทียบวันโดยตรง

```python
cutoff = pd.Timestamp("2021-06-30")
known_at_cutoff = labeled_data.loc[labeled_data["label_known_on"] <= cutoff]
features_at_cutoff = feature_table.loc[cutoff, ["recent_return", "volatility_3m"]]
print("Rows with known answers:", known_at_cutoff.index.strftime("%Y-%m").tolist())
print("Features available at cutoff:")
print(features_at_cutoff)
```

ผลรายการแถวคือ `['2021-03', '2021-04', '2021-05']` ส่วน features ที่ใช้พยากรณ์ ณ สิ้นมิถุนายนคือผลตอบแทนล่าสุด −4% และความผันผวนสามเดือนประมาณ 2.0548% ข้อมูลเพียงสามแถวนี้เล็กเกินกว่าจะใช้ประเมินคุณภาพโมเดลจริง เราใช้เพื่อให้ตรวจลำดับเวลาได้ด้วยตา

[Data leakage](glossary.html#data-leakage) เกิดเมื่อกระบวนการฝึกได้รับข้อมูลที่ยังไม่ควรมีในเวลาที่ต้องตัดสินใจ เช่น นำ target กรกฎาคมมาฝึกก่อนกรกฎาคมจบ หรือคำนวณค่าเฉลี่ยเพื่อปรับสเกล features จากทั้งอดีตและอนาคต บท[การทดสอบโมเดล](model-validation.html)จะตรวจกรณีเหล่านี้ด้วยข้อมูลที่ยาวขึ้น

<span id="ml-learning-tasks"></span>

## คำถามต่างกัน ทำให้ชนิดของคำตอบต่างกัน

[Supervised learning](glossary.html#supervised-learning) ใช้คู่ตัวอย่าง $(X,y)$ เพื่อเรียนความสัมพันธ์ระหว่างข้อมูลเข้ากับคำตอบ ถ้า $y$ เป็นตัวเลขต่อเนื่อง เช่น ผลตอบแทนเดือนหน้า เรียกโจทย์ว่า [regression](glossary.html#regression) ถ้า $y$ เป็นกลุ่ม เช่น ผลตอบแทนบวกหรือไม่บวก เรียกว่า [classification](glossary.html#classification)

สองโจทย์นี้ใช้ features ชุดเดียวกันได้ แต่รักษารายละเอียดของคำตอบต่างกัน การเปลี่ยนผลตอบแทนเป็น 0/1 จะทิ้งข้อมูลว่ากำไรหรือขาดทุนมากเท่าไร เช่น −0.1% กับ −20% กลายเป็น label 0 เหมือนกันหากกำหนด “บวก” ว่าต้องมากกว่าศูนย์

เลือกสองคอลัมน์ features ด้วยวงเล็บสองชั้นเพื่อให้ได้ DataFrame แล้ว `.to_numpy()` แปลงเป็น array ตัว `X_features.shape` จะแสดงจำนวนแถวและคอลัมน์ ส่วน `.astype(int)` เปลี่ยน `False/True` เป็น `0/1`

```python
X_features = labeled_data[["recent_return", "volatility_3m"]].to_numpy()
target_return = labeled_data["next_return"].to_numpy()
target_positive = (target_return > 0).astype(int)
print("X shape:", X_features.shape)
print("Regression target:", target_return)
print("Classification target:", target_positive)
```

ได้ $X$ ขนาด `(6, 2)` คือหก observations สอง features ส่วน regression target คือ `[-0.02, 0.01, -0.04, 0.02, 0.01, 0.03]` และ classification target คือ `[0, 1, 0, 1, 1, 1]` แต่ละตำแหน่งของ $y$ ต้องตรงกับแถวเดียวกันของ $X$ เสมอ

ชื่อ logistic regression อาจทำให้สับสน เพราะในงาน ML โดยทั่วไปโมเดลนี้ประมาณความน่าจะเป็นของ class แล้วใช้จำแนกประเภท ไม่ได้หมายความว่าคำตอบสุดท้ายต้องเป็นผลตอบแทนต่อเนื่อง รายละเอียดอยู่ใน[บทเริ่มพยากรณ์](supervised-learning.html)

<span id="ml-predictions-loss"></span>

## จากค่าพยากรณ์สู่ความผิดพลาดที่วัดได้

สมมติให้มีกฎพยากรณ์ผลตอบแทนหนึ่งเดือน

$$
\hat y=0.002+0.25x_1,
$$

โดย $x_1$ คือผลตอบแทนเดือนล่าสุดและ $\hat y$ คือค่าพยากรณ์เดือนถัดไป หมวกบน $y$ ใช้แยกค่าที่พยากรณ์ออกจากคำตอบที่เกิดจริง ค่าคงที่ 0.002 คือ 0.2 จุดเปอร์เซ็นต์ และสัมประสิทธิ์ 0.25 หมายความว่าเมื่อ feature เพิ่มหนึ่งจุดเปอร์เซ็นต์ ค่าพยากรณ์เพิ่ม 0.25 จุดเปอร์เซ็นต์ตามกฎนี้

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

Mean squared error หรือ MSE หาค่าเฉลี่ยของความคลาดเคลื่อนยกกำลังสอง:

$$
\operatorname{MSE}=\frac1n\sum_{i=1}^{n}(\hat y_i-y_i)^2,
\qquad \operatorname{RMSE}=\sqrt{\operatorname{MSE}}.
$$

การยกกำลังสองทำให้ข้อผิดพลาดบวกและลบไม่หักล้างกัน และให้โทษมากขึ้นกับความผิดพลาดขนาดใหญ่ RMSE กลับมาอยู่ในหน่วยเดียวกับ $y$ ส่วน MSE มีหน่วยยกกำลังสอง `X_features[:, 0]` เลือกทุกแถวของคอลัมน์แรก โดย Python เริ่มนับคอลัมน์จากศูนย์

```python
fixed_predictions = 0.002 + 0.25 * X_features[:, 0]
fixed_errors = fixed_predictions - target_return
mse_fixed = np.mean(fixed_errors ** 2)
rmse_fixed = np.sqrt(mse_fixed)
print("Predicted monthly returns (%):", np.round(100 * fixed_predictions, 2))
print(f"MSE in squared decimal returns: {mse_fixed:.8f}")
print(f"RMSE in monthly return units: {rmse_fixed:.4%}")
```

ค่าพยากรณ์คือ `[0.95, -0.30, 0.45, -0.80, 0.70, 0.45]`% ต่อเดือน MSE เท่ากับประมาณ 0.00074379 และ RMSE 2.7273 จุดเปอร์เซ็นต์ต่อเดือน แถวแรกพยากรณ์ +0.95% แต่เกิด −2% จึงผิด $0.0095-(-0.02)=0.0295$ หรือ 2.95 จุดเปอร์เซ็นต์ พจน์ของแถวนี้ในผลรวม squared errors คือ $0.0295^2=0.00087025$

การเห็น RMSE ตัวเดียวไม่บอกว่าคุ้มใช้หรือไม่ ต้องเทียบกับวิธีพื้นฐาน เช่น พยากรณ์ด้วยค่าเฉลี่ยจากข้อมูลฝึก และวัดบนข้อมูลที่ไม่ได้ใช้เลือกโมเดล หน่วยที่ต่างกันก็ทำให้ MSE ต่างกัน หากเปลี่ยนผลตอบแทนจากทศนิยมเป็นตัวเลขเปอร์เซ็นต์ MSE จะโต $100^2=10{,}000$ เท่า โดยคุณภาพคำตอบเดิมไม่ได้เปลี่ยน

<span id="ml-probability-class"></span>

## ความน่าจะเป็นกับคำตอบว่าใช่หรือไม่ใช่

ในโจทย์ผลตอบแทนบวก โมเดลอาจให้ความน่าจะเป็น $p=P(y=1\mid X)$ เช่น 0.65 แล้วเราจึงเลือกเกณฑ์หรือ threshold เพื่อเปลี่ยนเป็นคำตอบ 0/1 ถ้าใช้เกณฑ์ $p\geq0.5$ ให้ทายเป็น 1 ค่าทั้ง 0.51 และ 0.99 จะได้ class เดียวกัน แม้ระดับความมั่นใจต่างกัน

ตัวเลขความน่าจะเป็นในตัวอย่างนี้กำหนดขึ้นเพื่อฝึกอ่านผล ยังไม่ได้มาจากโมเดลที่ fit แล้ว `==` เปรียบเทียบว่าคำตอบตรงกันหรือไม่ และ `np.mean` ของ array `True/False` ให้สัดส่วนที่ตอบถูกหรือ accuracy

```python
supplied_probabilities = np.array([0.35, 0.65, 0.60, 0.70, 0.40, 0.80])
positive_predictions = (supplied_probabilities >= 0.5).astype(int)
classification_accuracy = np.mean(positive_predictions == target_positive)
print("Predicted classes:", positive_predictions)
print("Observed classes:", target_positive)
print(f"Accuracy: {classification_accuracy:.2%}")
```

ได้คำตอบ `[0, 1, 1, 1, 0, 1]` ถูกสี่จากหกแถว หรือ 66.67% พลาดแถวที่ผลตอบแทนจริง −4% และแถวที่จริง +1% โดย accuracy นับการพลาดทั้งสองครั้งเป็นหนึ่งเท่ากัน หากความเสียหายของสองกรณีต่างกันต้องนำมาพิจารณาตอนออกแบบเกณฑ์ตัดสินใจด้วย

โมเดลที่ให้ความน่าจะเป็นถูก calibration ควรมีสัดส่วนเหตุการณ์ที่เกิดจริงสอดคล้องกับค่าที่รายงานเมื่อมีตัวอย่างมากพอ เช่น กลุ่มที่พยากรณ์ใกล้ 0.7 ควรเกิดเหตุการณ์ใกล้ 70% การเรียกตัวเลขว่า probability หรือมี accuracy สูง ยังไม่พิสูจน์คุณสมบัตินี้ บทถัดไปจะใช้ log loss เพื่อตรวจคุณภาพคำตอบแบบความน่าจะเป็นด้วย

<span id="ml-prediction-decision"></span>

## ทายทิศทางได้ ไม่ได้กำหนดว่าควรลงทุนเท่าไร

สมมติว่าเรารู้จริงในโลกตัวอย่างว่าสินทรัพย์มีโอกาส 60% ที่จะได้ +2% และโอกาส 40% ที่จะเสีย −4% ความน่าจะเป็นของผลตอบแทนบวกเกินครึ่ง แต่ผลตอบแทนคาดหวังคือ

$$
E[r]=0.60(0.02)+0.40(-0.04)=-0.004=-0.4\%.
$$

การตัดสินใจลงทุนต้องใช้ทั้งขนาดกำไร ขนาดขาดทุน ความน่าจะเป็น ต้นทุน และความเสี่ยงที่ยอมรับได้ ถ้าคิดต้นทุนเพิ่มเติม 0.1% ของเงินลงทุน ผลตอบแทนคาดหวังหลังต้นทุนในตัวอย่างจะเป็น −0.5%

```python
outcome_returns = np.array([0.02, -0.04])
outcome_probabilities = np.array([0.60, 0.40])
expected_gross_return = outcome_probabilities @ outcome_returns
assumed_cost = 0.001
expected_net_return = expected_gross_return - assumed_cost
print(f"Probability of a positive return: {outcome_probabilities[0]:.0%}")
print(f"Expected gross return: {expected_gross_return:.2%}")
print(f"Expected net return: {expected_net_return:.2%}")
```

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

Reinforcement learning ขยายไปสู่โจทย์ที่มีสถานะ การกระทำ และผลตอบแทนของการกระทำต่อเนื่อง เช่น เลือกน้ำหนักแล้วสังเกตมูลค่าพอร์ตกับต้นทุนรอบถัดไป การกำหนด reward ทำให้ระบบเรียนว่าจะปรับการกระทำอย่างไรในสภาพแวดล้อมที่ใช้ฝึก แต่คุณภาพยังขึ้นกับสภาพแวดล้อม สมมติฐาน และการทดสอบ ระบบที่เรียนได้ดีในแบบจำลองตลาดอาจทำงานต่างออกไปในตลาดจริง คอร์สช่วงต้นแนะนำแนวคิดนี้โดยยังไม่ได้สอนตัวแก้ reinforcement learning เราจะใช้การแยก “ค่าพยากรณ์” ออกจาก “กฎตัดสินใจ” เป็นฐานก่อน

<span id="ml-unsupervised"></span>

## เมื่อไม่มี Label เราค้นหารูปแบบอะไรได้บ้าง

[Unsupervised learning](glossary.html#unsupervised-learning) ใช้โครงสร้างของข้อมูล $X$ โดยไม่มี target ที่กำหนดให้ตอบถูกหรือผิดแบบเดียวกับ supervised learning ตัวอย่างเช่น จัดกลุ่มสินทรัพย์ที่คล้ายกัน ลดจำนวนมิติของข้อมูล หรือสำรวจความสัมพันธ์เป็นเครือข่าย การไม่มี label ไม่ได้หมายความว่าไม่มีสมมติฐาน เพราะยังต้องเลือกหน่วย ระยะทาง จำนวนกลุ่ม หรือความสัมพันธ์ที่สนใจ

### จัดกลุ่มจากความใกล้กัน

สมมติ A–D มี annual volatility เท่ากับ 10%, 12%, 30% และ 32% ถ้ากำหนดจุดศูนย์กลางสองกลุ่มไว้ที่ 11% กับ 31% เราสามารถจัดแต่ละตัวเข้ากลุ่มที่ใกล้ที่สุด นี่คือขั้นตอน assignment ในการจัดกลุ่ม โดยยังไม่ใช่การรันอัลกอริทึม K-means ครบทุกขั้น

`[:, None]` เปลี่ยน array สี่ค่าเป็นสี่แถวหนึ่งคอลัมน์ ส่วน `[None, :]` ทำให้ศูนย์กลางเป็นหนึ่งแถวสองคอลัมน์ เมื่อลบกัน NumPy จึงสร้างระยะทางครบสี่สินทรัพย์คูณสองกลุ่ม `argmin(axis=1)` คืนตำแหน่งของระยะทางต่ำสุดในแต่ละแถว

```python
cluster_vols = np.array([0.10, 0.12, 0.30, 0.32])
cluster_centers = np.array([0.11, 0.31])
cluster_distances = np.abs(cluster_vols[:, None] - cluster_centers[None, :])
cluster_assignments = cluster_distances.argmin(axis=1)
print("Distances in annual-volatility units:")
print(np.round(cluster_distances, 2))
print("Group labels:", cluster_assignments)
```

ได้กลุ่ม `[0, 0, 1, 1]` หมายถึง A/B อยู่ด้วยกันและ C/D อยู่ด้วยกัน เลข 0 กับ 1 เป็นชื่อกลุ่ม จะสลับชื่อก็ยังเป็นการแบ่งกลุ่มเดียวกัน ผลนี้บอกเพียงว่า volatility ใกล้กันตาม feature ที่ใช้ ไม่ได้บอกว่า correlation สูง ผลตอบแทนเท่ากัน หรือควรแบ่งเงินในกลุ่มเท่ากัน หากเพิ่มหลาย features ต้องพิจารณาสเกลก่อนวัดระยะทาง รายละเอียดจะต่อในหัวข้อ [asset clustering](glossary.html#asset-clustering)

### ลดจำนวนมิติด้วยการผสม Features

[Principal component analysis หรือ PCA](glossary.html#pca) สร้างแกนใหม่จากส่วนผสมเชิงเส้นของ features เพื่อเก็บความแปรปรวนของข้อมูลไว้มากที่สุดตามจำนวนแกนที่เลือก ค่าที่ได้เป็น feature ใหม่ เช่น $z=(x_1+x_2)/\sqrt2$ จึงอาจใช้ข้อมูลจากทั้งสองคอลัมน์พร้อมกัน แม้ลดจากสองคอลัมน์เหลือคอลัมน์เดียว

ดูจุดสมมติสี่จุด `[-2,-1]`, `[-1,-2]`, `[1,2]`, `[2,1]` ซึ่งเป็น features ไม่มีหน่วยที่จัดสเกลไว้แล้วและมีค่าเฉลี่ยแต่ละคอลัมน์เป็นศูนย์ จุดส่วนใหญ่เรียงไปตามแนวจากซ้ายล่างไปขวาบน เราจึงลองฉายลงแกนที่มีทิศทาง $[1,1]/\sqrt2$ ตัวหารทำให้ความยาวของ vector ทิศทางเท่ากับหนึ่ง

```python
pca_points = np.array([[-2.0, -1.0], [-1.0, -2.0], [1.0, 2.0], [2.0, 1.0]])
pca_direction = np.array([1.0, 1.0]) / np.sqrt(2)
pca_scores = pca_points @ pca_direction
pca_reconstruction = pca_scores[:, None] * pca_direction
pca_explained_fraction = np.sum(pca_reconstruction ** 2) / np.sum(pca_points ** 2)
print("One-dimensional scores:", np.round(pca_scores, 4))
print("Reconstructed points:", pca_reconstruction)
print(f"Fraction of centered variation retained: {pca_explained_fraction:.1%}")
```

คะแนนหนึ่งมิติประมาณ `[-2.1213, -2.1213, 2.1213, 2.1213]` เมื่อนำกลับมาเป็นสองมิติได้ `[-1.5,-1.5]` สองจุดและ `[1.5,1.5]` สองจุด เราสูญเสียความแตกต่างภายในแต่ละคู่ แต่เก็บผลรวมกำลังสองรอบค่าเฉลี่ยได้ $18/20=90$% ในตัวอย่างนี้แกนที่เลือกตรงกับ principal component แรกจริง ส่วน PCA ของข้อมูลทั่วไปต้องคำนวณทิศทางจากข้อมูลฝึก

90% ในที่นี้เป็นสัดส่วนความแปรปรวนที่เก็บได้ ไม่ใช่ accuracy ของการทายตลาด และแกนที่อธิบายความแปรปรวนมากอาจไม่ใช่แกนที่ช่วยพยากรณ์ target ได้ดีที่สุด ดูนิยามและข้อกำหนดเรื่อง centering ใน[เอกสาร PCA](https://scikit-learn.org/1.6/modules/decomposition.html#pca)

### ความสัมพันธ์ในรูปเครือข่าย

อีกวิธีคือให้สินทรัพย์เป็นจุดหรือ node แล้วเชื่อมคู่ที่มีความสัมพันธ์ตามเกณฑ์ เช่น correlation เกิน 0.6 ตาราง 0/1 ที่บอกว่าคู่ใดเชื่อมกันเรียกว่า adjacency matrix เราใช้ตัวอย่างสามสินทรัพย์ที่กำหนด correlation ขึ้นเอง และไม่นับการเชื่อมสินทรัพย์กับตัวเอง

```python
corr_map = np.array([[1.0, 0.8, 0.1], [0.8, 1.0, 0.2], [0.1, 0.2, 1.0]])
network_adjacency = (corr_map > 0.6).astype(int)
np.fill_diagonal(network_adjacency, 0)
network_degrees = network_adjacency.sum(axis=1)
print("Adjacency matrix:")
print(network_adjacency)
print("Number of connections:", network_degrees)
```

ผลมีเส้นเชื่อมเพียง A–B จึงได้จำนวนเพื่อนบ้าน `[1,1,0]` เกณฑ์ 0.6 เป็นค่าที่เลือกเพื่อสาธิต เมื่อเปลี่ยนเกณฑ์เครือข่ายก็เปลี่ยน และตำแหน่งที่โปรแกรมวาดจุดไว้กลางภาพไม่ใช่หลักฐานว่าสินทรัพย์นั้นมีอิทธิพลเชิงเหตุผลต่อระบบ การศึกษาความสัมพันธ์แบบมีเงื่อนไขจะใช้แนวคิด [partial correlation](glossary.html#partial-correlation) เพิ่มเติมในบทเครือข่าย

<span id="ml-financial-limits"></span>

## เลือกข้อมูลให้ตรงกับงานที่จะใช้

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

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

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

<span id="ml-foundation-exercises"></span>

## แบบฝึกหัดพร้อมเฉลย

### 1. บอกหน่วยสังเกตให้ครบ

ถ้าตารางมี 100 หุ้นและ 12 เดือน แถวหนึ่งแทนหุ้นหนึ่งตัวในเดือนหนึ่ง จะมี observations กี่แถว และถือว่าทั้งหมดเป็นอิสระต่อกันได้ทันทีหรือไม่

เฉลย: ถ้าครบทุกคู่จะมี $100\times12=1{,}200$ แถว แต่หุ้นในเดือนเดียวกันอาจรับปัจจัยตลาดร่วมกัน และหุ้นตัวเดิมอาจมีความสัมพันธ์ข้ามเวลา จำนวนแถวจึงต่างจากจำนวนหลักฐานอิสระ

### 2. ผลตอบแทนเดือนหน้าควรอยู่ใน X หรือ y

ต้องการพยากรณ์ผลตอบแทนกรกฎาคมหลังสิ้นมิถุนายน คอลัมน์ `next_return` ของแถวมิถุนายนใช้เป็น feature ได้หรือไม่

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

### 3. ผลตอบแทนศูนย์อยู่ Class ใด

ใช้กฎ `(target_return > 0).astype(int)` ถ้า target เท่ากับศูนย์จะได้ class ใด และกรณี target หายควรตีความเหมือนกันหรือไม่

เฉลย: ผลตอบแทนศูนย์เป็น class 0 เพราะไม่ได้มากกว่าศูนย์ ส่วนข้อมูลหายยังไม่รู้คำตอบ จึงต้องจัดการ missing target ก่อนเปรียบเทียบ ในตัวอย่างเราเลือกแถวที่ target ครบแล้วจึงสร้าง class เพื่อไม่ให้ `NaN` ถูกตีความเป็นคำตอบที่ไม่บวก

### 4. ตรวจ Error ของแถวแรก

กฎให้ $\hat y=0.002+0.25(0.03)=0.0095$ ขณะที่ $y=-0.02$ จงหา error และ squared error

เฉลย: Error ตามนิยามค่าพยากรณ์ลบค่าจริงคือ 0.0295 หรือ 2.95 จุดเปอร์เซ็นต์ และ squared error เท่ากับ 0.00087025 หน่วยทศนิยมผลตอบแทนยกกำลังสอง Error บวกในที่นี้หมายถึงพยากรณ์สูงกว่าที่เกิดจริง

### 5. โอกาสกำไรสูงกว่าครึ่งเพียงพอหรือไม่

สินทรัพย์มีโอกาส 70% ที่ได้ +1% และ 30% ที่เสีย −5% ถ้าไม่คิดต้นทุน ผลตอบแทนคาดหวังเป็นเท่าไร

เฉลย: $0.70(0.01)+0.30(-0.05)=-0.008$ หรือ −0.8% ต่อช่วง โอกาสเกิดกำไรกับผลตอบแทนคาดหวังจึงต้องคำนวณแยกกัน

### 6. สลับชื่อกลุ่มทำให้ผลเปลี่ยนหรือไม่

ผลจัดกลุ่ม `[0,0,1,1]` เปลี่ยนเป็น `[1,1,0,0]` โดยสมาชิกไม่เปลี่ยน ถือว่าเป็นการแบ่งกลุ่มใหม่หรือไม่

เฉลย: เป็นการแบ่งเดียวกัน เพราะ A/B ยังอยู่ด้วยกันและ C/D ยังอยู่ด้วยกัน เลขกลุ่มเป็นป้ายชื่อ ไม่ได้หมายถึงอันดับผลตอบแทนหรือระดับคุณภาพ

### 7. PCA เก็บ Variation 90% แปลว่าทายถูก 90% หรือไม่

เฉลย: ไม่ใช่ ตัวเลข 90% มาจาก $18/20$ ซึ่งเปรียบเทียบผลรวมกำลังสองของข้อมูลที่สร้างกลับได้กับข้อมูลเดิมที่ลบค่าเฉลี่ยแล้ว ตัวอย่างไม่มี target จึงยังไม่ได้วัดความแม่นยำในการพยากรณ์ใด ๆ

### 8. Correlation Network ยืนยันเหตุและผลได้หรือไม่

ในตัวอย่าง A เชื่อมกับ B เพราะ correlation 0.8 เราสรุปได้หรือไม่ว่าข่าวของ A ทำให้ B เปลี่ยนราคา

เฉลย: สรุปไม่ได้จาก correlation อย่างเดียว ทั้งสองอาจรับข่าวตลาดร่วมกันหรือมีปัจจัยอื่นที่ไม่ได้ใส่ในข้อมูล เส้นเชื่อมบอกเพียงว่าผ่านเกณฑ์ความสัมพันธ์ที่เรากำหนด ส่วนข้อสรุปเชิงเหตุและผลต้องใช้ข้อมูลและการออกแบบการศึกษาที่รองรับคำถามนั้น

บทถัดไปจะใช้ข้อมูลฝึกเลือกพารามิเตอร์จริง แล้วตรวจว่า [Regression และ KNN](supervised-learning.html) เปลี่ยนตาราง features เป็นคำพยากรณ์อย่างไร

<span id="ml-foundation-sources"></span>

## แหล่งที่มาและขอบเขต

อ่าน Transcript ภาษาอังกฤษเต็มเมื่อ 3 ตุลาคม 2026 ของ [Welcome](https://www.coursera.org/learn/python-machine-learning-for-investment-management/lecture/ueW5r/welcome-to-the-python-machine-learning-for-investment-management-course), [Introduction to machine-learning](https://www.coursera.org/learn/python-machine-learning-for-investment-management/lecture/bT5gM/introduction-to-machine-learning), [Financial applications](https://www.coursera.org/learn/python-machine-learning-for-investment-management/lecture/NEevd/financial-applications), [Supervised learning](https://www.coursera.org/learn/python-machine-learning-for-investment-management/lecture/U2fjL/supervised-learning), [Unsupervised learning](https://www.coursera.org/learn/python-machine-learning-for-investment-management/lecture/lFYle/unsupervised-learning) และ [Challenges ahead](https://www.coursera.org/learn/python-machine-learning-for-investment-management/lecture/1Ba4p/challenges-ahead) ในคอร์ส Python and Machine Learning for Asset Management ใช้เป็นแนวหัวข้อและบริบท ไม่ได้นำตัวอย่างบุคคล ข้อมูลตลาด หรือข้อกล่าวอ้างประสิทธิภาพในอดีตมาใช้เป็นผลทดลองของบทนี้

คำอธิบาย PCA ตรวจประกอบกับ [scikit-learn 1.6: PCA](https://scikit-learn.org/1.6/modules/decomposition.html#pca) และข้อควรระวังการเตรียมข้อมูลกับ [Common pitfalls: Data leakage](https://scikit-learn.org/1.6/common_pitfalls.html#data-leakage) สมการ ตาราง และโค้ดในหน้านี้สร้างขึ้นใหม่เพื่อให้ตรวจเลขและลำดับเวลาได้โดยไม่ใช้ไฟล์ส่วนตัวของคอร์ส
