• בלוג
  • בגרות באנגלית: חלק שני

בגרות באנגלית: חלק שני

18/04/2021

בניסוי אתמול ראינו איך להוריד שאלוני בגרות באנגלית מהרשת ולשמור אותם על המחשב וגם להוציא את הטקסט מתוכם ולגלות סטטיסטיקה מעניינת על הטקסט באמצעות תוכנית פייתון.

היום אני רוצה להמשיך את הניסוי כדי ללמוד עוד כמה דברים על פיתון ועבודה עם טקסטים, ולקבל מידע יותר אמין על איזה מילים כדאי ללמוד לבגרות באנגלית.

אם לקחתם את הקוד אתמול ואולי ניסיתם להדפיס חלק מהמילים יכולתם לגלות שהמילים house ו houses נספרות כשתי מילים שונות, וכך גם go, goes ו going. בנוסף אולי שמתם לב ששמות כמו George, Bill ו Jane נספרו בתור מילים.

בואו נתקן את שתי הבעיות בעזרת ספריית nltk.

ספריית nltk או Natural Language Toolkit כוללת אינסוף פונקציות שעוזרות לנו לעבוד עם טקסטים בצורה נקיה ומאפשרת גישה לאינספור משאבים טקסטואלים שאפשר להתאמן עליהם כשכותבים תוכניות לניתוח שפה. אנחנו נשתמש בשתי יכולות של הספריה:

  1. היכולת לבצע Stemming למילה, כלומר לקחת את המילים house ו houses, להבין שזו אותה מילה ולהחזיר את הצורה המקורית של המילה - house.

  2. מאגר השמות הפרטיים שמגיע בתוך הספריה שיאפשר לנו לזהות האם מילה מסוימת היא שם פרטי.

את הספריה מתקינים עם:

pip install nltk

ובתוך התוכנית נשתמש בה עם ה import-ים הבאים:

from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
import nltk.corpus

נתחיל עם מאגר השמות. הקוד הבא שומר במשתנה all_names קבוצה של כל השמות שמופיעים במאגר של nltk:

names = nltk.corpus.names

all_names = set(names.words('male.txt') + names.words('female.txt'))

לפני שנוכל להריץ אותו נצטרך להתקין את מאגר השמות באמצעות כתיבה והרצת התוכנית הבאה:

import nltk
nltk.download('names')

בחזרה לקוד שלנו, החלק השני של התוכנית יהיה להשתמש בפונקציית stem כדי לזהות הטיות של מילה. הקוד הבא ממחיש את השימוש בפונקציה:

# import these modules
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize

ps = PorterStemmer()

# choose some words to be stemmed
words = ["program", "programs", "programer", "programing", "programers"]

for w in words:
    print(w, " : ", ps.stem(w))

התוצאה של כל ההדפסות היא המילה program.

התוכנית שלי אחרי עדכון נראית כך:

import requests, textract, re, os.path
from functools import reduce
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
import nltk.corpus

names = nltk.corpus.names

all_names = set(names.words('male.txt') + names.words('female.txt'))

index_url = 'https://meyda.education.gov.il/bagmgr/Ajax.ashx?search=1&sheelon=&miktzoa=16&safa=1&pagesize=10&page=1'

r = requests.get(index_url)
urls = [q["question"] for q in r.json()]
total_words = {}
ps = PorterStemmer()

s = requests.Session()
for url in urls:
    m = re.search(r'([^/]+\.pdf)', url)
    if m is None: continue

    filename = m[0]
    if not os.path.isfile(filename):
        r = s.get(url)

        with open(filename, 'wb') as f:
            f.write(r.content)

    text = textract.process(filename).decode('utf8')
    words = [
            ps.stem(w.lower()) for w in re.findall(r'\b[a-zA-Z_]+\b', text)
            if w not in all_names
            ]
    print(f"Test {filename} has {len(words)} different words")
    total_words[filename] = set(words)

all_words = reduce(lambda acc, val: acc | val, total_words.values())
print(f"All tests had a total of {len(all_words)} different words")