Advertisement
Guest User

Untitled

a guest
Oct 19th, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.85 KB | None | 0 0
  1. """
  2. Домашнее задание №3
  3.  
  4. Реализуйте n-граммную языковую модель, которая сможет отделить
  5. истинные предложения от полученных искусственным способом.
  6.  
  7. Если вы сомневаетесь, что можно использовать, а что нельзя -- спросите преподавателей.
  8.  
  9. После того, как побиты бейзлайны, или если подходит к концу срок сдачи,
  10. нужно привести код в порядок и отправить его преподавателям через сайт как файл
  11. (НЕ как ссылку на gist/whatever), убедившись в воспроизводимости результата на лидерборде.
  12.  
  13. В этом задании можно также уточнить у преподавателей в канале в слаке,
  14. побили ли вы бейзлайны "на привате", если уже побили их "на паблике".
  15.  
  16. CSC, NLP-2019
  17.  
  18. """
  19.  
  20. from collections import defaultdict
  21.  
  22. import numpy as np
  23. import pandas as pd
  24. from sklearn.feature_extraction.text import CountVectorizer
  25.  
  26.  
  27. class LanguageModel(object):
  28.     """
  29.        n-граммная модель.
  30.        Можно расширять и улучшать её любыми трюками, рассказанными на лекции.
  31.    """
  32.  
  33.     def __init__(self, ngram_size=3):
  34.  
  35.         if ngram_size < 2:
  36.             raise Exception
  37.  
  38.         # какого размера нграммы, параметр модели
  39.         self.ngram_size = ngram_size
  40.  
  41.         self.koefs_ngram = {}
  42.         self.D = 0.75
  43.         self.alpha = 0.045
  44.        
  45.         # простой способ из коробки построить нграммы
  46.         self.vectorizer = CountVectorizer(ngram_range=(2, ngram_size))
  47.         #print(self.vectorizer)
  48.  
  49.         # простой способ из коробки построить контексты (то, на что будем делить при оценке вероятности)
  50.         self.context_vectorizer = CountVectorizer(ngram_range=(2 - 1, ngram_size - 1))
  51.         self.ngram_counts = defaultdict(lambda: -np.inf)
  52.         self.words_set_size = None
  53.  
  54.        
  55.     def get_koef(self, ngram, curr_word):
  56.         if (self.koefs_ngram.get(ngram)):
  57.             return self.koefs_ngram[ngram];
  58.        
  59.         ngram_array  = ngram.split(" ")                
  60.         if (len(ngram_array)==1):
  61.             return self.sum_context[self.context_vectorizer.vocabulary_[ngram]] / self.words_set_size
  62.        
  63.         k1 = self.sum_context[self.context_vectorizer.vocabulary_[ngram]]
  64.         k2 = 0
  65.        
  66.         for ng in self.vectorizer.vocabulary_.keys():
  67.             ng_array = ng.split(" ")
  68.            
  69.             if (len(ng_array) == len(ngram_array) +1 and ng_array[:-1] == ngram_array):
  70.                 k2+=1
  71.         s = " ".join(ngram.split(" ")[1:] + curr_word.split(" "))
  72.         return k2*self.D*self.ngram_counts[s]/k1
  73.        
  74.     def fit(self, sentences: list):
  75.         """
  76.            Обучение модели на тексте, разбитом на предложения
  77.            :param sentences: список предложений
  78.        """
  79.  
  80.         print("Fitting sentences")
  81.  
  82.         # матрица счётчиков нграмм
  83.         counts_matrix = self.vectorizer.fit_transform(sentences)
  84.         #print("counts_matrix",counts_matrix)
  85.         # ...и контекстов
  86.         counts_context_matrix = self.context_vectorizer.fit_transform(sentences)
  87.         #print("counts_context_matrix",counts_context_matrix)
  88.        
  89.         # сколько всего слов
  90.         self.words_set_size = len(
  91.             set([key for ngram in self.vectorizer.vocabulary_.keys() for key in ngram.split(" ")]))
  92.  
  93.         print("Summing...")
  94.  
  95.         # считаем количество нграмм и контекстов -- просто суммируя все столбцы
  96.         # Count(x1,x2,...xn)
  97.         self.sum_ngram = np.sum(counts_matrix, axis=0).A1
  98.         #print(sum_ngram)
  99.        
  100.         # Count(x1,x2,...x_{n-1})
  101.         self.sum_context = np.sum(counts_context_matrix, axis=0).A1
  102.         #print(sum_context)
  103.  
  104.        
  105.         print("shapes: ", self.sum_ngram.shape, self.sum_context.shape)
  106.         print("Iterating through ngrams...")
  107.         count = 0
  108.  
  109.         for ngram in self.vectorizer.vocabulary_:
  110.             # строим контекст, откидывая последнее слово
  111.             words = " ".join(ngram.split(" ")[:-1])
  112.             #print(ngram)
  113.  
  114.             # сколько  нграмм = ngram
  115.             # hint: используйте sum_ngram
  116.             #print(ngram, sum_ngram[self.vectorizer.vocabulary_[ngram]])
  117.             # TODO: your code here
  118.             total = self.sum_ngram[self.vectorizer.vocabulary_[ngram]]
  119.  
  120.             # сколько контекстов = words
  121.             # hint: используйте sum_context
  122.             #print("sum_context",sum_context[words].sum())
  123.             # TODO: your code here
  124.             total_ctx = self.sum_context[self.context_vectorizer.vocabulary_[words]]
  125.  
  126.             # вычисляем логарифм вероятности нграммы ngram
  127.             # TODO: your code here
  128.             prob = max(total-self.D,0.0)/total_ctx + self.get_koef(words,ngram.split(" ")[-1])
  129.             #print(self.get_koef(words,ngram.split(" ")[-1]))
  130.            
  131.             # обновляем хранилище
  132.             self.ngram_counts[ngram] = prob
  133.             count += 1
  134.             #print(ngram)
  135.             if (count % 1000 == 0):
  136.                 print(count, " of ", self.sum_ngram.shape)
  137.  
  138.         # логарифмированная вероятность ДЛЯ НЕИЗВЕСТНЫХ НГРАММ
  139.         # TODO: your code here
  140.         self.ngram_counts.default_factory = lambda: 0.000001 #np.log2(0.045 / (0.045*self.words_set_size))
  141.  
  142.         return self
  143.  
  144.     def __log_prob_sentence(self, sentence: str):
  145.         """
  146.            Оцениваем логарифм вероятности предложения частотами в рамках данной модели
  147.        :param sentence:
  148.        :return:
  149.        """
  150.  
  151.         # бьём на токены
  152.         splitted = sentence.split(" ")
  153.         sum_log = 1.0
  154.  
  155.         for i in range(len(splitted) - self.ngram_size + 1):
  156.             # берём очередную нграмму
  157.             ngram = " ".join(splitted[i: i + self.ngram_size])
  158.  
  159.             # если не видели, возвращаем "логарифм нуля"
  160.             # иначе складываем логарифмы вероятностей
  161.             sum_log += np.log2(self.ngram_counts[ngram])
  162.  
  163.         return sum_log
  164.  
  165.     def log_prob(self, sentence_list: list):
  166.         """
  167.            Логарифм вероятности каждого из предложений в списке
  168.        """
  169.         return list(map(lambda x: self.__log_prob_sentence(x), sentence_list))
  170.  
  171.  
  172. df_train = pd.read_csv("train.tsv", sep='\t') #.head(15)
  173. df_test = pd.read_csv("task.tsv", sep='\t')
  174.  
  175. #print(df_train)
  176.  
  177. print("Read ", df_train.shape, df_test.shape)
  178.  
  179. basic_lm = LanguageModel()
  180.  
  181. sentences_train = df_train["text"].tolist()
  182. basic_lm.fit(sentences=sentences_train)
  183.  
  184. print("Trained")
  185.  
  186. test1, test2 = df_test["text1"], df_test["text2"]
  187.  
  188. logprob1, logprob2 = np.array(basic_lm.log_prob(test1)), np.array(basic_lm.log_prob(test2))
  189.  
  190. res = pd.DataFrame()
  191. res["id"] = df_test["id"]
  192. res["which"] = 0
  193.  
  194. res.loc[logprob2 >= logprob1, ["which"]] = 1
  195.  
  196. res.to_csv("submission.csv", sep=",", index=None, columns=["id", "which"])
  197. print("Done")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement