KNN สำหรับการถดถอยและข้อจำกัดด้านการขยายขนาด
ผู้เรียนจะใช้ KNeighborsRegressor กับเป้าหมายแบบต่อเนื่อง จากนั้นวัดเวลาการพยากรณ์บนชุดข้อมูลขนาดใหญ่เพื่อเข้าใจต้นทุนการอนุมาน O(n) ของ KNN
KNN สำหรับการถดถอยและข้อจำกัดด้านการขยายขนาด เป็นบทเรียน Machine Learning Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Machine Learning Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน
KNN สำหรับการถดถอย: การหาค่าเฉลี่ยของเพื่อนบ้าน
KNN ไม่ได้จำกัดอยู่แค่การจำแนกประเภทเท่านั้น แต่ยังสามารถทำนาย ค่าต่อเนื่อง ได้ด้วย ใน การถดถอยด้วย KNN ค่าทำนายสำหรับจุดใหม่คือ ค่าเฉลี่ย ของค่าเป้าหมายจากเพื่อนบ้านที่ใกล้ที่สุดจำนวน k ราย ตัวอย่างเช่น หากต้องการทำนายราคาบ้าน KNN จะค้นหาบ้านที่คล้ายกันมากที่สุดจำนวน k หลังในชุดข้อมูลฝึก แล้วหาค่าเฉลี่ยของราคา วิธีนี้สร้างแบบจำลองการถดถอยเฉพาะที่แบบไม่อิงพารามิเตอร์ ซึ่งสามารถจับรูปแบบที่ซับซ้อนได้โดยไม่ต้องสมมติรูปแบบฟังก์ชันใด ๆ ระหว่างคุณลักษณะกับค่าเป้าหมาย
import numpy as np
# Training data: house sizes (sqm) -> prices (thousands)
X_train = np.array([[50], [70], [90], [110], [130]])
y_train = np.array([150, 200, 260, 310, 380])
# Query: predict price for 80 sqm house
x_new = np.array([[80]])
# k=3: find 3 nearest neighbors
dists = np.abs(X_train - x_new).flatten()
nearest_idx = np.argsort(dists)[:3]
neighbor_prices = y_train[nearest_idx]
prediction = neighbor_prices.mean()
print('Neighbor prices:', neighbor_prices)
print('KNN regression prediction:', prediction)KNeighborsRegressor ใน scikit-learn
KNeighborsRegressor ของ scikit-learn ใช้ KNN กับค่าเป้าหมายต่อเนื่อง โดยมีส่วนติดต่อการใช้งานแบบเดียวกับตัวจำแนกประเภท และรองรับพารามิเตอร์เดียวกัน ได้แก่ n_neighbors, metric, weights และ algorithm การถดถอยแบบถ่วงน้ำหนักตามระยะห่าง (weights='distance') มักให้ผลดี เพราะเพื่อนบ้านที่ใกล้กว่าจะมีส่วนต่อค่าทำนายมากกว่าเพื่อนบ้านที่ไกลกว่า ซึ่งมีประโยชน์เป็นพิเศษบริเวณขอบของการกระจายข้อมูลฝึก ที่เพื่อนบ้านซึ่งอยู่ไกลอาจทำให้เกิดความเอนเอียงอย่างมาก
from sklearn.neighbors import KNeighborsRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import numpy as np
X, y = fetch_california_housing(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42)
pipe = Pipeline([
('sc', StandardScaler()),
('knn', KNeighborsRegressor(n_neighbors=10, weights='distance'))
])
pipe.fit(X_tr, y_tr)
rmse = mean_squared_error(y_te, pipe.predict(X_te), squared=False)
print('RMSE:', rmse.round(3))การเลือก k สำหรับการถดถอย
หลักการเรื่องความเอนเอียงกับความแปรปรวนแบบเดียวกันนี้ใช้กับการถดถอยด้วย KNN: k น้อย = ความแปรปรวนสูง ค่าทำนายคดเคี้ยวมาก; k มาก = ความเอนเอียงสูง ค่าทำนายถูกทำให้เรียบมากเกินไป คุณสามารถมองเห็นความแตกต่างนี้ได้ด้วยการพล็อตฟังก์ชันที่ทำนายบนช่วงอินพุตแบบหนึ่งมิติ เมื่อ k=1 เส้นค่าทำนายจะกระโดดไปยังค่าที่แน่นอนของจุดฝึกแต่ละจุด เมื่อเพิ่มค่า k เส้นจะเรียบขึ้น ค่า k ที่เหมาะสมจะทำให้ค่า RMSE (หรือ MAE) จากการตรวจสอบไขว้มีค่าต่ำสุด สำหรับการถดถอย ไม่ต้องกังวลเรื่องการตัดสินกรณีคะแนนเสมอกัน ดังนั้นแม้ใช้ค่า k เป็นจำนวนคู่ก็ไม่มีปัญหา
from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import numpy as np
best_k, best_score = 1, float('inf')
for k in range(1, 31):
pipe = Pipeline([
('sc', StandardScaler()),
('knn', KNeighborsRegressor(n_neighbors=k))
])
scores = -cross_val_score(pipe, X_tr, y_tr, cv=5, scoring='neg_root_mean_squared_error')
mean_rmse = scores.mean()
if mean_rmse < best_score:
best_score, best_k = mean_rmse, k
print(f'Best k={best_k} with CV RMSE={best_score:.3f}')เวลาทำนายของ KNN: O(N * d) ต่อการสอบถาม
ต่างจากแบบจำลองเชิงพารามิเตอร์ที่ผ่านการฝึกแล้ว (การถดถอยเชิงเส้น, โครงข่ายประสาทเทียม) ซึ่งทำนายได้ในเวลา O(d) โดยใช้พารามิเตอร์ที่จัดเก็บไว้ KNN ต้องสแกนจุดฝึกทั้งหมดจำนวน N จุดขณะอนุมาน การทำนายแต่ละครั้งต้องคำนวณระยะห่างไปยังตัวอย่างฝึกทุกตัว ซึ่งเป็นการดำเนินการแบบ O(N * d) สำหรับ N=1,000,000 และ d=100 จะเท่ากับการดำเนินการ 100 ล้านครั้งต่อการทำนายหนึ่งครั้ง หากการดำเนินการหนึ่งครั้งใช้เวลา 1 มิลลิวินาที การทำนายหนึ่งครั้งจะใช้เวลา 100 วินาที ทำให้ KNN แบบพื้นฐาน ไม่เหมาะสมอย่างสิ้นเชิงกับระบบใช้งานจริงแบบเรียลไทม์ ที่มีชุดข้อมูลฝึกขนาดใหญ่
import numpy as np
import time
np.random.seed(42)
for N in [1000, 10000, 100000, 1000000]:
X_big = np.random.randn(N, 10)
query = np.random.randn(1, 10)
start = time.time()
dists = np.linalg.norm(X_big - query, axis=1)
_ = np.argsort(dists)[:5]
elapsed = time.time() - start
print(f'N={N:>8}: {elapsed*1000:.1f} ms')
# Prediction time scales linearly with Nเพื่อนบ้านใกล้ที่สุดโดยประมาณ: KD-Tree และ Ball Tree
Scikit-learn มีโครงสร้างดัชนีเชิงพื้นที่สองแบบเพื่อเร่งการค้นหาเพื่อนบ้าน KD-Tree แบ่งปริภูมิคุณลักษณะโดยแบ่งซ้ำตามมิติที่มีความแปรปรวนสูงที่สุด ทำให้ค้นหาเพื่อนบ้านของข้อมูลมิติต่ำได้ในเวลา O(log N) ส่วน Ball Tree แบ่งข้อมูลออกเป็นทรงกลมหลายมิติที่ซ้อนกัน จึงมีประสิทธิภาพมากกว่าสำหรับข้อมูลมิติสูงหรือข้อมูลที่ใช้เมตริกแบบไม่ใช่ยูคลิด ทั้งสองแบบช่วยลดเวลาเฉลี่ยในการทำนายได้อย่างมาก ให้กำหนดพารามิเตอร์ algorithm ใน KNeighborsClassifier เป็น 'kd_tree', 'ball_tree' หรือ 'auto' (scikit-learn จะเป็นผู้เลือก)
from sklearn.neighbors import KNeighborsClassifier
import time, numpy as np
X = np.random.randn(50000, 5)
y = (X[:, 0] > 0).astype(int)
algorithms = ['brute', 'kd_tree', 'ball_tree']
for alg in algorithms:
knn = KNeighborsClassifier(n_neighbors=5, algorithm=alg)
knn.fit(X, y)
start = time.time()
knn.predict(X[:100])
print(f'{alg:10}: {(time.time()-start)*1000:.1f} ms for 100 predictions')ข้อกำหนดด้านหน่วยความจำของ KNN
KNN ต้อง จัดเก็บชุดข้อมูลฝึกทั้งหมดไว้ในหน่วยความจำตลอดเวลา เนื่องจากการทำนายต้องเข้าถึงตัวอย่างฝึก สำหรับตัวอย่างจำนวน N=1 ล้านรายการที่มีคุณลักษณะชนิด float64 จำนวน d=100 รายการ เมทริกซ์ข้อมูลเพียงอย่างเดียวต้องใช้ 800 MB ของ RAM หาก N=10 ล้านรายการ จะใช้หน่วยความจำ 8 GB ซึ่งมากเกินไปสำหรับสภาพแวดล้อมการนำไปใช้งานจำนวนมาก แบบจำลองเชิงพารามิเตอร์ เช่น การถดถอยเชิงเส้นหรือโครงข่ายประสาทเทียม จะบีบอัดตัวอย่าง N รายการให้เหลือพารามิเตอร์จำนวนคงที่ จึงใช้หน่วยความจำอย่างมีประสิทธิภาพกว่ามากขณะอนุมาน ต้นทุนหน่วยความจำของ KNN คือ O(N * d) โดยไม่ขึ้นกับความซับซ้อนของปัญหา
import numpy as np
def memory_mb(N, d, dtype=np.float64):
bytes_per_value = np.dtype(dtype).itemsize
total_bytes = N * d * bytes_per_value
return total_bytes / (1024**2)
for N in [1000, 10000, 100000, 1000000]:
mb = memory_mb(N, d=100)
print(f'N={N:>8}, d=100: {mb:.1f} MB')
# 1,000: 0.8 MB (fine)
# 1,000,000: 762.9 MB (borderline)
# A linear model: same O(d) parameters regardless of NFAISS: เพื่อนบ้านใกล้ที่สุดโดยประมาณในระดับขนาดใหญ่
สำหรับกรณีใช้งานจริงในระดับขนาดใหญ่ ไลบรารี เพื่อนบ้านใกล้ที่สุดโดยประมาณ (ANN) ช่วยลดเวลาค้นหาได้อย่างมาก โดยแลกกับการอาจพลาดเพื่อนบ้านที่ใกล้ที่สุดจริงในบางครั้ง FAISS (Facebook AI Similarity Search) สามารถสอบถามเวกเตอร์นับพันล้านรายการได้ภายในเวลาไม่กี่มิลลิวินาที โดยใช้โครงสร้างดัชนีที่เร่งด้วย GPU Annoy (Spotify) สร้างป่าของต้นไม้การฉายแบบสุ่มสำหรับการค้นหาโดยประมาณ กราฟ HNSW (Hierarchical Navigable Small World) สามารถตอบคำถามได้ภายในเวลาไม่ถึงหนึ่งมิลลิวินาที ไลบรารีเหล่านี้ใช้ในระบบแนะนำและการค้นหาเชิงความหมายระดับใช้งานจริง
# Conceptual FAISS usage (requires: pip install faiss-cpu)
import numpy as np
# import faiss # not available in standard envs
# Conceptual workflow:
# N = 1_000_000 # 1 million vectors
# d = 128 # dimensionality
# X = np.random.randn(N, d).astype('float32')
# index = faiss.IndexFlatL2(d) # Exact L2 search
# index.add(X) # Index all vectors
# Query 10 vectors
# query = np.random.randn(10, d).astype('float32')
# distances, indices = index.search(query, k=5)
# print(indices.shape) # (10, 5)เมื่อใด KNN ใช้งานได้จริง และเมื่อใดควรใช้ทางเลือกอื่น
KNN ใช้งานได้จริงเมื่อ: N < 100,000, การทำนายทำเป็นชุด (ไม่ใช่แบบเรียลไทม์) และต้องการความสามารถในการอธิบายผล (คุณสามารถแสดงตัวอย่างที่คล้ายกันจริง ๆ ได้) KNN มีข้อจำกัดเมื่อ: N มีขนาดใหญ่มาก, ต้องการการทำนายแบบเรียลไทม์ (เวลาแฝง <100ms) หรือปริภูมิคุณลักษณะมีมิติสูง (>50 คุณลักษณะ) ทางเลือกที่ดีกว่าสำหรับ N ขนาดใหญ่ ได้แก่ Random Forests และ Gradient Boosting สำหรับข้อมูลแบบตาราง และโครงข่ายประสาทเทียมสำหรับรูปภาพและข้อความ KNN ยังคงมีคุณค่าในฐานะ ค่าพื้นฐานที่แข็งแกร่งสำหรับระบบแนะนำและการตรวจจับความผิดปกติ เมื่อชุดข้อมูลมีขนาดพอดีกับหน่วยความจำอย่างสบาย
# Decision guide: KNN vs alternatives
def should_use_knn(N, d, latency_ms_required):
if N > 500_000:
return 'Too large for KNN -- use Random Forest or XGBoost'
elif d > 50:
return 'Too high-dimensional -- apply PCA first or use tree models'
elif latency_ms_required < 50:
return 'Too strict latency -- use parametric model'
else:
return 'KNN is suitable as a baseline'
print(should_use_knn(10000, 10, 500)) # KNN is suitable
print(should_use_knn(1000000, 10, 500)) # Too large
print(should_use_knn(10000, 100, 500)) # Too high-dimensionalการวัดประสิทธิภาพ KNN เทียบกับการถดถอยเชิงเส้น
การเปรียบเทียบ KNN กับการถดถอยเชิงเส้นในงานการถดถอยเดียวกันจะแสดงให้เห็นการแลกเปลี่ยนด้านการขยายขนาด การถดถอยเชิงเส้นฝึกเสร็จภายในไม่กี่วินาทีโดยไม่ขึ้นกับ N (การฝึกใช้เวลา O(N*d) แต่การทำนายใช้เวลา O(d)) การฝึก KNN เสร็จแทบจะทันที (ไม่มีการคำนวณ) แต่เวลาทำนายจะเพิ่มขึ้นตาม N ทำให้ KNN เป็น แบบจำลองที่เลื่อนการคำนวณออกไป กล่าวคือ ต้นทุนทั้งหมดจะเกิดขึ้นขณะทำนาย สำหรับงานทำนายแบบชุดครั้งเดียวที่มี 100k แถว KNN อาจยอมรับได้ แต่สำหรับ API ที่ให้บริการ 1000 คำขอต่อวินาที การถดถอยเชิงเส้นหรือโครงข่ายประสาทเทียมจะเร็วกว่าเป็นลำดับขั้น
import numpy as np
import time
from sklearn.neighbors import KNeighborsRegressor
from sklearn.linear_model import LinearRegression
X = np.random.randn(50000, 10)
y = X[:, 0] * 3 + np.random.randn(50000)
X_test = np.random.randn(1000, 10)
knn = KNeighborsRegressor(n_neighbors=5)
lr = LinearRegression()
knn.fit(X, y); lr.fit(X, y)
for name, model in [('KNN', knn), ('LinearReg', lr)]:
t0 = time.time()
model.predict(X_test)
dt = (time.time() - t0) * 1000
print(f'{name}: {dt:.1f} ms for 1000 predictions')การใช้ผลลัพธ์ของ KNN ในกระบวนการทำงาน
แม้ KNN จะช้าเกินไปสำหรับการใช้งานจริงโดยตรง ระยะห่างที่ได้จาก KNN ก็สามารถใช้เป็นคุณลักษณะที่ให้ข้อมูลได้ ตัวอย่างเช่น การคำนวณระยะห่างเฉลี่ยไปยังเพื่อนบ้านฝึกที่ใกล้ที่สุดจำนวน k รายการสำหรับจุดทดสอบแต่ละจุด จะสร้างคุณลักษณะหนึ่งรายการที่วัดว่าจุดนั้นผิดแปลกเพียงใด จุดที่ผิดแปลก (อยู่ห่างจากเพื่อนบ้านมาก) อาจเป็นความผิดปกติได้ รูปแบบนี้ ซึ่งใช้ KNN เป็น ตัวสกัดคุณลักษณะแทนที่จะใช้เป็นตัวทำนายสุดท้าย ทำให้คุณนำข้อมูลจากเพื่อนบ้านใกล้ที่สุดไปใช้ภายในแบบจำลองกลุ่มที่ทำงานได้รวดเร็ว
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
X_train = np.random.randn(500, 10)
y_train = (X_train[:, 0] > 0).astype(int)
X_test = np.random.randn(50, 10)
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
# Extract neighbor distances as an anomaly score
dists, _ = knn.kneighbors(X_test)
avg_dist = dists.mean(axis=1)
print('Average neighbor distances (anomaly score):')
print(avg_dist.round(2))
# High values indicate potential anomaliesการลดจำนวนมิติก่อนใช้ KNN
เพื่อให้ KNN ใช้งานได้จริงกับข้อมูลมิติสูง ให้ใช้ PCA ก่อน KNeighborsRegressor เพื่อลดจำนวนมิติขณะยังคงรักษาความแปรปรวนส่วนใหญ่ไว้ วิธีนี้แก้ปัญหาได้พร้อมกันสองประการ: ลดเวลาทำนาย (จำนวนมิติน้อยลง = คำนวณระยะห่างได้เร็วขึ้น) และบรรเทาคำสาปแห่งมิติ (ระยะห่างมีความหมายมากขึ้นในปริภูมิที่มีมิติต่ำกว่า) การใช้ PCA + KNN ภายใน Pipeline เดียวกันช่วยให้การประมวลผลก่อนหน้าไม่มีการรั่วไหลของข้อมูลระหว่างการตรวจสอบไขว้
from sklearn.pipeline import Pipeline
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import cross_val_score
import numpy as np
X_high_d = np.random.randn(1000, 100) # 100 features
y = X_high_d[:, :5].sum(axis=1) # Only first 5 matter
pipe = Pipeline([
('sc', StandardScaler()),
('pca', PCA(n_components=10)), # Reduce to 10 components
('knn', KNeighborsRegressor(n_neighbors=5))
])
scores = -cross_val_score(pipe, X_high_d, y, cv=5,
scoring='neg_root_mean_squared_error')
print('CV RMSE with PCA:', scores.mean().round(3))ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจแนวคิด Machine Learning with Python จากบทเรียนนี้
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า การถดถอยด้วย KNN ทำนายค่าเป้าหมายต่อเนื่องด้วยการหาค่าเฉลี่ยของค่าเพื่อนบ้านอย่างไร รวมถึง ต้นทุนการทำนาย O(N * d) ที่สำคัญและจำกัดการขยายขนาดของ KNN ตลอดจน KD-Tree, Ball Tree และ FAISS ช่วยเร่งการค้นหาเพื่อนบ้านสำหรับชุดข้อมูลขนาดใหญ่ได้อย่างไร บทถัดไป เราจะสำรวจต้นไม้ตัดสินใจ ซึ่งเป็นแนวทางที่แตกต่างโดยพื้นฐานและเรียนรู้กฎอย่างชัดเจนผ่านการแบ่งข้อมูลแบบวนซ้ำ
เรียนรู้ Python ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “KNN สำหรับการถดถอยและข้อจำกัดด้านการขยายขนาด” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “KNN สำหรับการถดถอยและข้อจำกัดด้านการขยายขนาด” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Machine Learning Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “KNN สำหรับการถดถอยและข้อจำกัดด้านการขยายขนาด”
ผู้เรียนจะใช้ KNeighborsRegressor กับเป้าหมายแบบต่อเนื่อง จากนั้นวัดเวลาการพยากรณ์บนชุดข้อมูลขนาดใหญ่เพื่อเข้าใจต้นทุนการอนุมาน O(n) ของ KNN คุณปฏิบัติ Machine Learning Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Machine Learning Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Machine Learning Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “KNN สำหรับการถดถอยและข้อจำกัดด้านการขยายขนาด” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Machine Learning Academy นี้ได้ไหม
ได้ บทเรียน Machine Learning Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- KNN ทำงานอย่างไร: ระยะทาง เพื่อนบ้าน และคะแนนโหวต
- การเลือก k: วิธีข้อศอกและเส้นโค้งการตรวจสอบ
- ตัวชี้วัดระยะทาง: ยุคลิด แมนฮัตตัน และมินคอฟสกี
- KNN สำหรับการถดถอยและข้อจำกัดด้านการขยายขนาด