Эксперимент с "цепями Маркова"
На днях решил поиграть с цепями маркова и посмотреть, что из этого выйдет. Надо сказать, что получилось очень забавно.
Не так давно, я решил поближе познакомиться с Golang и поэкспериментировать, вот, что из этого получилось. Я использовал готовый пакет который имплементирует алгоритм Цепей Маркова и пакет Colly для того, чтобы парсить новостные заголовки на Медузе.
Результат местами получился очень смешной, например:
Steam отказался выпускать игру Rape Day, в которой Агата Кристи пишет про Иуду, а Джоан Роулинг — про приключения китайского воина
Французские тюремщики объявили забастовку после видеоповтора в добавленное время
Telegram призвал пользователей выйти на митинг против изоляции российского экономиста Евгения Калинина. Его задержали в Афинах по запросу Украины
«Это был первый фильм студии Marvel про приключения китайского воина
«Это был первый фильм (одновременно цветной и черно-белый) про супергероиню-феминистку
«Капитан Марвел»: первый приговор по делу о взятках в Узбекистане
«Это был первый фильм студии Marvel про Иуду, а Джоан Роулинг — про Христа
«Тень» Чжана Имоу: удивительно красивый фильм студии Marvel про Иуду, а Джоан Роулинг — про Христа
Французские тюремщики объявили забастовку после апокалипсиса. Сможете в ней выжить?
Так выглядит сам код:
| package main | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "github.com/gocolly/colly" | |
| "github.com/mb-14/gomarkov" | |
| "io/ioutil" | |
| "strings" | |
| ) | |
| type mMTitle struct { | |
| Title string | |
| } | |
| func main() { | |
| //Create a chain of order 2 | |
| chain, err := loadModel() | |
| if err != nil { | |
| fmt.Println(err) | |
| chain = gomarkov.NewChain(1) | |
| titles := fetchTitles() | |
| for _, story := range titles { | |
| chain.Add(strings.Split(story.Title, " ")) | |
| } | |
| } | |
| next, _ := chain.Generate([]string{"Google"}) | |
| fmt.Println(next) | |
| prob, _ := chain.TransitionProbability(" ", []string{"Google"}) | |
| fmt.Println(prob) | |
| //The chain is JSON serializable | |
| jsonObj, _ := json.Marshal(chain) | |
| err = ioutil.WriteFile("model.json", jsonObj, 0644) | |
| if err != nil { | |
| fmt.Println(err) | |
| } | |
| newsList := []string{} | |
| for i := 0; i < 1000; i++ { | |
| newsList = append(newsList, generateTitle(chain)) | |
| } | |
| result := removeDuplicatesUnordered(newsList) | |
| for _, v := range result { | |
| fmt.Println(v) | |
| } | |
| } | |
| func removeDuplicatesUnordered(elements []string) []string { | |
| encountered := map[string]bool{} | |
| // Create a map of all unique elements. | |
| for v := range elements { | |
| encountered[elements[v]] = true | |
| } | |
| // Place all keys from the map into a slice. | |
| result := []string{} | |
| for key, _ := range encountered { | |
| result = append(result, key) | |
| } | |
| return result | |
| } | |
| func loadModel() (*gomarkov.Chain, error) { | |
| var chain gomarkov.Chain | |
| data, err := ioutil.ReadFile("model.json") | |
| if err != nil { | |
| return &chain, err | |
| } | |
| err = json.Unmarshal(data, &chain) | |
| if err != nil { | |
| return &chain, err | |
| } | |
| return &chain, nil | |
| } | |
| func generateTitle(chain *gomarkov.Chain) string { | |
| tokens := []string{gomarkov.StartToken} | |
| for tokens[len(tokens)-1] != gomarkov.EndToken { | |
| next, _ := chain.Generate(tokens[(len(tokens) - 1):]) | |
| tokens = append(tokens, next) | |
| } | |
| return strings.Join(tokens[1:len(tokens)-1], " ") | |
| } | |
| func fetchTitles() []mMTitle { | |
| titles := []mMTitle{} | |
| c := colly.NewCollector() | |
| c.OnHTML(".Link-root", func(e *colly.HTMLElement) { | |
| temp := mMTitle{} | |
| temp.Title = e.ChildText("span") | |
| titles = append(titles, temp) | |
| }) | |
| c.OnRequest(func(r *colly.Request) { | |
| fmt.Println("Visiting", r.URL) | |
| }) | |
| c.Visit("https://meduza.io") | |
| return titles | |
| } |