ailiteracynepal 🇳🇵
पाठ आकार

अध्याय २ · खण्ड III · 30 मिनेट

कार्यगत उदाहरण: यो SMS स्प्याम हो?

अध्याय 2 को पहिलो वास्तविक परियोजना। SMS सन्देशहरूको फोल्डर लिनुहोस् — केही स्प्याम, केही वैध — नयाँ सन्देश फ्ल्याग गर्न सक्ने वर्गीकरणकर्ता तालिम दिनुहोस् अचम्मलाग्दो शुद्धतासँग। पाठ फिचर, तालिम, मूल्याङ्कन, र नेपाली SMS बारे सानो टिप्पणी ओगट्छ।

तपाईंले यो अध्यायमा तीन वर्गीकरणकर्ता भेट्नुभयो। अब हामी वास्तविक समस्यामा तिनको प्रयोग गर्छौँ — तपाईंले हप्ता-अन्तमा बनाउन र आफ्नै फोनमा वास्तवमा तैनात गर्न सक्ने प्रकारको सानो एआई औजार। कार्य: SMS दिइयो, यो स्प्याम हो कि निर्णय गर्नुहोस्। डाटासेट सानो छ (लगभग 5,500 सन्देश)। फिचर पाठ आफैबाट आउँछन्। यो खण्डको अन्त्यसम्ममा तपाईंसँग काम गर्ने स्प्याम वर्गीकरणकर्ता र पाठ कसरी मेसिन-लर्निङ फिचर बन्छ भन्ने स्पष्ट तस्बिर हुनेछ।

डाटासेट

क्लासिक शिक्षण डाटासेट SMS Spam Collection हो — लगभग 5,572 अङ्ग्रेजी SMS सन्देश, प्रत्येक ham (स्प्याम नभएको) वा spam लेबल गरिएको। करिब 13% स्प्याम छन्। यो Kaggle, UCI Machine Learning Repository, र दर्जनौं अन्य ठाउँमा उपलब्ध छ; sms spam collection csv खोज्नुहोस्।

data/raw/sms_spam.csv का रूपमा बचाउनुहोस्। ढाँचा प्रति पङ्क्ति एक सन्देश हो, दुई स्तम्भसहित: labelmessage

label,message
ham,"Hey, are we still on for chiya at 5?"
spam,"FREE entry in our weekly competition to win Rs 50000! Text WIN to 90909 to enter."
ham,"Don't forget the meeting tomorrow at 10am."

नेपाली-सन्दर्भ संस्करणका लागि, तपाईं आफ्नै फोनबाट लगभग 200 स्प्याम र 800 ham सङ्कलन गरेर आफ्नै मिश्रित नेपाली/अङ्ग्रेजी SMS को सानो डाटासेट पनि बनाउन सक्नुहुन्छ (जसबाट सङ्कलन गर्नुभयो तिनको सहमतिसँग, अवश्य; Course 02 अध्याय 6 हेर्नुहोस्)। सिद्धान्त समान छन्; तालिम प्राप्त मोडेलले केवल तपाईंको स्थानीय ढाँचाबाट सिक्छ।

लोड र हेराइ

import pandas as pd

df = pd.read_csv("data/raw/sms_spam.csv", encoding="latin-1")
print(df.shape)
print(df.head())
print()
print(df["label"].value_counts())
print(df["label"].value_counts(normalize=True))

तपाईंले यस्तै देख्नुहुनेछ:

(5572, 2)
       label                                            message
0        ham  Go until jurong point, crazy.. Available only ...
1        ham                      Ok lar... Joking wif u oni...
2       spam  Free entry in 2 a wkly comp to win FA Cup fina...
3        ham  U dun say so early hor... U c already then say...
4        ham  Nah I don't think he goes to usf, he lives aro...

ham     4825
spam     747
Name: label, dtype: int64

13% स्प्याम। हल्का असन्तुलित, तर काम गर्न मिल्ने। .head(20) सँग जाँच्नुहोस् र केही स्प्याम र ham सन्देश हेर्नुहोस्। स्प्याम प्रायः:

  • सबै क्याप वा अनौठो ठाउँमा मिश्रित क्याप।
  • FREE, WIN, इनाम, ठूला रकमको उल्लेख।
  • पाठ पठाउने वा कल गर्ने नम्बर।

यी सहज ज्ञान हुन्। मोडेलले तिनलाई — र थप — स्वचालित रूपमा पत्ता लगाउनेछ।

पाठलाई फिचरमा बदल्ने: bag-of-words

मोडेलले सङ्ख्या खान्छ। SMS सन्देश पाठ हुन्। हामीलाई हरेक सन्देशलाई सङ्ख्यात्मक भेक्टरमा बदल्ने तरिका चाहिन्छ। सबैभन्दा सरल दृष्टिकोण — अचम्मलाग्दो प्रभावकारी — bag-of-words हो।

हरेक सन्देशका लागि, हरेक शब्द कति पटक देखापर्छ गन्नुहोस्। अनि सन्देश भेक्टर हो जहाँ प्रत्येक स्थान एक शब्दसँग मेल खान्छ र मान त्यो सन्देशमा त्यो शब्दको गन्ती हो। पूरै डाटासेट प्रति सन्देश एक पङ्क्ति र शब्दावलीमा प्रति शब्द एक स्तम्भ भएको मेट्रिक्स बन्छ।

scikit-learn ले यो CountVectorizer सँग गर्छ:

from sklearn.feature_extraction.text import CountVectorizer

vectorizer = CountVectorizer()
X_counts = vectorizer.fit_transform(df["message"])
print(X_counts.shape)   # (5572, ~8700)
print(vectorizer.get_feature_names_out()[:20])

मेट्रिक्स sparse छ — अधिकांश सन्देशमा 8,700-शब्दको शब्दावलीबाट मुट्ठीभर शब्द मात्र हुन्छन्, त्यसैले झन्डै हरेक प्रविष्टि शून्य हो। scikit-learn ले यसलाई कुशलतापूर्वक सम्हाल्छ।

नजिकको आफन्त TfidfVectorizer हो, जसले गन्तीलाई डाटासेटभर हरेक शब्द कति सूचनात्मक छ भन्ने आधारमा तौल दिन्छ। “the” जस्ता सामान्य शब्दलाई तल-तौल दिइन्छ; “WIN” जस्ता दुर्लभ शब्दलाई माथि-तौल दिइन्छ। स्प्याम पत्ता लगाउनका लागि, TF-IDF ले प्रायः कच्चा गन्ती हराउँछ:

from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer(
    lowercase=True,
    stop_words="english",
    max_features=5000,
    ngram_range=(1, 2),   # शब्द र क्रमिक शब्दहरूको जोडा
)

ती आर्गुमेन्टहरूमध्ये केही बुझ्न लायक:

  • lowercase=True — “FREE” र “free” उही टोकनका रूपमा व्यवहार गरिन्छ।
  • stop_words="english" — “the”, “is”, “and” जस्ता सामान्य शब्द हटाइन्छन्। तिनले थोरै सङ्केत बोक्छन्।
  • max_features=5000 — केवल 5000 सबैभन्दा प्रायः देखिने शब्द राख्नुहोस्। मेट्रिक्सलाई सम्हाल्न मिल्ने राख्छ।
  • ngram_range=(1, 2) — व्यक्तिगत शब्द र क्रमिक शब्दका जोडा दुवै समावेश गर्नुहोस्। “win cash” जोडाका रूपमा “win” र “cash” अलग-अलग भन्दा बढी सूचनात्मक छ।

वर्गीकरणकर्ता तालिम दिने

मानक पाइपलाइन:

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.metrics import classification_report, confusion_matrix

X = df["message"]
y = (df["label"] == "spam").astype(int)   # स्प्यामका लागि 1, ham का लागि 0

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=42,
)

model = Pipeline([
    ("tfidf", TfidfVectorizer(
        lowercase=True,
        stop_words="english",
        max_features=5000,
        ngram_range=(1, 2),
    )),
    ("classifier", LogisticRegression(max_iter=1000, class_weight="balanced")),
])

model.fit(X_train, y_train)
predictions = model.predict(X_test)

print(classification_report(y_test, predictions, target_names=["ham", "spam"]))
print(confusion_matrix(y_test, predictions))

आउटपुट (चित्रात्मक — तपाईंको अलिकति फरक हुनेछ):

              precision    recall  f1-score   support

         ham       0.99      0.99      0.99       965
        spam       0.94      0.93      0.93       150

    accuracy                           0.98      1115
   macro avg       0.97      0.96      0.96      1115
weighted avg       0.98      0.98      0.98      1115

[[955  10]
 [ 11 139]]

confusion मेट्रिक्स पढ्नुहोस्:

  • 955 वास्तविक ham (सही रूपमा ham लेबल गरिएको)। ठूलो diagonal।
  • 139 वास्तविक स्प्याम (सही रूपमा स्प्याम लेबल गरिएको)। अर्को diagonal।
  • 10 ham स्प्यामका रूपमा गलत वर्गीकरण। झुटो अलार्म — कष्टकर तर सहनयोग्य।
  • 11 स्प्याम ham का रूपमा गलत वर्गीकरण। वास्तविक स्प्याम पास भयो। केही अनुप्रयोगमा कम सहनयोग्य।

98% शुद्धता, स्प्याममा 93% recall। एक-दिनको परियोजनाका लागि, यो काम गर्ने औजार हो।

मोडेलले के सिक्यो पढ्ने

Pipeline को वर्गीकरणकर्ता लोजिस्टिक रिग्रेसन हो, त्यसैले हामी यसका भार पढ्न सक्छौं — र तिनी “स्प्याम सङ्केत गर्ने शब्द (उच्च सकारात्मक भार) र ham सङ्केत गर्ने शब्द (उच्च नकारात्मक भार)” का रूपमा व्याख्यायोग्य छन्:

import numpy as np

vectorizer = model.named_steps["tfidf"]
classifier = model.named_steps["classifier"]

vocab = vectorizer.get_feature_names_out()
weights = classifier.coef_[0]

# शीर्ष 10 स्प्याम-सङ्केत गर्ने शब्द/bigrams
top_spam_idx = np.argsort(weights)[-10:][::-1]
print("Top spam indicators:")
for i in top_spam_idx:
    print(f"  {vocab[i]:30s} {weights[i]:+.2f}")

print()

# शीर्ष 10 ham-सङ्केत गर्ने शब्द/bigrams
top_ham_idx = np.argsort(weights)[:10]
print("Top ham indicators:")
for i in top_ham_idx:
    print(f"  {vocab[i]:30s} {weights[i]:+.2f}")

तपाईंले classics देख्नुहुनेछ: स्प्याम फिचरमा txt, free, claim, urgent, win, prize, call now समावेश छन्। Ham फिचरमा home, meet, tonight, okay, lol समावेश छन्। यी पढ्नु सबैभन्दा रमाइलो ML अनुभवमध्ये एक हो — मोडेलले स्प्यामको भाषा र साथीहरूको भाषा सिकेको छ, र यसले तपाईंलाई दुवै देखाउन सक्छ।

आफ्ना सन्देशमा प्रयास

तालिम प्राप्त मोडेल बचाउनुहोस् र अन्तरक्रियात्मक रूपमा प्रयोग गर्नुहोस्:

import joblib
joblib.dump(model, "spam_classifier.joblib")

# पछि, अर्को स्क्रिप्टमा:
model = joblib.load("spam_classifier.joblib")

while True:
    msg = input("Message: ")
    if not msg:
        break
    proba = model.predict_proba([msg])[0]
    print(f"  ham: {proba[0]:.2f}  spam: {proba[1]:.2f}")

केही सन्देश टाइप गर्नुहोस्। गत हप्ताको आफ्नो मन पर्ने स्प्याम SMS टाइप गर्नुहोस्। साथीबाट सामान्य सन्देश टाइप गर्नुहोस्। मोडेलले सम्भावना असाइन गर्दै हेर्नुहोस्। यो त्यो क्षण हो जब एआई अमूर्तता हुन छाड्छ।

नेपाली SMS बारे टिप्पणी

अङ्ग्रेजी SMS Spam Collection शिक्षण डाटासेटका रूपमा राम्रोसँग काम गर्छ, तर वास्तविक नेपाली फोनले मिश्रित नेपाली/अङ्ग्रेजी/रोमन-लिखित नेपाली स्प्याम पाउँछन् — र तालिम प्राप्त मोडेल तिनमा सामान्यीकरण गर्न सक्दैन।

दुई व्यवहारिक बाटो:

  1. आफ्नै नेपाली SMS डाटासेट सङ्कलन गर्नुहोस्। दुई सय लेबल गरिएको उदाहरण सानो परियोजनाका लागि पर्याप्त छन्; हामी अध्याय 5 मा साना-डाटा तालिम चालहरू ओगट्नेछौं।
  2. बहुभाषी embedding-आधारित दृष्टिकोण प्रयोग गर्नुहोस् (Course 04 मा, जब हामी sentence embeddings भेट्छौं) — अङ्ग्रेजी, नेपाली, र रोमन-लिखित नेपालीलाई अन्तर-बदलनीय रूपमा सम्हाल्ने मोडेल।

अहिलेलाई, अङ्ग्रेजी संस्करणले प्रविधि सिकाउँछ। यसलाई नेपालीमा सामान्यीकरण गर्नु अध्याय 6 परियोजना हो जुन हुन प्रतीक्षा गर्दैछ।

आफ्नो बुझाइ जाँच्नुहोस्

Quick check

एक टिम सदस्यले `class_weight='balanced'` बिना स्प्याम वर्गीकरणकर्ता तालिम दिन खोज्छन् र 87% शुद्धता रिपोर्ट गर्छन्। तिनले काम गरिरहेको दाबी गर्छन्। confusion मेट्रिक्स हेर्दा, तिनले नोट गर्छन् 0 सन्देश स्प्याम पूर्वानुमान गरिएका थिए। के भइरहेको छ, र उपचार के हो?

Quick check

एक साथीले अङ्ग्रेजी SMS मा स्प्याम वर्गीकरणकर्ता तालिम दिए र नेपाली फोनमा तैनात गर्दैछन् जहाँ सन्देश नेपाली, अङ्ग्रेजी, र रोमन-लिखित नेपाली मिसाउँछन्। शुद्धता बिग्रन्छ। यो खण्ड र Course 02 मा भर पर्दै, सबैभन्दा विचारशील पहिलो प्रतिक्रिया के हो?

अब के आउँछ

अध्याय 2 सकियो। तपाईंले ऋण वर्गीकरण गर्नुभयो, तीन फरक एल्गोरिथम प्रयोग गर्नुभयो, र सुरुदेखि वास्तविक स्प्याम वर्गीकरणकर्ता बनाउनुभयो। अध्याय 3 ले वर्गीकरणलाई रिग्रेसन — श्रेणीको सट्टा सङ्ख्या पूर्वानुमान गर्ने — सँग साट्छ। कार्य गरिएको उदाहरण काठमाडौंका घर भाडा हुनेछ, र बाटोमा हामी रेखीय रिग्रेसन वास्तवमा के हो, कहिले पर्याप्त छ, र कहिले तपाईंलाई अझ लचिलो केही चाहिन्छ हेर्नेछौं।