0Pricing
AI Agents · บทเรียน

การประมวลผลข้อมูลอนุกรมเวลาในเอเจนต์

หน้าต่างเลื่อน การรวมข้อมูล และการตรวจจับความผิดปกติในข้อมูลเซนเซอร์แบบสตรีม

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

อนุกรมเวลาใน Agent IoT

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

การประมวลผลอนุกรมเวลาจะแปลงสัญญาณดิบให้เป็นข้อมูลเชิงลึกที่นำไปดำเนินการได้

การสร้างบัฟเฟอร์หน้าต่างเลื่อน

หน้าต่างเลื่อนจะเก็บเฉพาะค่าที่อ่านได้ N รายการล่าสุดไว้ในหน่วยความจำ เมื่อหน้าต่างเต็ม ค่าที่เก่าที่สุดจะถูกนำออกเมื่อมีค่าล่าสุดเข้ามา นี่คือพื้นฐานของการวิเคราะห์อนุกรมเวลาทั้งหมดใน Agent

from collections import deque
from datetime import datetime

class SensorBuffer:
    def __init__(self, window_size: int = 60):
        self.window_size = window_size
        self._data = deque(maxlen=window_size)

    def add(self, value: float, timestamp: datetime = None):
        ts = timestamp or datetime.utcnow()
        self._data.append({'ts': ts, 'value': value})

    def values(self) -> list:
        return [d['value'] for d in self._data]

    def timestamps(self) -> list:
        return [d['ts'] for d in self._data]

    def is_full(self) -> bool:
        return len(self._data) == self.window_size

buf = SensorBuffer(window_size=60)
buf.add(22.5)
buf.add(22.8)
buf.add(23.1)
print(f'Buffer: {len(buf._data)} readings, values: {buf.values()}')

ค่าเฉลี่ยเคลื่อนที่

ค่าเฉลี่ยเคลื่อนที่อย่างง่าย (SMA) ช่วยลดสัญญาณรบกวนด้วยการหาค่าเฉลี่ยของค่า N รายการล่าสุด ซึ่งลดผลกระทบจากความผิดพลาดเฉพาะจุดของเซนเซอร์และเผยให้เห็นแนวโน้มพื้นฐาน ใช้ค่านี้เป็นเส้นฐานสำหรับการตรวจจับความผิดปกติ

import statistics

def simple_moving_average(values: list, window: int = 10) -> list:
    if len(values) < window:
        return []
    return [
        statistics.mean(values[i - window:i])
        for i in range(window, len(values) + 1)
    ]

def exponential_moving_average(values: list, alpha: float = 0.2) -> list:
    """EMA weights recent values more heavily."""
    if not values:
        return []
    ema = [values[0]]
    for v in values[1:]:
        ema.append(alpha * v + (1 - alpha) * ema[-1])
    return ema

readings = [22.1, 22.3, 22.0, 35.0, 22.2, 22.4, 22.1, 22.3, 22.5, 22.2, 22.4]
sma = simple_moving_average(readings, window=5)
ema = exponential_moving_average(readings, alpha=0.2)
print(f'SMA (last 3): {[round(v,2) for v in sma[-3:]]}')
print(f'EMA (last 3): {[round(v,2) for v in ema[-3:]]}')

การตรวจจับจุดพุ่งสูง

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

import statistics

def detect_spikes(
    values: list,
    window: int = 20,
    z_threshold: float = 3.0
) -> list:
    """Returns list of (index, value, z_score) for detected spikes."""
    if len(values) < window:
        return []

    spikes = []
    for i in range(window, len(values)):
        window_vals = values[i - window:i]
        mean = statistics.mean(window_vals)
        stdev = statistics.stdev(window_vals)
        if stdev == 0:
            continue
        z_score = abs(values[i] - mean) / stdev
        if z_score > z_threshold:
            spikes.append({
                'index': i,
                'value': values[i],
                'z_score': round(z_score, 2),
                'mean': round(mean, 2)
            })
    return spikes

data = [22.1, 22.3, 22.0, 22.2, 22.4] * 5 + [55.0] + [22.2, 22.3] * 3
spikes = detect_spikes(data, window=10, z_threshold=3.0)
print('Spikes detected:', spikes)

แพนดาสสำหรับการวิเคราะห์อนุกรมเวลา

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

import pandas as pd
from datetime import datetime, timedelta

# Create a sample time series DataFrame
base_time = datetime(2024, 1, 1, 12, 0, 0)
times = [base_time + timedelta(seconds=i*10) for i in range(20)]
values = [22.1, 22.3, None, 22.0, 22.4, 22.2, 35.0, 22.1,
          22.3, 22.2, 22.5, 22.1, None, 22.4, 22.2, 22.3,
          22.0, 22.1, 22.4, 22.2]

df = pd.DataFrame({'value': values}, index=pd.DatetimeIndex(times))
df.index.name = 'timestamp'

print('Shape:', df.shape)
print('Missing values:', df['value'].isna().sum())
print(df.head())

การจัดการการประทับเวลาที่หายไป

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

import pandas as pd

def fill_missing_readings(df: pd.DataFrame, freq: str = '10S') -> pd.DataFrame:
    """
    df: DataFrame with DatetimeIndex and 'value' column
    freq: expected sampling frequency ('10S' = 10 seconds, '1T' = 1 minute)
    """
    original_count = df['value'].notna().sum()

    # Resample to regular grid (introduces NaN for missing periods)
    df_regular = df.resample(freq).mean()

    missing_count = df_regular['value'].isna().sum()
    print(f'Missing readings before fill: {missing_count}')

    # Forward fill then linear interpolate
    df_regular['value'] = df_regular['value'].interpolate(
        method='linear', limit=5  # don't fill gaps longer than 5 periods
    )

    filled_count = df_regular['value'].notna().sum()
    print(f'Filled {filled_count - original_count} missing values')
    return df_regular

การปรับช่วงเวลาใหม่: การรวมค่าจากทุก 1 นาทีเป็นทุก 5 นาที

การปรับช่วงเวลาใหม่จะลดทอนข้อมูลความถี่สูงให้มีความละเอียดหยาบลง ซึ่งช่วยลดสัญญาณรบกวนและความต้องการพื้นที่จัดเก็บ ใช้ resample('5T').agg() เพื่อคำนวณค่าต่ำสุด ค่าสูงสุด mean และส่วนเบี่ยงเบนมาตรฐานในแต่ละหน้าต่าง 5 นาที

import pandas as pd

def resample_to_5min(df: pd.DataFrame) -> pd.DataFrame:
    return df.resample('5min').agg({
        'value': ['mean', 'min', 'max', 'std', 'count']
    }).round(3)

# Example with 1-minute data:
times = pd.date_range('2024-01-01 12:00', periods=30, freq='1min')
import random
random.seed(42)
vals = [22.0 + random.gauss(0, 0.5) for _ in range(30)]
df_1min = pd.DataFrame({'value': vals}, index=times)

df_5min = resample_to_5min(df_1min)
print(df_5min)

การตรวจจับแนวโน้มด้วยการถดถอยเชิงเส้น

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

def detect_trend(
    values: list,
    slope_threshold: float = 0.1  # units per second
) -> dict:
    import statistics
    n = len(values)
    if n < 2:
        return {'trend': 'insufficient_data'}

    x = list(range(n))
    x_mean = statistics.mean(x)
    y_mean = statistics.mean(values)

    numerator = sum((xi - x_mean) * (yi - y_mean) for xi, yi in zip(x, values))
    denominator = sum((xi - x_mean) ** 2 for xi in x)
    slope = numerator / denominator if denominator != 0 else 0.0

    return {
        'slope': round(slope, 4),
        'trend': 'rising' if slope > slope_threshold
                 else 'falling' if slope < -slope_threshold
                 else 'stable',
        'alert': abs(slope) > slope_threshold * 2
    }

readings = [22.0, 22.5, 23.0, 23.5, 24.0, 24.5, 25.0]
print(detect_trend(readings, slope_threshold=0.3))

การตัดสินใจของ Agent จากอนุกรมเวลา

ผสานการตรวจจับจุดพุ่งสูง การตรวจจับแนวโน้ม และค่าเฉลี่ยเคลื่อนที่เข้าด้วยกันเพื่อสร้างการตัดสินใจแบบผสม Agent ใช้ลำดับชั้นของกฎดังนี้: จุดพุ่งสูงจะเรียกใช้การดำเนินการทันที แนวโน้มจะเรียกใช้คำเตือน และ LLM จะจัดการกรณีที่ไม่ชัดเจน

def analyze_sensor_window(
    values: list,
    topic: str
) -> dict:
    if len(values) < 10:
        return {'action': 'collecting_data'}

    spikes = detect_spikes(values, window=10, z_threshold=3.0)
    trend_info = detect_trend(values[-20:], slope_threshold=0.2)
    avg = sum(values[-10:]) / 10

    if spikes:
        return {
            'action': 'IMMEDIATE_ALERT',
            'reason': f'Spike detected: {spikes[-1]["value"]} (z={spikes[-1]["z_score"]})',
            'severity': 'high'
        }
    if trend_info['alert']:
        return {
            'action': 'TREND_WARNING',
            'reason': f'Rapid {trend_info["trend"]} trend: slope={trend_info["slope"]}',
            'severity': 'medium'
        }
    return {
        'action': 'NORMAL',
        'avg_last_10': round(avg, 2),
        'trend': trend_info['trend']
    }

result = analyze_sensor_window([22.0]*15 + [55.0], 'sensors/temp')
print(result)

การบันทึกอนุกรมเวลาลงฐานข้อมูล

สำหรับการวิเคราะห์ระยะยาว ให้บันทึกค่าที่อ่านได้จากเซนเซอร์ลงในฐานข้อมูลอนุกรมเวลา TimescaleDB (ส่วนขยายของ PostgreSQL) และ InfluxDB เป็นตัวเลือกยอดนิยม การใช้ psycopg2 ร่วมกับ TimescaleDB ช่วยให้คุณสืบค้นข้อมูลด้วย SQL มาตรฐาน รวมถึงฟังก์ชันเฉพาะสำหรับเวลา

import psycopg2
from datetime import datetime

# TimescaleDB connection (standard PostgreSQL connection)
conn = psycopg2.connect(
    host='localhost', port=5432, dbname='iot',
    user='agent', password='YOUR_DB_PASSWORD'
)

def insert_reading(topic: str, value: float, ts: datetime = None):
    ts = ts or datetime.utcnow()
    with conn.cursor() as cur:
        cur.execute(
            'INSERT INTO sensor_readings (time, topic, value) VALUES (%s, %s, %s)',
            (ts, topic, value)
        )
    conn.commit()

def query_last_hour(topic: str) -> list:
    with conn.cursor() as cur:
        cur.execute(
            'SELECT time, value FROM sensor_readings '
            'WHERE topic=%s AND time > NOW() - INTERVAL \'1 hour\' '
            'ORDER BY time ASC',
            (topic,)
        )
        return cur.fetchall()

ระยะพักการแจ้งเตือน

หากไม่มีระยะพัก ความผิดปกติที่เกิดขึ้นต่อเนื่องอาจทำให้เกิดการแจ้งเตือนหลายร้อยครั้งต่อนาที ให้ใช้ระยะพักแยกตามหัวข้อ: เมื่อส่งการแจ้งเตือนสำหรับหัวข้อหนึ่งแล้ว ให้ระงับการแจ้งเตือนเพิ่มเติมของหัวข้อนั้นเป็นเวลา N วินาที

from datetime import datetime, timedelta

class AlertCooldownManager:
    def __init__(self, cooldown_seconds: int = 300):
        self.cooldown_seconds = cooldown_seconds
        self._last_alert: dict = {}  # topic -> last alert datetime

    def should_alert(self, topic: str) -> bool:
        last = self._last_alert.get(topic)
        if last is None:
            return True
        return (datetime.utcnow() - last).seconds >= self.cooldown_seconds

    def mark_alerted(self, topic: str):
        self._last_alert[topic] = datetime.utcnow()

    def cooldown_remaining(self, topic: str) -> int:
        last = self._last_alert.get(topic)
        if last is None:
            return 0
        elapsed = (datetime.utcnow() - last).seconds
        return max(0, self.cooldown_seconds - elapsed)

cooldown = AlertCooldownManager(cooldown_seconds=300)
if cooldown.should_alert('sensors/temperature'):
    print('Sending alert')
    cooldown.mark_alerted('sensors/temperature')
else:
    print(f'Cooldown: {cooldown.cooldown_remaining("sensors/temperature")}s remaining')

ตรวจสอบความรู้

คะแนน z ที่สูงกว่า 3.0 บ่งชี้อะไรเมื่อใช้ตรวจจับจุดพุ่งสูง?

ทบทวน: การประมวลผลข้อมูลอนุกรมเวลา

คุณได้เรียนรู้ชุดเครื่องมือประมวลผลอนุกรมเวลาสำหรับ Agent อย่างครบถ้วน:

  • บัฟเฟอร์หน้าต่างเลื่อน: คิวสองด้านที่กำหนดความยาวสูงสุดเพื่อใช้หน่วยความจำอย่างมีประสิทธิภาพในการประมวลผลสตรีม
  • ค่าเฉลี่ยเคลื่อนที่: SMA และ EMA เพื่อลดสัญญาณรบกวน
  • การตรวจจับจุดพุ่งสูง: วิธีคะแนน z โดยอ้างอิงสถิติของหน้าต่างเลื่อน
  • แพนดาส: resample, interpolate และการรวมค่าด้วย DatetimeIndex
  • การตรวจจับแนวโน้ม: ความชันจากการถดถอยเชิงเส้นเพื่อแจ้งเตือนล่วงหน้า
  • ระยะพักการแจ้งเตือน: ระงับการแจ้งเตือนซ้ำสำหรับความผิดปกติที่เกิดขึ้นต่อเนื่อง

ถัดไป: การตอบสนองอัตโนมัติของ Agent ต่อเหตุการณ์จากเซนเซอร์ — คิวการดำเนินการ การขจัดรายการซ้ำ และนโยบายการดำเนินการ

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

บทเรียน “การประมวลผลข้อมูลอนุกรมเวลาในเอเจนต์” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “การประมวลผลข้อมูลอนุกรมเวลาในเอเจนต์”

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

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

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

บทเรียน “การประมวลผลข้อมูลอนุกรมเวลาในเอเจนต์” ใช้เวลานานแค่ไหน

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

ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม

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

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

  1. โพรโทคอล MQTT สำหรับการผสานเอเจนต์
  2. การประมวลผลข้อมูลอนุกรมเวลาในเอเจนต์
  3. การตอบสนองอัตโนมัติต่อเหตุการณ์จากเซนเซอร์
  4. การนำเอเจนต์น้ำหนักเบาไปใช้งานที่เอดจ์
← กลับไปที่ AI Agents