Pandas & NumPy Academy · บทเรียน

การประมาณค่าและการแทนค่าขั้นสูง

ใช้ interpolate() เพื่อเติมค่าตามเวลาอย่างราบรื่น และทำความเข้าใจว่าเมื่อใดควรใช้ค่าเฉลี่ยแทนค่ามัธยฐาน

บทเรียน 4 จาก 413 ขั้นตอน

การประมาณค่าและการแทนค่าขั้นสูง เป็นบทเรียน Pandas & NumPy Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Pandas & NumPy Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน

เมื่อการประมาณค่าแทรกดีกว่า fillna()

การเติมค่าไปข้างหน้าและย้อนกลับจะนำค่าที่ทราบล่าสุดหรือถัดไปมาใช้ โดยไม่พิจารณา แนวโน้มของข้อมูล การประมาณค่าแทรกจะประเมินค่าที่หายไปโดยสมมติว่าค่าระหว่างจุดที่ทราบมีการเปลี่ยนแปลงอย่างราบรื่น เช่น หากอุณหภูมิวันจันทร์อยู่ที่ 20°C และวันศุกร์อยู่ที่ 30°C การประมาณค่าแทรกจะประเมินว่าอุณหภูมิวันพุธอยู่ที่ 25°C วิธีนี้ให้ค่าที่แทนได้สมจริงกว่าสำหรับสัญญาณที่เปลี่ยนแปลงอย่างราบรื่น เช่น ข้อมูลจากเซนเซอร์ ราคา หรือจำนวนประชากร

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'day': [1, 2, 3, 4, 5],
    'temp': [20.0, np.nan, np.nan, np.nan, 30.0]
})

# Linear interpolation fills gaps smoothly
df['temp_interp'] = df['temp'].interpolate(method='linear')
print(df)
#    day  temp  temp_interp
# 0    1  20.0         20.0
# 1    2   NaN         22.5
# 2    3   NaN         25.0
# 3    4   NaN         27.5
# 4    5  30.0         30.0

เมธอด interpolate()

Pandas รองรับ เมธอดหลายรูปแบบสำหรับ interpolate() รูปแบบที่ใช้บ่อยที่สุด ได้แก่ 'linear' (เว้นระยะเท่า ๆ กันระหว่างค่าที่ทราบ), 'time' (คำนึงถึงช่วงเวลาที่ห่างไม่เท่ากันเมื่อกำหนด DatetimeIndex), 'polynomial' (ปรับเส้นโค้งพหุนาม ซึ่งต้องระบุอาร์กิวเมนต์ order) และ 'spline' (พหุนามแบบเป็นช่วงที่มีความราบรื่น) แบบเชิงเส้นเป็นค่าเริ่มต้นที่ปลอดภัยที่สุด ส่วนเมธอดลำดับสูงอาจเกิดการปรับให้เข้ากับข้อมูลมากเกินไปในช่วงว่างขนาดเล็ก

import pandas as pd
import numpy as np

s = pd.Series([0, np.nan, np.nan, 8.0])

print('linear:', s.interpolate('linear').tolist())
# [0.0, 2.6666..., 5.3333..., 8.0]

print('polynomial(2):', s.interpolate('polynomial', order=2).tolist())
# [0.0, 2.222..., 5.111..., 8.0]

การประมาณค่าแทรกแบบ time ด้วย DatetimeIndex

เมื่อ Series ของคุณมี DatetimeIndex ที่ช่วงเวลาห่างกันไม่เท่ากัน (เช่น มีเฉพาะวันทำงานและไม่มีวันหยุดสุดสัปดาห์) method='time' จะประมาณค่าแปรผันตามเวลาที่ผ่านไปจริง ไม่ใช่เพียงตามตำแหน่ง วิธีนี้แม่นยำกว่าการประมาณค่าแบบเชิงเส้น ซึ่งถือว่าแต่ละแถวมีระยะห่างเท่ากันโดยไม่สนใจช่องว่างตามปฏิทิน

import pandas as pd
import numpy as np

# Unequal gaps: Jan 1, Jan 3, Jan 10
idx = pd.to_datetime(['2024-01-01', '2024-01-03', '2024-01-10'])
s = pd.Series([100.0, np.nan, 170.0], index=idx)

# linear treats gaps as equal (position-based)
print(s.interpolate('linear').tolist())  # [100.0, 135.0, 170.0]

# time accounts for actual day count
# Jan 1 to Jan 3 = 2 days, Jan 1 to Jan 10 = 9 days
# fraction: 2/9 of the way from 100 to 170
print(s.interpolate('time').tolist())   # [100.0, 115.55..., 170.0]

การจำกัดขอบเขตการประมาณค่าแทรก

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

import pandas as pd
import numpy as np

s = pd.Series([1.0, np.nan, np.nan, np.nan, np.nan, 10.0])

# Only fill the first 2 NaN positions
filled = s.interpolate('linear', limit=2)
print(filled.tolist())
# [1.0, 2.8, 4.6, NaN, NaN, 10.0]

การเลือกใช้การแทนค่าด้วยค่าเฉลี่ยหรือค่ามัธยฐาน

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

import pandas as pd
import numpy as np

# Skewed income data with an outlier
income = pd.Series([30000, 35000, 32000, 1_000_000, np.nan])

print('Mean:  ', income.mean())    # ~274000 — pulled by outlier
print('Median:', income.median())  # ~33500 — robust choice

# Prefer median for skewed data
filled = income.fillna(income.median())
print(filled.tolist())
# [30000, 35000, 32000, 1000000, 33500.0]

แนวคิดการแทนค่าด้วย KNN

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

KNNImputer ของ Scikit-learn ทำงานร่วมกับอาร์เรย์ NumPy และ DataFrames ของ Pandas ได้โดยตรง

import pandas as pd
import numpy as np
from sklearn.impute import KNNImputer

df = pd.DataFrame({
    'age': [25, 35, np.nan, 45],
    'income': [50000, 70000, 60000, np.nan]
})

imputer = KNNImputer(n_neighbors=2)
df_imputed = pd.DataFrame(
    imputer.fit_transform(df),
    columns=df.columns
)
print(df_imputed.round(1))
#     age   income
# 0  25.0  50000.0
# 1  35.0  70000.0
# 2  30.0  60000.0   <- filled from neighbours
# 3  45.0  65000.0   <- filled from neighbours

การแทนค่าหลายรูปแบบด้วย IterativeImputer

การแทนค่าหลายรูปแบบเป็นมาตรฐานสูงสุดสำหรับการจัดการข้อมูลที่หายไปในงานวิจัยทางสถิติ IterativeImputer ของ Scikit-learn ใช้แนวทาง MICE (Multiple Imputation by Chained Equations) โดยสร้างแบบจำลองให้แต่ละคอลัมน์ที่มีค่าหายไปเป็นฟังก์ชันของคอลัมน์อื่น ๆ แล้วทำการแทนค่าซ้ำจนกว่าค่าจะลู่เข้า วิธีนี้จับความสัมพันธ์ระหว่างคุณลักษณะได้ดีกว่ากลยุทธ์ที่พิจารณาทีละคอลัมน์

import pandas as pd
import numpy as np
from sklearn.experimental import enable_iterative_imputer  # noqa
from sklearn.impute import IterativeImputer

df = pd.DataFrame({
    'x1': [1, 2, np.nan, 4, 5],
    'x2': [2, np.nan, 6, 8, 10],
    'y':  [3, 5, 7, np.nan, 11]
})

imp = IterativeImputer(max_iter=10, random_state=0)
df_filled = pd.DataFrame(imp.fit_transform(df), columns=df.columns)
print(df_filled.round(2))

คอลัมน์ตัวบ่งชี้สำหรับข้อมูลที่หายไป

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

import pandas as pd
import numpy as np

df = pd.DataFrame({'salary': [50000, np.nan, 70000, np.nan, 90000]})

# Add indicator before filling
df['salary_was_missing'] = df['salary'].isna().astype(int)

# Then fill
df['salary'] = df['salary'].fillna(df['salary'].median())
print(df)
#    salary  salary_was_missing
# 0  50000.0                   0
# 1  70000.0                   1
# 2  70000.0                   0
# 3  70000.0                   1
# 4  90000.0                   0

การแทนค่าและการรั่วไหลของข้อมูล

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

import pandas as pd
import numpy as np
from sklearn.impute import SimpleImputer
from sklearn.model_selection import train_test_split

df = pd.DataFrame({'feature': [1, 2, np.nan, 4, np.nan, 6, 7, 8]})
train, test = train_test_split(df, test_size=0.25, random_state=0)

# Fit ONLY on training data
imp = SimpleImputer(strategy='mean')
train['feature'] = imp.fit_transform(train[['feature']])

# Transform test using training statistics
test['feature'] = imp.transform(test[['feature']])
print('Train mean used:', imp.statistics_[0])

การเปรียบเทียบกลยุทธ์การแทนค่าด้วยภาพ

หลังใช้วิธีการแทนค่าหลายรูปแบบแล้ว ให้เปรียบเทียบผลกระทบด้วยการพล็อตการแจกแจงของคอลัมน์ดั้งเดิมและคอลัมน์ที่แทนค่าไว้เคียงข้างกัน การแทนค่าที่ดีควรรักษารูปร่างของการแจกแจงเดิม (ค่าเฉลี่ย ความแปรปรวน ความเบ้) ให้ใกล้เคียงที่สุด การแทนค่าด้วยค่าเฉลี่ยจะทำให้การแจกแจงแคบลง ส่วน KNN และ MICE มักรักษารูปร่างไว้ได้ดีกว่า

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)
original = np.random.exponential(scale=5, size=200)
with_nan = original.copy()
with_nan[np.random.choice(200, 40, replace=False)] = np.nan

s = pd.Series(with_nan)

fig, axes = plt.subplots(1, 2, figsize=(10, 4))
s.dropna().hist(ax=axes[0], bins=20, title='Original (no NaN)')
s.fillna(s.mean()).hist(ax=axes[1], bins=20, title='Mean-imputed')
plt.tight_layout()
plt.savefig('imputation_comparison.png')
print('Saved comparison chart')

การเลือกกลยุทธ์การแทนค่าที่เหมาะสม

ไม่มีกลยุทธ์การแทนค่าใดดีที่สุดสำหรับทุกกรณี ตัวเลือกที่เหมาะสมขึ้นอยู่กับบริบท ใช้ mean/median สำหรับกรณีตัวแปรเดียวที่เรียบง่ายและมีค่าหายไปน้อย ใช้ ffill/bfill สำหรับอนุกรมเวลาที่มีแนวโน้มคงที่ ใช้ KNN หรือ IterativeImputer เมื่อคุณลักษณะมีความสัมพันธ์กันและต้องการใช้ประโยชน์จากความสัมพันธ์เหล่านั้น ใช้ ค่าคงที่ตามบริบทของงาน (เช่น 0 สำหรับไม่มีข้อมูล, -1 สำหรับไม่ทราบค่า) เมื่อค่าที่หายไปมีความหมายทางธุรกิจที่ชัดเจน ควรบันทึกเหตุผลของตัวเลือกไว้เสมอ

# Decision guide (no runnable code)
#
# Missing < 5%  AND data is MCAR?  -> Mean/median fill is fine
# Time series with stable trend?   -> ffill() with limit
# Features are correlated?         -> KNNImputer or IterativeImputer
# Categorical column?              -> Mode fill or 'Unknown' sentinel
# Going into ML model?             -> Add indicator column + fill
# Research / publication quality?  -> Multiple imputation (MICE)
print('Strategy selected based on context')

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับการประมาณค่าแทรกและการแทนค่าขั้นสูง

สรุปบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า interpolate() จะประเมินค่าที่หายไปโดยสมมติว่ามีแนวโน้มที่ราบรื่นระหว่างค่าที่ทราบ, method='time' รองรับช่วงว่างที่ไม่เท่ากันใน DatetimeIndex และกลยุทธ์ขั้นสูงอย่าง KNNImputer และ IterativeImputer จะใช้ข้อมูลจากคอลัมน์อื่นเพื่อช่วยกำหนดค่าที่เติม ควรเพิ่ม คอลัมน์ตัวบ่งชี้ ก่อนการแทนค่าเสมอ และคำนวณสถิติจากชุดฝึกเท่านั้นเพื่อป้องกันการรั่วไหลของข้อมูล บทถัดไป เราจะตรวจสอบและแปลงชนิดข้อมูลของคอลัมน์ใน DataFrame

เริ่มต้นได้ฟรี

เรียนรู้ Python ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
30
บทเรียน
120

คำถามที่พบบ่อย

บทเรียน “การประมาณค่าและการแทนค่าขั้นสูง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การประมาณค่าและการแทนค่าขั้นสูง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Pandas & NumPy Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การประมาณค่าและการแทนค่าขั้นสูง”

ใช้ interpolate() เพื่อเติมค่าตามเวลาอย่างราบรื่น และทำความเข้าใจว่าเมื่อใดควรใช้ค่าเฉลี่ยแทนค่ามัธยฐาน คุณปฏิบัติ Pandas & NumPy Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Pandas & NumPy Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Pandas & NumPy Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การประมาณค่าและการแทนค่าขั้นสูง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Pandas & NumPy Academy นี้ได้ไหม

ได้ บทเรียน Pandas & NumPy Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การตรวจหาค่าที่หายไป
  2. การลบค่าที่หายไป
  3. การเติมค่าที่หายไป
  4. การประมาณค่าและการแทนค่าขั้นสูง
← กลับไปที่ Pandas & NumPy Academy