티스토리 뷰

study/Django

한글 형태소 분석기 Okt

xoxowo 2023. 7. 3. 00:22

게시판 app을 만들기로 계획하면서 커뮤니티 게시판과 공지사항 게시판은 다르게 만들어보고 싶었는데,

어떤 게시글 안에 자주 등장하는 단어를 필터링하여 다른 게시글에서도 등장하면 게시글들을 가져와 게시글 하단에 연관 게시글이 추가로 보이게 화면에 그리는 게 목표였다.

 

게시글에서 등장하는 단어를 필터링하기 위해선 형태소 분석을 한 단어들이 몇 번 등장했는지 카운트한 뒤,

제일 많이 많이 등장한 단어를 가지고 다른 게시글들에 해당 단어로 필터링한 후 게시글을 정렬하도록 코드를 작성해 봤다.

 

한글 형태소 분석기는 Okt, Komoran, Kkma, Mecab가 있는데 프로젝트에는 Okt를 사용했다.

(각 형태소 분석기마다 연산속도가 다를 수 있고, 한글 문장 안에 영어 및 숫자가 있을 경우 오류가 발생할 수 있으므로 프로젝트에 어떤 분석기를 사용할지 분석기에 대해 잘 알아보는 것이 중요하다.)

 

 

→ 폴더명\hyj\board\views.py

from konlpy.tag import Okt
# 기타 import 생략

def detail_post(request, pk):
    try:
        post = Post.objects.get(pk=pk)
        main_post = Post.objects.get(pk=pk)
        
        okt = Okt()
        korean_nouns = okt.nouns(post.content)
        korean_nouns_counter = Counter(korean_nouns)

        # 빈도수가 60% 이하인 단어 필터링
        total_count = Post.objects.aggregate(total_count=Count('id'))['total_count']
        filtered_korean_nouns = [noun for noun, count in korean_nouns_counter.items() if count/total_count < 0.6 and count >= 2]

        related_posts = Post.objects.none()

        for noun in filtered_korean_nouns:
            related_posts |= Post.objects.filter(content__icontains=noun).exclude(id=post.id)

        # 게시글 중복 제거 후 게시글 정렬
        related_posts = related_posts.distinct()
        related_post_counts = {}

        for related_post in related_posts:
            related_korean_nouns = okt.nouns(related_post.content)
            related_korean_nouns_counter = Counter(related_korean_nouns)
            
            # 빈도수가 40% 이하이면서 2개 이상의 단어가 동시에 나타나는 글만 고려
            filtered_related_korean_nouns = [noun for noun in related_korean_nouns_counter if noun in filtered_korean_nouns]

            related_korean_nouns_count = sum([related_korean_nouns_counter[noun] for noun in filtered_related_korean_nouns])

            # 전체 게시글에서 카운트된 단어의 비율 계산
            related_post_counts[related_post] = related_korean_nouns_count / total_count
            
        sorted_related_posts = [post for post, count in sorted(related_post_counts.items(), key=lambda x: x[1], reverse=True)]

        context = {'main_post': main_post, 'related_posts': sorted_related_posts}
        
        return render(request, 'board/detail.html', context)
    
    except Post.DoesNotExist:
        return render(request, 'board/exist.html', status=404)

 

 

아래와 같이 한 문장을 게시글로 작성했을 때, 문장에 등장하는 빈도가 60% 이하인 단어 필터링을 한 뒤 

필터링한 단어들로 게시글을 검색한다. 그리고 게시글들을 다시 for문으로 돌면서 다시 빈도수가 40% 이하면서, 2개 이상의 단어가 동시에 나타나는 글만 고려한 뒤 연관 게시글로 출력한다.

 

유소년에게서 만천하의 행복스럽고 약동하다. 그들의 방황하였으며, 실현에 부패뿐이다. 희망의 석가는 인생영락과 어디 옷을 말이다. 맺어, 이상의 너의 피고, 것이다. 구할 가지에 현저하게 대고, 우리의 이 평화스러운 없으면, 있는가? 같은 대고, 청춘 것이다. 인생의 못하다 그들은 말이다. 찬미를 아니더면, 별과 곳으로 얼음이 공자는 칼이다. 이는 그들은 소담스러운 영락과 주며, 무엇을 뿐이다. 투명하되 청춘이 봄날의 것이 보라.

 

얼음이 같이 새 이상, 길지 보이는 바이며, 약동하다. 관현악이며, 인간우리 풀밭에 내는 있는 살 그들은 그리하였는가? 무엇이 커다란 생명을 피어나기 원질이 반짝이는 청춘의 하였으며, 인간의 아니다. 커다란 피는 없으면, 이것이다. 주는 보내는 것이다. 보라, 대중을 봄바람이다. 길지 위하여서, 따뜻한 같이, 얼마나 우는 열락의 사막이다. 풀이 청춘을 산야에 운다. 무엇을 꽃이 가장 그들을 뜨고, 아름답고 하여도 찾아 우리 교향악이다. 들어 얼음이 날카로우나 때에, 있는 있으랴?

 

 

빈도수가 60% 이하인 단어 필터링

['약동', '그', '인생', '영락', '말', '이상', '것', '대고', '우리', '청춘', '얼음', '무엇', '보라', '인간']

 

→위 문장에서 2번 이상 자주 등장하는 단어들을 필터링한 결과다. 

 

필터링한 단어들로 검색한 게시글들 모음
<QuerySet [<Post: 테스트 데이터 18>, <Post: 테스트 데이터 19>, <Post: 테스트 데이터 20>, <Post: 테스트 데이터 21>, <Post: 테스트 데이터 22>, <Post: 테스트 데이터 23>]>

 

→ 위 단어로 게시글을 검색했을 때 나오는 모든 게시글들의 모음이다.

 

빈도수가 40% 이하면서, 2개 이상의 단어가 동시에 나타나는 글

['약동', '그', '인생', '영락', '말', '이상', '것', '대고', '우리', '청춘', '얼음', '무엇', '보라', '인간']
39
['약동', '그', '인생', '영락', '말', '이상', '것', '대고', '우리', '청춘', '얼음', '무엇', '보라', '인간']
39
['것', '청춘', '얼음', '이상', '우리', '그', '인생', '인간', '약동', '무엇']
28
['것', '청춘', '얼음', '이상', '우리', '그', '인생', '인간', '약동', '무엇']
28
['무엇', '그', '청춘', '약동', '것', '얼음']
12
['무엇', '그', '청춘', '약동', '것', '얼음']
12

 

→ 게시글들을 for문으로 돌면서 처음 60% 으로 필터링한 단어들 중 2개 이상이면서 그 단어의 빈도수가 40% 이하인 단어들을 프린트했을 때 나오는 단어들이다. 총 6개의 개시글들 내부에 위 두조건을 만족하는 단어들을 프린트했고, 하단에 39와 같은 단어들은 게시글 내부에 해당 단어들이 총 몇번 등장했는지 알 수 있다.

 

 

'study > Django' 카테고리의 다른 글

django.contrib.auth  (0) 2023.06.15
authenticate() 함수  (0) 2023.05.29
Template - 검색 결과 내 페이지네이션  (0) 2023.05.22
Template 기본 구조  (0) 2023.05.11
Django - AWS S3 파일 업로드  (0) 2023.04.14
댓글