Jekyll2018-09-13T17:36:01+00:00/phanhoangDescription Here =))
Xây dựng hệ thống gợi ý bài viết cho … website Viblo2018-09-13T17:11:35+00:002018-09-13T17:11:35+00:00/machine-learning/2018/09/13/viblo-recommender-system<h2 id="xây-dựng-hệ-thống-gợi-ý-bài-viết-cho--website-viblo">Xây dựng hệ thống gợi ý bài viết cho … website Viblo</h2>
<ul>
<li>
<p>Hệ gợi ý (Hệ khuyến nghị) hay Recommender System (hoặc Recommendation System) hiện nay là một trong những vấn đề được các công ty hay các trang thương mại điện tử rất quan tâm. Ngày nay, trên thế giới nói chung và tại Việt Nam nói riêng, các hệ thống recommender system đã trở thành một xu hướng không thể thiếu trong thương mai điện tử. Mục đích của nó là hỗ trợ người dùng tìm kiếm được đúng các thông tin cần thiết, dự đoán sở thích hay xếp hạng mà ngươì dùng có thể dành cho một sản phẩm nào đó mà khách hàng xem xét tới trong quá khứ. Từ đó, gợi ý cho người dùng các sản phẩm liên quan. Việc thực hiện tính toán được xây dựng dựa trên các thuật toán Học máy (Machine Learning), đưa ra các dự đoán tốt nhất về sản phẩm mà người dùng có thể thích, giúp tối ưu hóa doanh thu, tăng tín nhiệm, … Cải thiện trải nghiệm người dùng, tăng hiệu năng hoạt động bằng tự động hóa, biến khách hàng tiềm năng trở thành khách hàng thật.</p>
</li>
<li>
<p>Nhìn chung hệ gợi ý được xây dựng với 2 cách tiếp cận chủ đạo là: <code class="highlighter-rouge">Content-Based</code> và <code class="highlighter-rouge">Colaborative Filtering</code>. Mình sẽ không đi sâu vào phân tích từng cách tiếp cận trên, các bạn có thể tham khảo thêm tại website <a href="https://machinelearningcoban.com/">machinelearningcoban.com</a> - từ bài 23 đến bài 26. Mình nghĩ khá chi tiết và cụ thể rồi nên sẽ không đề cập lại, chỉ hơi nhiều toán một chút thôi :D</p>
</li>
<li>
<p>Đây cũng là bài blog đầu tiên của mình trên Viblo, và chủ đề mình muốn viết đó là: xây dựng một hệ thống gợi ý cơ bản cho website <code class="highlighter-rouge">Viblo</code>. Các bạn cũng có thể tham khảo source code tại <a href="https://github.com/huyhoang17/LDA_Viblo_Recommender_System">đây</a>. Nếu có sai sót gì trong bài viết, các bạn vui lòng comment bên dưới hoặc liên hệ về mail <code class="highlighter-rouge">phan.huy.hoang@framgia.com</code> nhé. Không dài dòng nữa, bắt đầu thôi! :D</p>
</li>
<li>
<p>Github Link: https://github.com/huyhoang17/LDA_Viblo_Recommender_System</p>
</li>
<li>
<p>Các bước tiến hành</p>
<ul>
<li>Chuẩn bị dữ liệu</li>
<li>Tiền xử lí dữ liệu</li>
<li>Mô hình hóa hệ gợi ý LDA</li>
</ul>
</li>
</ul>
<h2 id="chuẩn-bị-dữ-liệu">Chuẩn bị dữ liệu:</h2>
<ul>
<li>Về dữ liệu các bài viết trên viblo, các bạn có thể lấy bằng cách truy cập API của Viblo:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://viblo.asia/api/posts
https://viblo.asia/api/posts?page=1
https://viblo.asia/api/posts?page=100
...
</code></pre></div></div>
<p>hoặc để truy cập API của 1 post, các bạn truy cập vào link với format như sau:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://viblo.asia/api/posts/<slug>
</code></pre></div></div>
<ul>
<li>Với slug là 1 chuỗi kí tự random, có thể dễ dàng lấy được trên url của từng bài viết:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://viblo.asia/p/installing-apache-php-mysql-on-ubuntu-1804-GrLZDXBBZk0
# <slug> = GrLZDXBBZk0
https://viblo.asia/api/posts/GrLZDXBBZk0
</code></pre></div></div>
<ul>
<li>Có 1 điểm chú ý là các bạn không nên gửi request liên tục lên API, rất có thể sẽ bị chặn truy cập và dẫn đến xảy ra lỗi khi chạy code. Cách đơn giản nhất cách bạn có thể thực hiện là dừng lại 1 lúc trước khi tiếp tục thực hiện request đến page tiếp theo</li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">time</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
</code></pre></div></div>
<h2 id="xử-lí-dữ-liệu">Xử lí dữ liệu</h2>
<ul>
<li>
<p>Xử lí dữ liệu là một trong những bước quan trọng nhất khi thực hiện bất kì 1 project liên quan đến <code class="highlighter-rouge">Machine Learning</code> nào. Dữ liệu có “tốt” thì mới mong mô hình có thể “tốt” được, không cũng chỉ <code class="highlighter-rouge">"Garbage In, Garbage Out"</code> mà thôi!</p>
</li>
<li>
<p>Trường <code class="highlighter-rouge">contents</code> trong dữ liệu mình lấy từ API về được viết dưới dạng <code class="highlighter-rouge">markdown</code> (một ngôn ngữ định dạng văn bản tương tự HTML, nhưng đơn giản và dễ sử dụng hơn nhiều), nên công đoạn đầu tiên đó là xử lí đống dữ liệu markdown này trước đã:</p>
</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Nghề hot hiện nay là thiết kế website và biết làm SEO\nNhững năm gần đây, nhu cầu tuyển dụng nhân sự vừa có khả năng **[thiết kế web](http://cuthtmlcss.com/dich-vu/thiet-ke-website/)**, vừa có thể làm **seo** ngày càng lớn. Vì các doanh nghiệp bắt đầu nhận ra lợi ích của việc bán hàng, kinh doanh hiệu quả bằng chính website của mình. Cuộc chiến tranh giành thứ hạng trên google chưa bao giờ nóng như lúc này, khi website của bạn ở trang nhất google, đồng nghĩa với cơ hội marketing sản phẩm tới khách hàng lớn hơn bao giờ hết. Để thực hiện điều này, đòi hỏi các công ty, doanh nghiệp phải có một đội ngũ **lập trình viên** và seo riêng biệt, đặc biệt là kiếm người vừa có đồng thời hai khả năng trên không phải là điều dễ dàng. Do đó mà mức lương cho nhân viên **[seo website lên top google](http://webmastershaven.net/vi-sao-phai-seo-website-len-top-google/)** luôn ở mức khá, điều này khiến cho nghề thiết kế website và seo web được đông đảo bạn trẻ quan tâm. Tuy nhiên, **nghề hot hiện nay** cũng đòi hỏi người làm phải thực sự giỏi, chịu áp lực công việc cao.\n\n![](https://viblo.asia/uploads/c94ae5b3-7cac-46f0-a324-21560e124d7a.png)\n## Học thiết kế website không lo thất nghiệp\n\nNếu như trước đây, các doanh nghiệp chỉ **thiết kế web giới thiệu** theo kiểu trưng bày cho có, thì giờ đây họ bắt đầu quan tâm nhiều hơn đến giao diện, tính năng, và thông tin sản phẩm phải luôn được cập nhật. Những việc này thì không thể giao phó hoàn toàn cho bên các đơn vị, **công ty thiết kế web**, vì chi phí sẽ đội lên rất cao, mỗi lần yêu cầu nhờ support là một lần khó, đó còn là chưa kể thuê thêm một công ty chuyên về seo. Rõ ràng, họ cần một nhân viên thiết kế web, [seo](https://vi.wikipedia.org/wiki/T%E1%BB%91i_%C6%B0u_h%C3%B3a_c%C3%B4ng_c%E1%BB%A5_t%C3%ACm_ki%E1%BA%BFm) chuyên biệt.\nXem thêm: [thiết kế website chuyên nghiệp cần gì?](https://viblo.asia/p/thiet-ke-website-chuyen-nghiep-can-gi-OeVKBYpE5kW)\n## Bạn cũng nên học thêm kiến thức seo \nCông việc của những nhân viên này là sao tối ưu trang web, cập nhật tin tức, bài viết, giới thiệu sản phẩm, dịch vụ mới của công ty. Thường xuyên kiểm tra, cập nhật, hoặc thay đổi những tính năng của website sao cho khách hàng dễ sử dụng nhất. Chẳng hạn như khung đặt hàng, bạn cần phải thiết kế, chỉnh sửa làm sao cho khách hàng cảm thấy thoải mái, không thể bắt họ nhập quá nhiều thông tin, hoặc thao tác liên tục. Nếu để họ bực mình chắc chắn công ty của bạn sẽ mất một đơn hàng, mà nhiều người như thế thì doanh số sẽ bị giảm nghiêm trọng. Hoặc chỗ hình ảnh sản phẩm, bạn phải biết up hình sao cho cân đối dễ nhìn, thông tin đầy đủ, giúp khách hàng có thể cảm nhận rõ nét về sản phẩm của công ty nhất....Thỉnh thoảng website của công ty có thể bị ai đó chơi xấu, bạn cũng phải biết khắc phục ngay lập tức. Bởi vì website là bộ mặt của doanh nghiệp, giúp quảng bá sản phẩm, dịch vụ của doanh nghiệp tới khách hàng 24h mỗi ngày, 365 ngày trong năm, nên nếu website bị rớt có nghĩa là doanh nghiệp phải tạm đóng cửa, thiệt hại là không thể đo đếm được. Rõ ràng **nghề hot hiện nay** này đòi hỏi người lao động phải có trình độ chuyên môn cao, bản lĩnh, và sự kiên trì.\n\n![](https://viblo.asia/uploads/4b2e8398-e17f- ......
</code></pre></div></div>
<ul>
<li>Có một chú ý chính vì sự đơn giản trong cách viết của markdown nên dẫn đến việc xử lí dữ liệu lại khó khăn hơn 1 chút, vì markdown sử dụng nhiều các cú pháp như:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>` dấu nháy
- dấu gạch ngang
* dấu sao
[] dấu ngoặc vuông
() dấu ngoặc tròn
...
</code></pre></div></div>
<p>mà không được tổ chức dưới dạng các thẻ như HTML, mà là các kí tự đặc biệt hay punctuation</p>
<ul>
<li>Một giải pháp được đưa ra đó là chuyển dữ liệu từ định dạng markdown sang HTML rồi tiếp tục xử lí. Vì có khá nhiều các thư viện đã hỗ trợ việc xử lí với HTML, kết quả khá tốt. Thư viện mình dùng để xử lí markdown là mistune: <code class="highlighter-rouge">pip install mistune</code></li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">markdown_to_text</span><span class="p">(</span><span class="n">markdown_string</span><span class="p">,</span> <span class="n">parser</span><span class="o">=</span><span class="s">"html.parser"</span><span class="p">,</span>
<span class="n">tags</span><span class="o">=</span><span class="p">[</span><span class="s">'pre'</span><span class="p">,</span> <span class="s">'code'</span><span class="p">,</span> <span class="s">'a'</span><span class="p">,</span> <span class="s">'img'</span><span class="p">,</span> <span class="s">'i'</span><span class="p">]):</span>
<span class="n">markdown</span> <span class="o">=</span> <span class="n">mistune</span><span class="o">.</span><span class="n">Markdown</span><span class="p">()</span>
<span class="n">html</span> <span class="o">=</span> <span class="n">markdown</span><span class="p">(</span><span class="n">markdown_string</span><span class="p">)</span>
<span class="n">soup</span> <span class="o">=</span> <span class="n">BeautifulSoup</span><span class="p">(</span><span class="n">html</span><span class="p">,</span> <span class="n">parser</span><span class="p">)</span>
<span class="c"># remove code snippets</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">preprocessing_tags</span><span class="p">(</span><span class="n">soup</span><span class="p">,</span> <span class="n">tags</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">remove_links_content</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">remove_emails</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">remove_punctuation</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="s">' '</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">remove_numeric</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">remove_multiple_space</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">ViTokenizer</span><span class="o">.</span><span class="n">tokenize</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">remove_stopwords</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">stopwords</span><span class="o">=</span><span class="n">stopwords</span><span class="p">)</span>
<span class="k">return</span> <span class="n">text</span>
</code></pre></div></div>
<p>xem chi tiết tại: <a href="https://github.com/huyhoang17/LDA_Viblo_Recommender_System/blob/master/src/utils.py">utils.py</a></p>
<ul>
<li>
<p>Sau khi đã chuyển sang HTML, các kí tự đặc biệt bên markdown đã được chuyển sang các thẻ bên HTML, ví dụ: <code class="highlighter-rouge"><code>, <pre>, <a>, <img>, <i>, ..</code></p>
</li>
<li>Tiếp đến loại bỏ các thành phần sau, vì không mang nhiều ý nghĩa và gây nhiễu khi huấn luyện mô hình. Sau đây là 1 số bước mình xử lí với trường <code class="highlighter-rouge">contents</code>:
<ul>
<li>Dùng thư viện <code class="highlighter-rouge">bs4</code> để <code class="highlighter-rouge">parse</code> đoạn context vừa chuyển sang HTML bên trên. Lí do sử dụng bs4 vì thư viện này hỗ trợ khá tốt khi xử lí với thẻ HTML, 1 vài thư viện khác các bạn có thể tham khảo như: <code class="highlighter-rouge">lxml, ..</code></li>
<li>Bỏ các thẻ và phần nội dung nằm giữa các thẻ đặc biệt như: <code class="highlighter-rouge"><code>, <pre></code>, vì đây là các thẻ được dùng để bọc các đoạn code, command, .. nên không có nhiều ý nghĩa</li>
<li>Loại bỏ các đường dẫn (link)</li>
<li>Loại bỏ các email</li>
<li>Loại bỏ các kí tự đặc biệt</li>
<li>Thay thế các kí tự khoảng trắng (bao gồm <code class="highlighter-rouge">\n, \t</code> thành <code class="highlighter-rouge">' '</code> hay loại bỏ nhiều kí tự khoảng trắng liền nhau về <code class="highlighter-rouge">' '</code> luôn)</li>
<li>Loại bỏ số</li>
<li>Loại bỏ stopwords (là các từ xuất hiện nhiều trong văn nói, văn viết nhưng không mang nhiều ý nghĩa, ví dụ: rằng, thì, là, mà, … Về danh sách các stopwords của tiếng Việt, các bạn có thể tham khảo ơ đây: <a href="https://github.com/stopwords/vietnamese-stopwords">Stopwords Vietnamese</a> - Cảm ơn tác giả <a href="https://github.com/duyetdev">Le Van Duyet</a> :D</li>
</ul>
</li>
<li>
<p>Ở đây có một chú ý là tiếng Việt bao gồm nhiều từ ghép, được ghép bởi >=2 từ trở lên, đứng riêng lẻ từng từ một thì không có ý nghĩa, nếu xử lí bằng cách đơn giản là phân cách các từ tại các dấu <code class="highlighter-rouge">space</code> thì có thể khiến cho việc huấn luyện mô hình về sau gặp những sai sót hoặc kết quả không thực sự tốt. Ở đây mình có sử dụng một thư viện là <a href="https://github.com/trungtv/pyvi">PyVi</a>, hỗ trợ khá tốt vấn đề về <code class="highlighter-rouge">tokenize</code> và <code class="highlighter-rouge">postagging</code> với tiếng Việt, các bạn có thể tham khảo thử. Cảm ơn tác giả <a href="https://github.com/trungtv">trungtv</a> :D</p>
</li>
<li>Kết quả sau khi đã tiến hành xử lí theo các bước bên trên</li>
</ul>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nghề hot thiết_kế website seo nhu_cầu tuyển_dụng nhân_sự khả_năng seo doanh_nghiệp lợi_ích hàng kinh_doanh hiệu_quả website chiến_tranh_giành thứ_hạng google nóng website trang google đồng_nghĩa marketing sản_phẩm khách_hàng đòi_hỏi công_ty doanh_nghiệp đội_ngũ lập_trình_viên seo riêng_biệt kiếm hai khả_năng dễ_dàng lương nhân_viên nghề thiết_kế website seo web đông_đảo trẻ nghề hot đòi_hỏi người_làm giỏi áp_lực công_việc cao_học thiết_kế website lo thất_nghiệp doanh_nghiệp thiết_kế web giới_thiệu kiểu trưng_bày giao_diện tính_năng thông_tin sản_phẩm cập_nhật giao_phó công_ty thiết_kế web chi_phí đội support thuê công_ty chuyên seo rõ_ràng nhân_viên thiết_kế web chuyên_biệt học kiến_thức seo công_việc nhân_viên tối_ưu trang_web cập_nhật tin_tức viết giới_thiệu sản_phẩm dịch_vụ công_ty thường_xuyên kiểm_tra cập_nhật tính_năng website khách_hàng chẳng_hạn khung đặt_hàng thiết_kế chỉnh_sửa khách_hàng thoải_mái bắt nhập thông_tin thao_tác liên_tục bực_mình công_ty đơn hàng doanh_số nghiêm_trọng chỗ hình_ảnh sản_phẩm up hình cân_đối thông_tin đầy_đủ giúp khách_hàng cảm_nhận nét sản_phẩm công_ty nhấtthỉnh thoảng website công_ty chơi_xấu khắc_phục lập_tức website bộ_mặt doanh_nghiệp giúp quảng_bá sản_phẩm dịch_vụ doanh_nghiệp khách_hàng h website rớt nghĩa_là doanh_nghiệp tạm đóng_cửa thiệt_hại đo_đếm rõ_ràng nghề hot đòi_hỏi lao_động trình_độ chuyên_môn bản_lĩnh kiên_trì mảng nhân_viên đa_nhiệm thiết_kế web seo nhiệm_vụ quản_trị website đăng hình viết sản_phẩm website khách_hàng seo web tức_là khóa keyword sản_phẩm dịch_vụ top google công_việc hề đơn_giản hôm_nay top google ngày_mai cuộc_chiến khốc_liệt khoan_nhượng doanh_nghiệp ảo_tưởng sức_mạnh thuê top google công_việc seo đội bắt nhân_viên chẳng một_mình chống mafia thu_nhập nghề thiết_kế web seo thách_thức đòi_hỏi chuyên_môn bù lương nhân_viên kiểu đãi_ngộ hậu_hĩnh học thiết_kế website học_các ngôn_ngữ lập_trình ngôn_ngữ lập_trình lập_trình website lập_trình phần_mềm ứng_dụng lập_trình app android học_các ngôn_ngữ lập_trình cơ_bản làm_quen dần thế_giới lập_trình_như ngôn_ngữ lập_trình c css c java javascript php học lập_trình niềm đam_mê yêu học ngành học đừng phí tương_tự nghề lập_trình_viên nghề seo đòi_hỏi chuyên_môn kỹ_thuật vững_chắc kiến_thức đa ngành đa_hệ công_việc seo đơn_giản quanh_quẩn mấy kế_hoạch seo tổng_thể lập khóa viết content chuẩn seo chuẩn hàng đi link thành_thạo chuyên_gia hề đơn_giản kinh_nghiệm học khóa seo công_ty thực_tập lên_tay seo dự_án tổng_quan thị_trường việc_làm học thiết_kế web seo web việc_làm bao nghề web seo nghề hot công_ty công_ty có_nhân_sự quản_trị website thuê công_ty dịch_vụ học thực_hành tất_yếu nhân_viên pro cuộc_sống nhấn_mạnh làm_việc chú_tâm ông_bà câu nghệ_tinh thân vinh nghề thiết_kế website seo web học học tới_chốn được_việc đứng sinh tâm chán_nản đứng núi trông_núi tâm_tưởng thành_công
</code></pre></div></div>
<ul>
<li>Có thể thấy là thư viện <code class="highlighter-rouge">PyVi</code> đã xử lí khá tốt đối với các từ ghép, ví dụ: <code class="highlighter-rouge">lập_trình_viên, kinh_nghiệm, nhân_viên, thiết_kế, ..</code> Tuy nhiên cũng có 1 vài chỗ chưa thực sự chuẩn lắm, ví dụ: <code class="highlighter-rouge">có_nhân_sự, chiến_tranh_giành</code> Nhưng nhìn chung kết quả đem lại khá tốt và mình khá hài lòng với kết quả như vậy :D</li>
</ul>
<h2 id="mô-hình-hóa-với-thuật-toán-lda">Mô hình hóa với thuật toán LDA</h2>
<ul>
<li>Thuật toán LDA (Latent Dirichlet Allocation) là một trong những phương pháp Topic Modeling được sử dụng nhiều nhất. LDA miêu tả các văn bản như là sự pha trộn của các topics (bao gồm các từ * trọng số của các từ đó) với các xác suất nhất định. Mô hình này gần giống với phương pháp pLSA (nâng cao hơn của thuật toán LSA), ngoại trừ điểm cơ bản nhất đó là các phân bố <code class="highlighter-rouge">topic</code> trong LDA được giả định theo phân bố Dirichlet thưa (hay sparse Dirichlet), với mục đích biểu thị rằng các đoạn văn bản (document) được biểu diễn bằng 1 số các <code class="highlighter-rouge">topic</code> và các <code class="highlighter-rouge">topic</code> đó lại được biểu diễn bằng 1 tập nhỏ các từ (với trọng số ứng với từng từ giảm dần)</li>
</ul>
<p><img src="https://static1.squarespace.com/static/5378d8b8e4b078c526a500ea/t/58f10fc486e6c0436ef4388b/1492193228796/" alt="LDA" /></p>
<ul>
<li>Để mọi người dễ hình dung hơn, ta đi đến 1 ví dụ đơn giản sau. Giả sử bạn có 1 tập các đoạn văn bản (documents) như sau:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- Machine Learning và AI trong thời gian qua đã đạt được các thành tựu vô cùng đáng kinh ngạc
- Blockchain - từ công nghệ tiền ảo đến ứng dụng tương lại
- Tác hại kinh hoàng của game online với giới trẻ hiện nay
- Mâu thuẫn khi chơi game, nam sinh giết hại bạn của mình cho bõ tức
- Trí tuệ nhân tạo OpenAI chính thức đánh bại 5 game thủ chuyên nghiệp giỏi nhất thế giới
</code></pre></div></div>
<ul>
<li>
<p>Với LDA, giả sử hiện tại bạn quy định sẽ có 2 topic (chưa có tên cụ thể) cần được “phân phối” vào các văn bản cụ thể, LDA sẽ cho ra các kết quả như sau</p>
<ul>
<li>Văn bản 1 và 2 được phân loại vào topic 1</li>
<li>Văn bản 3 và 4 được phân loại vào topic 2</li>
<li>
<p>Văn bản 5 được phân loại như sau: 80% topic 1, 20% topic 2</p>
</li>
<li>Topic 1 được quy định bằng các trọng số của các từ liên quan (cũng là các từ có trọng số lớn nhất) như: <code class="highlighter-rouge">30% về machine_learning + 30% về AI + 20% về block_chain + 10% về mã_hóa + 10% về bảo_mật + ...</code> Từ đó, ta có thể thấy topic 1 liên quan khá nhiều đến <code class="highlighter-rouge">Công nghệ</code></li>
<li>Topic 2 được quy định như sau: <code class="highlighter-rouge">30% về game + 20% về giới_trẻ + 20% về mâu_thuẫn + 20% về tác_hại + 10% về online ...</code> Từ đó, có thể thấy topic 2 nói về các vấn đề liên quan đến <code class="highlighter-rouge">game</code></li>
</ul>
</li>
<li>
<p>Vậy câu hỏi đặt ra là: làm sao LDA có thể thực hiện được việc phân phối các topic và các từ thuộc từng topic với từng xác suất chi tiết như vậy?</p>
</li>
<li>Giả sử hiện tại bạn có 1 tập hợp các đoạn văn bản (documents). Việc đầu tiên bạn phải làm là xác định số K <code class="highlighter-rouge">topics</code> để tiến hành phân phối sau này, và việc đó được thực hiện như sau:
<ul>
<li>Ứng với mỗi văn bản, ngẫu nhiên gán các từ trong đoạn văn bản đó với 1 trong K <code class="highlighter-rouge">topics</code></li>
<li>Với mỗi văn bản <code class="highlighter-rouge">d</code>:
<ul>
<li>Với mỗi từ <code class="highlighter-rouge">w</code> trong văn bản <code class="highlighter-rouge">d</code>:
<ul>
<li>Với mỗi topic <code class="highlighter-rouge">t</code>, ra tính toán 2 thông số: 1 là <code class="highlighter-rouge">p(topic t | document d)</code> và <code class="highlighter-rouge">p(word w | topic t)</code>. Tiến hành gán lại từ <code class="highlighter-rouge">w</code> với 1 <code class="highlighter-rouge">topic</code> mới với xác suất <code class="highlighter-rouge">p(topic t | document d) * p(word w | topic t)</code></li>
</ul>
</li>
</ul>
</li>
<li>Sau khi lặp lại bước trên 1 số lần nhất định, việc phân phối giữa <code class="highlighter-rouge">document-topic</code> và <code class="highlighter-rouge">topic-word</code> đã đạt tới trạng thái đủ tốt. Từ đó, ta có thể sử dụng mô hình để ước lượng phân phối <code class="highlighter-rouge">topic</code> của mỗi văn bản (document) và từ (word) với mỗi <code class="highlighter-rouge">topic</code></li>
</ul>
</li>
<li>Cụ thể hơn:
<ul>
<li>Xác định số K <code class="highlighter-rouge">topics</code> để tiến hành phân phối sau này, số K là gì và việc chọn số K bao nhiêu là ổn, mình sẽ đề cập kĩ hơn bên dưới.</li>
<li>Gán <code class="highlighter-rouge">TẠM</code> mỗi từ trong đoạn văn bản với 1 <code class="highlighter-rouge">topic</code> nhất định. Việc này thực hiện sau khi đã bỏ đi các từ <code class="highlighter-rouge">stopwords</code>. Lưu ý là cùng 1 từ nhưng hoàn toàn có thể thuộc các <code class="highlighter-rouge">topic</code> khác nhau.</li>
<li>Kiểm tra và tiến hành cập nhật việc gán từ cho mỗi <code class="highlighter-rouge">topic</code>, dựa trên 2 tiêu chí:
<ul>
<li>Độ phổ biến của <code class="highlighter-rouge">word</code> đó trong các <code class="highlighter-rouge">topic</code></li>
<li>Độ phổ biến của <code class="highlighter-rouge">topic</code> trong các <code class="highlighter-rouge">documents</code></li>
</ul>
</li>
</ul>
</li>
<li>
<p>Ở đây, mình có sử dụng thư viện <code class="highlighter-rouge">Gensim</code>, là một trong những thư viện hỗ trợ tốt và đa dạng các bài toán liên quan đến Topic Modeling như: <code class="highlighter-rouge">LSA, LDA</code> hay các bài toán liên quan đến Word Embedding như: <code class="highlighter-rouge">Word2Vec, Doc2Vec</code>, các bạn quan tâm có thể tham khảo thêm tại phần <a href="https://radimrehurek.com/gensim/tutorial.html">Tutorial</a> của Gensim</p>
</li>
<li>
<p>Nhìn chung, khi sử dụng Gensim với bài toán LDA, có một số điểm mà các bạn cần chú ý khi định nghĩa:</p>
<ul>
<li><code class="highlighter-rouge">dictionary</code>: mapping giữa index và các từ. Ví dụ: <code class="highlighter-rouge">{0: 'computer', 1: 'human', 2: 'interface', 3: 'response', 4: 'survey', 5: 'system', 6: 'time', 7: 'user', 8: 'eps', 9: 'trees', 10: 'graph', 11: 'minors'}</code></li>
<li><code class="highlighter-rouge">corpus</code>: list chứa bộ các tuple theo định dạng <code class="highlighter-rouge">(index, word_frequency)</code>. Ví dụ: <code class="highlighter-rouge">[(0, 1), (1, 2), (2, 1)]</code> tương ứng với từ tại index 0 xuất hiện 1 lần, từ tại index 1 xuất hiện 2 lần, từ tại index 2 xuất hiện 1 lần trong đoạn văn bản đó. Index tính theo tổng số từ (không lặp lại) trong toàn bộ tập văn bản.</li>
</ul>
</li>
<li>Một điểm chú ý nữa đó là <code class="highlighter-rouge">gensim</code> hỗ trợ việc <code class="highlighter-rouge">fetch</code> dữ liệu theo <code class="highlighter-rouge">iterable object</code> thay vì là 1 mảng (list hoặc numpy array). Do đó, bạn không cần phải tạo 1 list chứa 1.000.000 văn bản (rất tốn <code class="highlighter-rouge">RAM</code>) rồi mới đưa vào model, đơn giản là viết code return về <code class="highlighter-rouge">generator</code> trong python, sau đây là 1 số đoạn code ví dụ:</li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># sentences cũng được fetch theo generator object</span>
<span class="k">def</span> <span class="nf">make_texts_corpus</span><span class="p">(</span><span class="n">sentences</span><span class="p">):</span>
<span class="k">for</span> <span class="n">sentence</span> <span class="ow">in</span> <span class="n">sentences</span><span class="p">:</span>
<span class="k">yield</span> <span class="n">simple_preprocess</span><span class="p">(</span><span class="n">sentence</span><span class="p">,</span> <span class="n">deacc</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">StreamCorpus</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sentences</span><span class="p">,</span> <span class="n">dictionary</span><span class="p">,</span> <span class="n">clip_docs</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="s">"""
Parse the first `clip_docs` documents
Yield each document in turn, as a list of tokens.
"""</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sentences</span> <span class="o">=</span> <span class="n">sentences</span>
<span class="bp">self</span><span class="o">.</span><span class="n">dictionary</span> <span class="o">=</span> <span class="n">dictionary</span>
<span class="bp">self</span><span class="o">.</span><span class="n">clip_docs</span> <span class="o">=</span> <span class="n">clip_docs</span>
<span class="k">def</span> <span class="nf">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">for</span> <span class="n">tokens</span> <span class="ow">in</span> <span class="n">itertools</span><span class="o">.</span><span class="n">islice</span><span class="p">(</span>
<span class="n">make_texts_corpus</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sentences</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">clip_docs</span><span class="p">):</span>
<span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">dictionary</span><span class="o">.</span><span class="n">doc2bow</span><span class="p">(</span><span class="n">tokens</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">clip_docs</span>
</code></pre></div></div>
<p>các bạn đọc thêm tại <a href="https://radimrehurek.com/gensim/tut1.html#corpus-streaming-one-document-at-a-time">đây</a></p>
<ul>
<li>LDA model</li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">gensim</span>
<span class="n">lda_model</span> <span class="o">=</span> <span class="n">gensim</span><span class="o">.</span><span class="n">models</span><span class="o">.</span><span class="n">LdaModel</span><span class="p">(</span><span class="n">corpus</span><span class="p">,</span> <span class="n">num_topics</span><span class="o">=</span><span class="mi">64</span><span class="p">,</span> <span class="n">id2word</span><span class="o">=</span><span class="n">id2word</span><span class="p">,</span> <span class="n">passes</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">chunksize</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">42</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">1e-2</span><span class="p">,</span> <span class="n">eta</span><span class="o">=</span><span class="mf">0.5e-2</span><span class="p">,</span> <span class="n">minimum_probability</span><span class="o">=</span><span class="mf">0.0</span><span class="p">),</span> <span class="n">per_word_topics</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>
<p>ở đây mình chọn số lượng <code class="highlighter-rouge">topic</code> là 64 (chính là số <code class="highlighter-rouge">K</code> bên trên), đây cũng sẽ là số quy định vector đầu ra ứng với ma trận <code class="highlighter-rouge">documents x topics</code>, thể hiện việc phân bố <code class="highlighter-rouge">topic</code> ứng với từng <code class="highlighter-rouge">document</code>, mỗi <code class="highlighter-rouge">document</code> sẽ được biểu diễn bằng vector 64 chiều.</p>
<ul>
<li>
<p>Vậy câu hỏi đặt ra là: số <code class="highlighter-rouge">topic</code> quy định bao nhiêu là tốt, liệu mình lấy 10 hay 1000 <code class="highlighter-rouge">topics</code> có được không? Lúc đó, 1 giá trị được quy định gọi là <code class="highlighter-rouge">Coherence Value</code>, <code class="highlighter-rouge">Coherence Value</code> càng cao thì càng tốt. Các bạn đọc thêm về <code class="highlighter-rouge">Corehenre Value</code> tại <a href="https://www.machinelearningplus.com/nlp/topic-modeling-gensim-python/#17howtofindtheoptimalnumberoftopicsforlda">đây</a></p>
</li>
<li>
<p>Kết quả một số <code class="highlighter-rouge">topic</code> thu được sau khi chạy mô hình</p>
</li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">lda_model</span><span class="o">.</span><span class="n">print_topics</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>INFO : topic #56 (0.010): 0.127*"javascript" + 0.095*"html" + 0.052*"jquery" + 0.047*"thu_vien" + 0.047*"template" + 0.039*"dom" + 0.036*"js" + 0.030*"ajax" + 0.023*"angular" + 0.019*"css"
INFO : topic #23 (0.010): 0.113*"trang" + 0.109*"web" + 0.082*"trang_web" + 0.063*"website" + 0.055*"trinh_duyet" + 0.043*"angularjs" + 0.033*"url" + 0.028*"link" + 0.025*"html" + 0.024*"page"
INFO : topic #31 (0.010): 0.101*"team" + 0.072*"agile" + 0.058*"product" + 0.051*"release" + 0.050*"master" + 0.044*"scrum" + 0.033*"thanh_vien" + 0.025*"owner" + 0.021*"tables" + 0.016*"mo_hinh"
INFO : topic #3 (0.010): 0.135*"lenh" + 0.064*"thu_muc" + 0.054*"dong" + 0.027*"mac_đinh" + 0.026*"cau_lenh" + 0.023*"thiet_lap" + 0.020*"phien_ban" + 0.015*"cau_hinh" + 0.015*"đuong_dan" + 0.014*"tu_đong"
INFO : topic #50 (0.010): 0.149*"rails" + 0.096*"gem" + 0.049*"ruby" + 0.035*"redis" + 0.028*"cluster" + 0.028*"job" + 0.022*"chat" + 0.017*"gemfile" + 0.016*"on" + 0.014*"config"
INFO : topic #53 (0.010): 0.050*"thiet_ke" + 0.039*"hang" + 0.021*"unity" + 0.020*"san_pham" + 0.015*"khach_hang" + 0.014*"bao_cao" + 0.014*"yeu_to" + 0.013*"dich_vu" + 0.012*"cong_ty" + 0.012*"mua"
INFO : topic #0 (0.010): 0.134*"ui" + 0.091*"domain" + 0.083*"mobile" + 0.069*"native" + 0.053*"platform" + 0.045*"virtual" + 0.036*"objectivec" + 0.034*"chain" + 0.028*"markup" + 0.023*"nen_tang"
INFO : topic #44 (0.010): 0.325*"app" + 0.028*"store" + 0.026*"tutorial" + 0.024*"play" + 0.018*"developer" + 0.017*"changes" + 0.016*"apps" + 0.016*"qr" + 0.016*"devices" + 0.014*"book"
INFO : topic #36 (0.010): 0.055*"luu_tru" + 0.048*"database" + 0.047*"ghi" + 0.046*"co_so" + 0.039*"luu" + 0.037*"truong" + 0.032*"thao_tac" + 0.026*"xoa" + 0.026*"bang" + 0.024*"kieu"
INFO : topic #63 (0.010): 0.176*"model" + 0.119*"controller" + 0.093*"user" + 0.083*"view" + 0.038*"mvc" + 0.024*"aspnet" + 0.020*"active" + 0.019*"route" + 0.017*"framework" + 0.016*"tuong_ung"
INFO : topic #57 (0.010): 0.164*"android" + 0.067*"google" + 0.059*"activity" + 0.034*"api" + 0.033*"sdk" + 0.032*"thu_vien" + 0.026*"map" + 0.026*"ban_đo" + 0.024*"studio" + 0.021*"fragment"
INFO : topic #26 (0.010): 0.058*"to" + 0.037*"and" + 0.036*"is" + 0.034*"of" + 0.030*"in" + 0.022*"you" + 0.021*"for" + 0.020*"it" + 0.018*"that" + 0.018*"this"
INFO : topic #52 (0.010): 0.118*"tap_tin" + 0.098*"tai" + 0.070*"eclipse" + 0.049*"nen" + 0.035*"ma" + 0.031*"spring" + 0.028*"download" + 0.028*"đinh_dang" + 0.024*"cau_hinh" + 0.022*"giai"
INFO : topic #10 (0.010): 0.047*"click" + 0.035*"nut" + 0.026*"button" + 0.024*"man_hinh" + 0.024*"nhap" + 0.020*"nhan" + 0.016*"menu" + 0.015*"add" + 0.014*"chuot" + 0.014*"tab"
INFO : topic #27 (0.010): 0.127*"function" + 0.069*"string" + 0.053*"true" + 0.051*"null" + 0.043*"false" + 0.043*"set" + 0.036*"object" + 0.036*"property" + 0.033*"var" + 0.027*"return"
...
</code></pre></div></div>
<ul>
<li>Sau khi thực hiện training model, các bạn nhớ thực hiện việc lưu lại model nhé:</li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># save corpus</span>
<span class="n">gensim</span><span class="o">.</span><span class="n">corpora</span><span class="o">.</span><span class="n">MmCorpus</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="n">PATH_CORPUS</span><span class="p">,</span> <span class="n">corpus</span><span class="p">)</span>
<span class="c"># save dictionary</span>
<span class="n">gensim</span><span class="o">.</span><span class="n">corpora</span><span class="o">.</span><span class="n">Dictionary</span><span class="o">.</span><span class="n">dictionary</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">PATH_DICTIONARY</span><span class="p">)</span>
<span class="c"># save LDA model</span>
<span class="n">gensim</span><span class="o">.</span><span class="n">models</span><span class="o">.</span><span class="n">LdaModel</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">PATH_LDA_MODEL</span><span class="p">)</span>
</code></pre></div></div>
<ul>
<li>sau đó các bạn thực hiện việc tính toán ma trận <code class="highlighter-rouge">documents x topics</code> và lưu lại ma trận bằng đoạn code sau:</li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">from</span> <span class="nn">sklearn.externals</span> <span class="kn">import</span> <span class="n">joblib</span>
<span class="c"># class method</span>
<span class="k">def</span> <span class="nf">documents_topic_distribution</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">doc_topic_dist</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span>
<span class="p">[[</span><span class="n">tup</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">tup</span> <span class="ow">in</span> <span class="n">lst</span><span class="p">]</span> <span class="k">for</span> <span class="n">lst</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">lda_model</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">corpus</span><span class="p">]]</span>
<span class="p">)</span>
<span class="c"># save documents-topics matrix</span>
<span class="n">joblib</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">doc_topic_dist</span><span class="p">,</span> <span class="n">PATH_DOC_TOPIC_DIST</span><span class="p">)</span>
<span class="k">return</span> <span class="n">doc_topic_dist</span>
</code></pre></div></div>
<ul>
<li>Khi có một bài viết mới trên viblo, công việc đầu tiên thực hiện sẽ là <code class="highlighter-rouge">parse</code> dữ liệu dạng markdown tại trường <code class="highlighter-rouge">content</code> như bên trên. Sau đó, sử dụng <code class="highlighter-rouge">dictionary</code> và <code class="highlighter-rouge">LDA model</code> đã train và lưu lại để thu được vector <code class="highlighter-rouge">document_dist</code>, ứng với phân bố các topic của document đó. Code minh họa:</li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># class method</span>
<span class="k">def</span> <span class="nf">transform</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sentence</span><span class="p">):</span>
<span class="s">"""
:param document: preprocessed document
"""</span>
<span class="n">document_corpus</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">make_texts_corpus</span><span class="p">([</span><span class="n">sentence</span><span class="p">]))</span>
<span class="n">corpus</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">id2word</span><span class="o">.</span><span class="n">doc2bow</span><span class="p">(</span><span class="n">document_corpus</span><span class="p">)</span>
<span class="n">document_dist</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span>
<span class="p">[</span><span class="n">tup</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">tup</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">lda_model</span><span class="o">.</span><span class="n">get_document_topics</span><span class="p">(</span><span class="n">bow</span><span class="o">=</span><span class="n">corpus</span><span class="p">)]</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">corpus</span><span class="p">,</span> <span class="n">document_dist</span>
</code></pre></div></div>
<ul>
<li>Sau đó tiến hành so sánh độ tương tự với từng <code class="highlighter-rouge">sample</code> trong ma trận <code class="highlighter-rouge">documents x topics</code> đã lưu bên trên. Metric mình sử dụng ở đây là <code class="highlighter-rouge">Jensen Shannon</code>, các bạn có thể đọc thêm tại <a href="https://www.quora.com/How-does-Jensen%E2%80%93Shannon-divergence-criterion-work">đây</a>. Code minh họa:</li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">scipy.stats</span> <span class="kn">import</span> <span class="n">entropy</span>
<span class="k">def</span> <span class="nf">jensen_shannon</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">matrix</span><span class="p">):</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">query</span><span class="p">[</span><span class="bp">None</span><span class="p">,</span> <span class="p">:]</span><span class="o">.</span><span class="n">T</span>
<span class="n">q</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">.</span><span class="n">T</span>
<span class="n">m</span> <span class="o">=</span> <span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">p</span> <span class="o">+</span> <span class="n">q</span><span class="p">)</span>
<span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="mf">0.5</span> <span class="o">*</span> <span class="p">(</span><span class="n">entropy</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">m</span><span class="p">)</span> <span class="o">+</span> <span class="n">entropy</span><span class="p">(</span><span class="n">q</span><span class="p">,</span> <span class="n">m</span><span class="p">)))</span>
</code></pre></div></div>
<ul>
<li>và thực hiện việc sắp xếp các giá trị đó, khoảng cách càng nhỏ chứng tỏ sự tương đồng phân bố <code class="highlighter-rouge">topics</code> giữa 2 <code class="highlighter-rouge">documents</code> càng cao. Ở đây, mình lấy <code class="highlighter-rouge">k=10</code> ứng với 10 <code class="highlighter-rouge">documents</code> tương đồng nhất. Code minh họa:</li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get_most_similar_documents</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">matrix</span><span class="p">,</span> <span class="n">k</span><span class="o">=</span><span class="mi">10</span><span class="p">):</span>
<span class="c"># list of jensen shannon distances</span>
<span class="n">sims</span> <span class="o">=</span> <span class="n">jensen_shannon</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">matrix</span><span class="p">)</span>
<span class="c"># the top k positional index of the smallest Jensen Shannon distances</span>
<span class="k">return</span> <span class="n">sims</span><span class="o">.</span><span class="n">argsort</span><span class="p">()[:</span><span class="n">k</span><span class="p">]</span>
</code></pre></div></div>
<p>xem chi tiết tại: <a href="https://github.com/huyhoang17/LDA_Viblo_Recommender_System/blob/master/src/distances.py">utils.py</a></p>
<ul>
<li>Hàm <code class="highlighter-rouge">get_most_similar_documents()</code> trả về <code class="highlighter-rouge">index</code> của các <code class="highlighter-rouge">documents</code> trong cơ sở dữ liệu của mình (bắt đầu từ 0 và tương ứng với index các hàng trong ma trận <code class="highlighter-rouge">documents x topics</code> bên trên, đó cũng chính là lí do vì sao phải lưu giữ ma trận này lại). Với trường hợp có <code class="highlighter-rouge">document</code> mới được thêm vào cơ sở dữ liệu (1 bài viết mới trên Viblo), sau khi đã tính toán được <code class="highlighter-rouge">vector</code> phân phối theo <code class="highlighter-rouge">topics</code> của <code class="highlighter-rouge">document</code> đó bằng method <code class="highlighter-rouge">transform</code> bên trên, các bạn tiến hành cập nhật ma trận <code class="highlighter-rouge">documents x topics</code> bằng cách thêm 1 hàng vào cuối ma trận đó. Vậy là xong!</li>
</ul>
<h2 id="kết-quả">Kết quả</h2>
<ul>
<li>Sau đây là một số kết quả khi chạy model. Về database thì mình sử dụng <code class="highlighter-rouge">MongoDB</code>, web framework là <code class="highlighter-rouge">Flask</code></li>
</ul>
<p><img src="https://i.imgur.com/WhhjdTF.png" alt="Imgur" /></p>
<p><img src="https://i.imgur.com/xiStfaw.png" alt="Imgur" /></p>
<p><img src="https://i.imgur.com/wKNflIl.png" alt="Imgur" /></p>
<p><img src="https://i.imgur.com/5OVHrIx.png" alt="Imgur" /></p>
<p><img src="https://i.imgur.com/34ePh2g.png" alt="Imgur" /></p>
<ul>
<li>Khá ổn phải không nào =))</li>
</ul>
<h2 id="kết-luận">Kết luận</h2>
<ul>
<li>
<p>Trên đây là bài blog giới thiệu xây dựng 1 hệ gợi ý cơ bản cho website Viblo. Các bước tuần tự từ chuẩn bị dữ liệu, tiền xử lí dữ liệu và mô hình hóa bằng thuật toán LDA, hi vọng sẽ có ích cho những bạn quan tâm đến <code class="highlighter-rouge">Recommender System</code> hay những bạn mới bắt đầu tiếp cận với <code class="highlighter-rouge">Machine Learning</code> nói chung. Nếu các bạn có bất kì thắc mắc nào hãy comment bên dưới hoặc tiến hành tạo <code class="highlighter-rouge">Issue</code> hay <code class="highlighter-rouge">Pull Requests</code> trên repo của mình nhé, mọi chi tiết xin liên hệ mình theo địa chỉ: <code class="highlighter-rouge">phan.huy.hoang@framgia.com</code></p>
</li>
<li>
<p>Github Link: https://github.com/huyhoang17/LDA_Viblo_Recommender_System</p>
</li>
<li>
<p>Nếu các bạn thấy hữu ích khi đọc bài viết của mình, hãy upvote và star cho repo của mình nhé! Cảm ơn mọi người đã đọc bài viết và hẹn gặp lại trong những bài blog tiếp theo!</p>
</li>
</ul>Xây dựng hệ thống gợi ý bài viết cho … website VibloHướng dẫn cơ bản về git trên Windows2017-04-21T17:11:35+00:002017-04-21T17:11:35+00:00/git/2017/04/21/introduction-to-git-GUI<h2 id="hướng-dẫn-cơ-bản-về-git-trên-windows">Hướng dẫn cơ bản về git trên Windows</h2>
<ul>
<li>
<p>Trong hướng dẫn lần này, mình sẽ hướng dẫn các bạn cách cài đặt và sử dụng Git trên Windows. Bao gồm hướng dẫn trên giao diện đồ họa GUI và Terminal.</p>
</li>
<li>
<p>Đầu tiên, truy cập https://git-scm.com/downloads tải về bản git dành cho Windows.</p>
</li>
<li>
<p>Sau khi tải về sẽ có 1 file .exe, bạn tiến hành cài đặt như bình thường.</p>
<p><img src="http://i.imgur.com/xWYy3t7.png" alt="Imgur" /></p>
<p></p>
</li>
<li>
<p>Xong khi cài đặt xong, bạn click chuột phải trên màn hình. Để ý sẽ thấy có 2 phần tùy chọn <code class="highlighter-rouge">Git Gui Here</code> và <code class="highlighter-rouge">Git Bash Here</code></p>
<p><img src="http://i.imgur.com/vA8D0ET.png" alt="Imgur" /></p>
</li>
<li>
<p>Bạn chọn git GUI, 1 cửa sổ thông báo sẽ hiện ra</p>
<p><img src="http://i.imgur.com/BoX2oF4.png" alt="Imgur" /></p>
<p></p>
</li>
<li>
<p>Click mục <code class="highlighter-rouge">Help --> Set up SSH_KEY</code>, tiếp tục chọn <code class="highlighter-rouge">Generate Key</code>, xuất hiện 1 đoạn public key như hình bên dưới, sau đó copy</p>
<p><img src="http://i.imgur.com/OdlO72v.png" alt="Imgur" /></p>
</li>
<li>
<p>Truy cập vào Gitlab, phần <code class="highlighter-rouge">Settings --> SSH Keys</code> và paste đoạn key vừa copy vào đó</p>
<p><img src="http://i.imgur.com/9Q4AF9H.png" alt="Imgur" /></p>
</li>
<li>
<p>Sau đó bạn trup cập theo đường dẫn: https://gitlab.com/pyfml/pyfml để tiến hành clone hay kéo thư mục trên gitlab của lớp về máy. Để ý sẽ có 2 tuỳ chọn</p>
<p><img src="http://i.imgur.com/R57XgaJ.png" alt="Imgur" /></p>
</li>
<li>
<p>Bạn có thể chọn 1 trong 2, nếu dùng HTTPS thì mỗi lần liên kết tới gitlab đều sẽ phải cung cập username và password. Ở đây, mình sẽ dùng HTTPs và tiến hành clone về máy (bạn chuột phải trên thư mục làm việc bạn muốn clone project về máy và chọn <code class="highlighter-rouge">Git Bash Here</code> )</p>
<p><img src="http://i.imgur.com/aTwjMPu.png" alt="Imgur" /></p>
</li>
<li>
<p>Sau khi clone về máy, bạn có thể thao tác thực hành với git như trong hướng dẫn cơ bản về git của mình. Ví dụ ở đây mình tạo mới 1 thư mục trên máy và thực hiện 1 số thao tác cơ bản</p>
<p><img src="http://i.imgur.com/tdsGDEd.png" alt="Imgur" /></p>
<p></p>
</li>
<li>
<p>và kiểm tra, tạo và chuyển nhánh trên giao diện dòng lệnh</p>
<p><img src="http://i.imgur.com/LFtFvFh.png" alt="Imgur" /></p>
</li>
</ul>
<p><strong>Phụ lục</strong>: hướng dẫn cơ bản về git cho người mới bắt đầu</p>
<blockquote>
<p>https://github.com/huyhoang17/Introduction-to-Git/blob/master/introduction_to_git.md</p>
</blockquote>Hướng dẫn cơ bản về git trên WindowsHướng dẫn cơ bản về git cho người mới bắt đầu2017-04-21T17:11:34+00:002017-04-21T17:11:34+00:00/git/2017/04/21/introduction-to-git<h2 id="hướng-dẫn-cơ-bản-về-git-cho-người-mới-bắt-đầu">Hướng dẫn cơ bản về git cho người mới bắt đầu</h2>
<hr />
<ol>
<li>Git là gì? Tại sao nên và cần sử dụng git?</li>
<li>Cài đặt và sử dụng git?</li>
<li>Hướng dẫn nộp bài tập qua <code class="highlighter-rouge">git</code> cho học viên <code class="highlighter-rouge">pyfml</code></li>
<li>Phụ lục</li>
</ol>
<hr />
<h2 id="i-git-là-gì-tại-sao-lại-sử-dụng-git"><strong>I. Git là gì? Tại sao lại sử dụng git?</strong></h2>
<ul>
<li>Thứ nhất, Git là 1 hệ thống quản lí phiên bản phân tán (DVCS - Distributed Version Control System) ??? Nhưng hiểu thế nào là 1 hệ thống quản lí phiên bản, rồi lại phân tán gì ở đây? Để đơn giản có thể hiểu DVCS là hệ thống lưu trữ các tập tin ( file, thư mục, …) theo thời gian, tương ứng với nhiều phiên bản khác nhau của các tập tin đó, và bạn hoàn toàn có thể quay lại 1 phiên bản xác định nào đó sau này, xem lại các thay đổi thực hiện theo thời gian hay làm việc trên nhiều <code class="highlighter-rouge">nhánh</code> khác nhau của 1 dự án ! Nghe thật kì diệu phải ko?</li>
<li>Vậy tại sao lại sử dụng git? Có lẽ mình sẽ lấy 1 ví dụ cho các bạn dễ hình dung:</li>
</ul>
<blockquote>
<p>Vào 1 ngày đẹp trời, 2 anh A và B cùng bắt tay vào thực hiện 1 dự án (xây dựng 1 website eCommerce cho khách hàng chẳng hạn). Tất nhiên, khối lượng công việc khá nhiều nên 2 người chia nhau làm các chức năng hay feature cho dự án đó. Bạn cứ thử tưởng tượng mà xem, anh A viết code rồi gửi cho anh B, anh B viết code rồi gửi cho anh A, vậy bạn nghĩ họ sẽ làm thế nào để có thể <code class="highlighter-rouge">có được</code> code của nhau để tiếp tục phát triển dự án. Có thể họ sẽ gửi file qua email hay lên paste code lên đâu đó rồi share link cho nhau ?? Lúc đó nảy sinh 1 vấn đề, giả sử anh A vô tình viết sai code dẫn đến phần mềm bị lỗi, gỡ lỗi mãi chưa được hoặc chỉ đơn giản là quay lại đoạn code trước mà anh ta thấy tối ưu hơn chẳng hạn thì giờ làm thế nào? Chắc chắn là không được và cứ thế, 2 người lại tiếp tục xây dựng lại tính năng đó và tiếp tục gửi code cho nhau như vậy !</p>
</blockquote>
<ul>
<li>Có lẽ đọc mẩu chuyện ngắn bên trên, bạn cũng sẽ hiểu được 1 số vấn đề mà 2 anh A và B gặp phải:
<ul>
<li>Việc gửi code qua email hay share link code cho nhau rất rất tốn thời gian.</li>
<li>Không theo dõi được tiến độ của dự án hoặc những thay đổi của người trong 1 nhóm vào sản phẩm.</li>
<li>Code ko được sao lưu và cập nhật thường xuyên khiến cho việc quay lại các phiên làm việc trước đó hết sức khó khăn !</li>
</ul>
</li>
<li>Và đó chính là các vấn đề mà git có thể giải quyết 1 cách đơn giản chỉ bằng 1 vài dòng lệnh !</li>
</ul>
<h2 id="ii-cài-đặt-git"><strong>II. Cài đặt git</strong></h2>
<p><strong>1. Trên Linux:</strong></p>
<ul>
<li>Ubuntu: <code class="highlighter-rouge">sudo apt-get install git</code></li>
</ul>
<p><strong>2. Trên Window:</strong></p>
<ul>
<li>Trên window thì việc cài đặt sẽ khó khăn hơn 1 chút, để đơn giản. bạn truy cập vào đường dẫn: https://www.git-scm.com/downloads và tại về bản git dành cho window bao gồm cả giao diện đồ họa GUI và terminal.</li>
</ul>
<h2 id="iii-1-số-thao-tác-cơ-bản-khi-sử-dụng-git---github"><strong>III. 1 số thao tác cơ bản khi sử dụng Git - Github</strong></h2>
<ul>
<li>Nếu bạn dùng window thì có thể xem tài liệu hướng dẫn sử dụng git với Window</li>
<li>Việc đầu tiên cần làm sau khi cài đặt git đó là thiết lập các thông số cấu hình ban đầu của git trên máy, bao gồm <code class="highlighter-rouge">username</code> và <code class="highlighter-rouge">email</code> của bạn. Trên terminal các bạn gõ lần lượt từng lệnh:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global user.name "Your name"
git config --global user.email "youremail@gmail.com"
</code></pre></div></div>
<p><strong>1. Các thao tác cơ bản:</strong></p>
<ul>
<li>Tiếp sau đó, bạn cần tạo <code class="highlighter-rouge">repository</code>hay <code class="highlighter-rouge">thư mục chứa code</code>, nơi sẽ lưu giữ toàn bộ mã nguồn của bạn. Trên terminal, bạn tạo ra 1 thư mục trên máy là truy cập vào thư mục đó:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir test_repo # lệnh tạo thư mục
cd test_repo # truy cập vào thư mục test_repo
</code></pre></div></div>
<ul>
<li>Trong thư mục <code class="highlighter-rouge">test_repo</code>, bạn thực hiện lệnh:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git init
</code></pre></div></div>
<p>Lệnh này sẽ khởi tạo 1 thư mục <code class="highlighter-rouge">.git</code>bên trong thư mục làm việc cuả bạn, là nơi chứa các thiết lập về git cũng như thông tin về kho chứa. Bạn có thể thấy 1 thông báo rằng đã khởi tạo 1 kho chứa thành công</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/workspace
╰─➤ mkdir test_repo
(venv) ╭─phanhoang@phanhoang-PC ~/workspace
╰─➤ cd test_repo
(venv) ╭─phanhoang@phanhoang-PC ~/workspace/test_repo
╰─➤ git init
Initialized empty Git repository in /home/phanhoang/workspace/test_repo/.git/
(venv) ╭─phanhoang@phanhoang-PC ~/workspace/test_repo ‹master›
╰─➤ ls -a
. .. .git
</code></pre></div></div>
<ul>
<li>Giờ bạn sẽ tạo mới 1 file ( hoặc thư mục ) tùy ý và thực hiện lệnh <code class="highlighter-rouge">git status</code></li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/workspace/test_repo ‹master›
╰─➤ touch README.md
(venv) ╭─phanhoang@phanhoang-PC ~/workspace/test_repo ‹master*›
╰─➤ git status
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)
</code></pre></div></div>
<ul>
<li>Như bạn có thể thấy, sau khi bạn tạo mới 1 file trên thư mục làm việc sẽ có 1 thông báo xuất ra màn hình báo <code class="highlighter-rouge">file chưa được theo dõi</code>( dòng README.md sẽ hiện màu đỏ ), giả sử bạn xóa file này đi thì git cũng không quan tâm. Hiểu đơn giản, git quản lí tập tin nên nếu bạn thay đổi hay tạo mới bất cứ 1 file ( hay thư mục ) mà chưa thông báo cho git thì mọi thay đổi trên file ( thư mục ) đó git sẽ chưa thể quản lí ( theo dõi ) được. Để cập nhật file ( thư mục ) đã được thay đổi, trên terminal các bạn thực hiện lệnh <code class="highlighter-rouge">git add tên_file</code> , rồi <code class="highlighter-rouge">git status</code>:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/workspace/test_repo ‹master*›
╰─➤ git add README.md
(venv) ╭─phanhoang@phanhoang-PC ~/workspace/test_repo ‹master*›
╰─➤ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
</code></pre></div></div>
<ul>
<li>Bạn có để ý thấy điều gì ko? Git báo file đã được cập nhật và có 1 file mới <code class="highlighter-rouge">README.md</code> màu xanh. Tuy nhiên, khi thực hiện <code class="highlighter-rouge">git add tên_file</code>ta mới thông báo cho git là file đã đc cập nhật nhưng chưa hề được đánh dấu version ( hay các phiên làm việc ). Để làm được điều đó, ta thực hiện lệnh <code class="highlighter-rouge">git commit -m "tên lời nhắn"</code>:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/workspace/test_repo ‹master*›
╰─➤ git commit -m 'add README.md'
[master (root-commit) 43e1e93] add README.md
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md
(venv) ╭─phanhoang@phanhoang-PC ~/workspace/test_repo ‹master›
╰─➤ git status
On branch master
nothing to commit, working directory clean
</code></pre></div></div>
<ul>
<li>
<p><code class="highlighter-rouge">Tên lời nhắn</code>chính là thao tác bạn vừa thực hiện trên thư mục đó. Lời nhắn nên để ở thì hiện tại đơn và nên ngắn gọn, dễ hiểu. Xong khi thực hiện <code class="highlighter-rouge">commit</code>, ta thấy git tạo ra 1 mã hashcode <code class="highlighter-rouge">[master (root-commit) 43e1e93] add README.md</code> kèm theo đó là tên lời nhắn vừa thực hiện. Gõ <code class="highlighter-rouge">git status</code>thì git báo chưa có gì để cập nhật hay hiện tại chưa có bất kì 1 sự thay đổi nào trong thư mục làm việc !</p>
</li>
<li>
<p>Để xem lại các commit trước, bạn thực hiện lệnh <code class="highlighter-rouge">git log</code>:</p>
</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>commit 43e1e9398960d2d686bae38a05c269152228b157
Author: huyhoang17 <hoangphan0710@gmail.com>
Date: --- --- - --:--:-- ---- +0700
add README.md
(END)
</code></pre></div></div>
<ul>
<li>Bạn có để ý thấy 7 kí tự đầu trên mã hashcode và tên commit tương ứng như lúc nãy mình vừa thực hiện lệnh <code class="highlighter-rouge">git commit -m "tên lời nhắn"</code> ko ? Vậy là bạn đã thực hiện xong commit đầu tiên, việc tiếp theo sẽ thực hành trên github.</li>
</ul>
<p><strong>2. Thao tác với Github:</strong></p>
<ul>
<li>Git và Github là 2 thứ hoàn toàn khác nhau. Git là 1 DVCS như mình đã giới thiệu từ ban đầu. Còn Github là 1 dịch vụ cung cấp các repo online mà người dùng sử dụng để tạo các kho chứa của riêng mình.</li>
<li>Đầu tiên, các bạn truy cập vào https://github.com/ và đăng kí 1 tài khoản.</li>
<li>Bước tiếp theo khá quan trọng, trên terminal các bạn thực hiện lệnh <code class="highlighter-rouge">ssh-keygen</code>, việc này sẽ tạo 1 <code class="highlighter-rouge">private key</code>, 1 <code class="highlighter-rouge">public key</code>, sau đó copy <code class="highlighter-rouge">public key</code> để chuẩn bị thực hiện bước tiếp theo (bước tạo ssh-key này bạn có thể xem phần hướng dẫn sử dụng git trên window)</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>╰─➤ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/phanhoang/.ssh/id_rsa): /home/phanhoang/.ssh/id_rsa_test
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/phanhoang/.ssh/id_rsa_test.
Your public key has been saved in /home/phanhoang/.ssh/id_rsa_test.pub.
The key fingerprint is:
4a:8d:bc:ec:27:5a:c6:01:da:14:a6:61:57:7b:c3:f5 phanhoang@phanhoang-PC
The key's randomart image is:
+--[ RSA 2048]----+
| o +.. . |
| . = . o . . |
| . o . + E |
| + o + . |
| . . = S |
| + + |
| B |
| +. . |
| ...o |
+-----------------+
(venv) ╭─phanhoang@phanhoang-PC ~
╰─➤ cat /home/phanhoang/.ssh/id_rsa_test.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC05XxMT7Nu9X//DrANSxMMP/HcWFD6ntBX0VkXqplIkq9BmHqQr4c6rclfI5P8A8ZMKaNHiH91OjdbJYqkYvW4tvvHl3qDVcc1/5q81iW3MZeCmCroa0Z7cTCD6eHVZcXoHGq/sZ2BBirBckdoKBb9/chJdEzvEPhpQ9ar3SiQNuOuVuiObkgg67sUuZj/2VazV9usVp962aSxrsnwEesTgnIqkLbErHCAaYgaPz4RsH+xYHwogRXF+PzAFF90ec0hPpJCcktKuaiP80JmMR3nPBgnFfu0/ZmgeO28FvA5nkxJTYN+4hQI4bEC6ZCums0MpX7wfSD/iKsRwTctOZMR phanhoang@phanhoang-PC
</code></pre></div></div>
<ul>
<li>Sau khi đã copy key, trên tài khoản github, mọi người chọn settings > SSH and GPG keys > chọn New SSH keys. Dán key vừa copy vào <code class="highlighter-rouge">Key</code>, thêm <code class="highlighter-rouge">Title</code> và chọn <code class="highlighter-rouge">Add SSH key</code>.</li>
</ul>
<p><img src="http://i.imgur.com/9Q4AF9H.png" alt="Add SSH key" /></p>
<ul>
<li>Bước tiếp, trên github, các bạn tạo mới 1 <code class="highlighter-rouge">repository</code> ở góc trên cùng bên phải. Đặt tên repo, description, rồi chọn tạo mới repo:</li>
</ul>
<p><img src="http://i.imgur.com/jm8M6Tw.png" alt="Create Repo" /></p>
<p><img src="http://i.imgur.com/pvE9BcY.png" alt="" /></p>
<ul>
<li>Ở đây có 2 tùy chọn. Thứ nhất là bạn đã có sẵn 1 thư mục trên máy là muốn link thư mục trên local đồng bộ với thư mục trên github, bạn thực hiện lệnh:’</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git remote add origin `tên đường dẫn đến repo của bạn`
</code></pre></div></div>
<ul>
<li>Hoặc đơn giản bạn chỉ muốn kéo repo đó về, thực hiện lệnh:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone `tên đường dẫn tới repo của bạn`
</code></pre></div></div>
<ul>
<li>Ở đây để đơn giản, mình sẽ clone repo về máy:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~
╰─➤ git clone git@github.com:huyhoang17/test.git
Cloning into 'test'...
warning: You appear to have cloned an empty repository.
Checking connectivity... done.
(venv) ╭─phanhoang@phanhoang-PC ~
╰─➤ ls | grep test
test
(venv) ╭─phanhoang@phanhoang-PC ~/test ‹master›
╰─➤ cd test
</code></pre></div></div>
<ul>
<li>Giờ cả repo trên local và trên github đều chưa có bất kì file nào. Ta tạo mới 1 file trên local rồi cũng thực hiện các thao tác cơ bản như ở trên: <code class="highlighter-rouge">git add 'tên file' và git commit -m 'tên lời nhắn'</code>:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/test ‹master›
╰─➤ echo "Hello Git, Github" >> README.md
(venv) ╭─phanhoang@phanhoang-PC ~/test ‹master*›
╰─➤ ls
README.md
(venv) ╭─phanhoang@phanhoang-PC ~/test ‹master*›
╰─➤ git add README.md
(venv) ╭─phanhoang@phanhoang-PC ~/test ‹master*›
╰─➤ git commit -m "add README.md"
[master (root-commit) 026a01e] add README.md
1 file changed, 1 insertion(+)
create mode 100644 README.md
(venv) ╭─phanhoang@phanhoang-PC ~/test ‹master›
╰─➤ git status
On branch master
Your branch is based on 'origin/master', but the upstream is gone.
(use "git branch --unset-upstream" to fixup)
nothing to commit, working directory clean
</code></pre></div></div>
<ul>
<li>Hiện tại repo trên máy mình đã có 1 file <code class="highlighter-rouge">README.md</code> nhưng bây giờ bạn thử truy cập repo đó trên github thì hoàn toàn chưa thấy file đó. Để thực hiện đẩy file sau khi đã commit lên github, ta thực hiện lệnh:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/test ‹master›
╰─➤ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 237 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:huyhoang17/test.git
* [new branch] master -> master
</code></pre></div></div>
<ul>
<li><code class="highlighter-rouge">master</code> chính là tên nhánh ban đầu bạn làm việc. Ta sẽ bàn về việc tạo nhánh trong phần sau của hướng dẫn. Như bạn đã thấy, git đã thực hiện thành công việc đẩy file lên github. Bây giờ bạn thử truy cập lại repo trên Github mà xem, BINGO …:</li>
</ul>
<p><img src="http://i.imgur.com/PBbEJhc.png" alt="BINGO !" /></p>
<ul>
<li>Như vậy bây giờ, thư mục trên máy và trên github đã được đồng bộ với nhau. Giả sử bây giờ mình tạo 1 file mới ngày trên github tên <code class="highlighter-rouge">abc.py</code>. Khi đó để cập nhật file đó xuống dưới local, bạn thực hiện lệnh:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/test ‹master›
╰─➤ git pull
Updating 026a01e..0e3215d
Fast-forward
abc.py | 1 +
1 file changed, 1 insertion(+)
create mode 100644 abc.py
(venv) ╭─phanhoang@phanhoang-PC ~/test ‹master›
╰─➤ ls
abc.py README.md
</code></pre></div></div>
<ul>
<li>Đó là 1 số các hướng dẫn cơ bản khi làm việc với git và các dịch vụ quản lí repo như github.</li>
</ul>
<h2 id="iii-hướng-dẫn-nộp-bài-tập-qua-git-cho-học-viên-pyfml"><strong>III. Hướng dẫn nộp bài tập qua git cho học viên PyFML</strong></h2>
<ul>
<li>Tạo tài khoản gitlab ( gitlab cũng là 1 dịch vụ quản lí repo như github, nhưng cho phép tạo repo private miễn phí, bạn có thể xem thêm phần phụ lục ở cuối bài ):</li>
<li>Thêm <code class="highlighter-rouge">SSH-KEY</code> trên tài khoản gitlab của bạn (tương tự như github ở bên trên).</li>
<li>Clone project:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://gitlab.com/pyfml/pyfml
</code></pre></div></div>
<ul>
<li>Kiểm tra nhánh ( branch ):</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/workspace/pyfml ‹master›
╰─➤ ls
01_lecture.rst 05_lecture.rst 09_lecture.rst 12_lecture.rst FAQ.rst lectures.rst requirements-doc.txt untitled.txt
02_lecture.rst 06_lecture.rst 10_lecture.rst conf.py final-exam.rst Makefile requirements-freeze.txt whatnext.rst
03_lecture.rst 07_lecture.rst 11_flask exercises git.rst nopbai.py requirements.txt
04_lecture.rst 08_lecture.rst 11_lecture.rst exercises.rst index.rst README.rst Resource
(venv) ╭─phanhoang@phanhoang-PC ~/workspace/pyfml ‹master›
╰─➤ git branch
* master
</code></pre></div></div>
<p>Như bạn thấy, hiện tại chỉ có duy nhất 1 nhánh tên <code class="highlighter-rouge">master</code>. Sau khi clone về bạn tạo mới 1 nhánh trên repo của bạn bằng lệnh <code class="highlighter-rouge">git checkout -b 'tên nhánh'</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/workspace/pyfml ‹master›
╰─➤ git checkout -b hoang
Switched to a new branch 'hoang'
(venv) ╭─phanhoang@phanhoang-PC ~/workspace/pyfml ‹hoang›
╰─➤ git branch
* hoang
master
</code></pre></div></div>
<p>Hiện tại thì bạn đang làm việc trên nhánh <code class="highlighter-rouge">hoang</code>. Ví dụ bài tập tuần 3, bạn tạo mới 1 nhánh con tên <code class="highlighter-rouge">hoang_bai3</code> chẳng hạn, sau đó tạo mới 1 thư mục <code class="highlighter-rouge">hoang_ex3</code> chứa toàn bộ các file bài tập của tuần 3 (hiện tại bạn đang đứng trên branch <code class="highlighter-rouge">hoang_bai3</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/workspace/pyfml ‹hoang›
╰─➤ git checkout -b hoang_bai3
Switched to a new branch 'hoang_bai3'
(venv) ╭─phanhoang@phanhoang-PC ~/workspace/pyfml ‹hoang_bai3›
╰─➤ git branch
hoang
* hoang_bai3
master
(venv) ╭─phanhoang@phanhoang-PC ~/workspace/pyfml ‹hoang_bai3›
╰─➤ mkdir hoang_ex3
</code></pre></div></div>
<ul>
<li>Để chuyển sang nhánh khác, thực hiện lệnh <code class="highlighter-rouge">git checkout 'tên nhánh'</code>:</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(venv) ╭─phanhoang@phanhoang-PC ~/workspace/pyfml ‹hoang_bai3›
╰─➤ git checkout hoang
Switched to branch 'hoang'
</code></pre></div></div>
<ul>
<li>Khi nộp bài tập, các bạn cũng thực hiện các lệnh <code class="highlighter-rouge">git add</code>, <code class="highlighter-rouge">git commit</code> trên branch bài tập tương ứng từng tuần (vd: hoang_bai3) và commit lên gitlab (lưu ý: tuyệt đối không push bài tập trên branch <code class="highlighter-rouge">master</code> ):</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git push origin hoang_bai3
</code></pre></div></div>
<ul>
<li>Thực hiện tạo Merge Request trên Gitlab. Chú ý chọn <code class="highlighter-rouge">Source branch</code> là <code class="highlighter-rouge">hoang_bai3</code>, <code class="highlighter-rouge">Target branch</code> là <code class="highlighter-rouge">hoang</code>. Assign lại cho các giảng viên và trợ giảng để review code của bạn.</li>
</ul>
<h2 id="iv-phụ-lục"><strong>IV. Phụ lục</strong>:</h2>
<ul>
<li>Git tutorial: https://git-scm.com/book/en/v2</li>
<li>
<p>How to add a new SSH key to your GitHub account: https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/</p>
</li>
<li>
<p>Điểm khác nhau giữa Github và Gitlab:</p>
<ul>
<li>
<p>Giống nhau: Cả hai đều là các dịch vụ quản lí repo ( thư mục chứa mã nguồn của bạn ), không giới hạn số lượng repo bạn tạo ra.</p>
</li>
<li>
<p>Khác nhau:</p>
<ul>
<li>Gitlab cho phép bạn có thể tạo repo private mà không phải trả phí, với Github bạn sẽ phải trả phí khi muốn tạo 1 repo private.</li>
<li>Gitlab cung cấp giao diện trực quan hơn, nhiều tùy chọn hơn, thuận tiện hơn trong việc review bài tập của học viên.</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr />Hướng dẫn cơ bản về git cho người mới bắt đầuWelcome to Jekyll!2017-04-21T17:11:33+00:002017-04-21T17:11:33+00:00/jekyll/welcome/2017/04/21/welcome-to-jekyll<p>You’ll find this post in your <code class="highlighter-rouge">_posts</code> directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run <code class="highlighter-rouge">jekyll serve</code>, which launches a web server and auto-regenerates your site when a file is updated.</p>
<p>To add new posts, simply add a file in the <code class="highlighter-rouge">_posts</code> directory that follows the convention <code class="highlighter-rouge">YYYY-MM-DD-name-of-post.ext</code> and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works.</p>
<p>Jekyll also offers powerful support for code snippets:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">print_hi</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"Hi, </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="n">print_hi</span><span class="p">(</span><span class="s1">'Tom'</span><span class="p">)</span>
<span class="c1">#=> prints 'Hi, Tom' to STDOUT.</span></code></pre></figure>
<p>Check out the <a href="https://jekyllrb.com/docs/home">Jekyll docs</a> for more info on how to get the most out of Jekyll. File all bugs/feature requests at <a href="https://github.com/jekyll/jekyll">Jekyll’s GitHub repo</a>. If you have questions, you can ask them on <a href="https://talk.jekyllrb.com/">Jekyll Talk</a>.</p>You’ll find this post in your _posts directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run jekyll serve, which launches a web server and auto-regenerates your site when a file is updated.