카테고리 없음

뉴스분석 및 요약서비스(키워드 랭킹 순위)

hearai 2025. 1. 13. 17:39

 

주말없이 밤낮을 고생하며 키워드 순위를 구현했다. 가장 많은 어려움은 명사를 추출하는 부분과 okt.nouns가 걸러내지 못하는 부분을 정제하는 부분이었다. 패턴분석을 우선해 키워드에 추가했고, 나머지 키워드를 처리하도록 했다. 순위는 빈도수에 초점을 두지만 동시 출현 빈도 임계값을 0.8로 두어 연관 키워드를 판단하고 그룹화하여 중복을 제거했다. 즉, 경호처장(5)과 경호처(3)가 같이 등장하면 짧은 단어가 긴 단어에 포함되었다고 해석하고 더 긴 키워드를 선택하게 되며, 빈도수는 8건으로 합산된다. 이를 통해 유사한 관련 키워드를 그룹화하여 관리하고, 의미적 연관성은 보존하여 현재 중요한 이슈를 파악할 수 있다.

if (keyword in existing or existing in keyword or  # 포함 관계 체크
    (keyword in cooccurrence and                   # 동시 출현 체크 시작
     existing in cooccurrence[keyword] and         # 두 키워드가 함께 등장했는지
     cooccurrence[keyword][existing] >= min(keyword_count[keyword], keyword_count[existing]) * 0.8)): # 동시 출현 빈도 임계값
     
     # 메인 키워드 선택
     main_keyword = keyword if len(keyword) > len(existing) else existing
     
     # 빈도수 합산
     counts[main_keyword] = counts.get(main_keyword, 0) + count
     
     # 연관 키워드 그룹화
     if main_keyword not in keyword_groups:
    keyword_groups[main_keyword] = {existing, keyword}
else:
    keyword_groups[main_keyword].add(keyword)

news_items count: 100
keyword_rankings: [('경호처', 14, {'경찰', '경호처'}), ('윤석열', 7, {'윤석열'}), ('이재명', 7, {'이재명'}), ('북한', 6, {'북한'}), ('영장', 6, {'영장'}), ('민주', 5, {'민주'}), ('산불', 5, {'산불'}), ('박정훈', 4, {'박정훈', '무죄'}), ('코로나', 4, {'코로나'}), ('헌재', 4, {'헌재'})]
filtered articles count: 53

 

로거를 분석하면 100개의 기사를 비교하여 가장 많이 나온 키워드를 랭킹에 올린 것을 알 수 있다. 키워드별 주요 기사는 중복 기사가 포함되어 있으나 언론사별 주요기사는 53건으로 중복 없이 확인할 수 있다. 키워드 수가 같을 경우 가나다 순으로 정렬했다.

 

news/utils.py - 뉴스 키워드 추출 유틸리티

주요 기능:
1. 한자 처리
2. 명사 추출 (OKT 활용)
3. 복합어 처리
4. 특수 패턴 처리 (정당명, 인명 등)
5. 키워드 빈도수 계산
6. 연관 키워드 그룹화

패턴 구조:
1. COMMON - 기본 패턴 상수
   - PERSON_RELATED: 직위/직책/인물 관련 (예: 장관, 총리, 스님)
   - ORGANIZATION_RELATED: 기관/단체 관련 (예: 정부, 위원회, 협회)
   - PLACE_RELATED: 시설/장소 관련 (예: 성당, 법원, 청사)
   - JOSA: 한국어 조사 및 어미 패턴

2. PARTY_NAMES - 정당명 집합
   - 현재 활동 중이거나 역사적으로 중요한 정당들의 정확한 매칭
   - (예: 국민의힘, 더불어민주당, 개혁신당, 조국혁신당 등)

3. STOP_WORDS - 불용어 집합
   - 뉴스/미디어 관련 용어
   - 행위/절차/업무 관련 용어
   - 문법 요소 (조사/어미/대명사)
   - 기타 일반 명사

4. COMPOUND_WORD_PATTERNS - 복합 단어 패턴
   - 기본 복합어 (COMMON 패턴 활용)
     * 기관/단체명 (예: 검찰청, 국정원)
     * 직책/직위명 (예: 검찰총장, 경찰청장)
     * 시설/장소명 (예: 서울청사, 중앙성당)
   - 특수 복합어 (뉴스 특화)
     * 법률/수사 관련 (예: 구속영장, 살인용의자)
     * 사건/사고 관련 (예: 이태원참사, 무안사고)
     * 공공기관/시설 (예: 형사기동대, 무안공항)
     * 단체/조직명 (예: 백골단, 1기동단, 구조단)

5. NAME_PATTERNS - 인명 패턴
   - 정부/공공 인사 (예: 홍길동 장관)
   - 혼합 이름 (예: John 김, 김 Smith)
   - 접미사 포함 이름 (예: 홍길동씨, 김철수군)

 

🥕okt.nouns 와 okt.pos 그리고 mecab

처음엔 KoNLPy 형태소 분석기의 Okt 기능을 보완하고자 Mecab을 결합해 쓰고자 했었다. Mecab은 속도가 빠르고 정확도가 높다고 알려져 있고, OKT 한국어에 특화되어 있지만 상대적으로 느리다고 알려져 있다.

Mecab: 세분화된 태그 체계 (예: NNG, NNP, VV, VA 등)
Okt: 단순화된 태그 체계 (예: Noun, Verb, Adjective 등)

 

 두 분석기의 장점을 결합하려는 시도를 했으나 불필요한 중복 코드가 발생하고, 두 분석기의 결과가 다를 때 처리가 복잡해졌다. 또한 통일된 기준으로 처리하기가 어려워지고, 처리 시간도 늘어났다. 결과적으로 신조어 처리는와 뉴스 텍스트에 강점이 있는 OKT.nouns()를 채택했고, 부족한 부분을 stop words와 패턴으로 처리했다. 

 

🥕패턴 처리

Okt의 기능을 보완하고자 시도한 과도한 전처리는 서로 충돌하거나 장점을 상쇄시켰다. 그리고 복잡한 로직으로 인한 오류 가능성이 증가하고, 처리된 단어를 다시 처리하면서 오히려 정확도가 하락했다. 그래서 원점으로 돌아가 Okt.nouns를 기반으로 다시 작업했다. 먼저 대괄호를 제거하고 공백 처리한 후 한자를 제거했다. 이후의 작업 순서는 다음과 같다. 같은 작업을 반복하지 않도록, 이전 단계를 이어받도록 했다.

 

OKT 기본 명사 추출 (1단계)
일반적인 명사를 문맥을 보고 정확하게 추출
예: "대통령", "수사", "변호인" 등 기본 명사
복합어 패턴 체크 (2단계)
OKT가 분리할 수 있는 복합어를 하나로 잡아냄
예: "내란 수사", "선임계" 같은 복합어
'■' not in word로 이미 추출된 단어는 제외
정당 이름 체크 (3단계)
정확한 정당명을 온전히 추출
예: "국민의힘", "더불어민주당" 등
'■' not in party로 이미 추출된 정당명은 제외
특수 패턴 처리 (4단계)
인명이나 직책 등 특수한 패턴 포착
예: "윤 대통령", "김 위원장" 등
'■' not in name로 이미 추출된 이름은 제외

 

뉴스 제목들에서 주요 키워드를 추출하는 함수

처리 흐름:
    1. 전처리 단계
       - 대괄호 제거 및 공백 정리
       - 한자 제거
       - OKT를 사용한 명사 추출
       - 불용어(stop_words) 1차 필터링
    
    2. 키워드 분류 단계
       - 복합어 (1순위): COMPOUND_WORD_PATTERNS 매칭
       - 정당명 (2순위): PARTY_NAMES 매칭
       - 인명 (3순위): NAME_PATTERNS 매칭
       - 일반명사 (4순위): 위 패턴에 해당하지 않는 나머지
    
    3. 우선순위 처리 단계
       - 각 카테고리별로 5개 이상 시 독립 처리
       - 5개 미만 시 일반명사로 통합
       - 중복 제거 (순서 유지)
    
    4. 후처리 단계
       - 마스킹된 단어 필터링 (■ 등 특수문자 처리)
       - 불용어 2차 필터링
       - 제목당 키워드 수 제한
    
    5. 키워드 빈도 분석 단계
       - 전체 키워드 빈도수 계산
       - 동시 출현 빈도 계산
       - 포함 관계 처리
       - 연관 키워드 그룹화
    
    6. 결과 정렬 및 반환
       - 빈도수 기준 내림차순 정렬
       - limit 개수만큼 상위 키워드 반환
       - (키워드, 빈도수, 연관키워드 그룹) 형태로 반환
    
    Args:
        titles (list): 분석할 뉴스 제목 리스트
        limit (int): 반환할 최대 키워드 수 (기본값: 10)
        keywords_per_title (int): 제목당 추출할 최대 키워드 수 (기본값: 5)
    
    Returns:
        list: (키워드, 빈도수, 연관키워드 집합) 튜플의 리스트

 

🥕키워드 선정

현재 최종 키워드 10개 추출하는데 있어 다양한 언론사의 기사를 고르게 반영하고, 전체 기사에서의 빈도수도 고려하고자 했다.
제목당 5개로 키워드 추출을 제한해 특정 기사/언론사의 키워드가 과다 대표되는 것 방지하였고, 빈도수 기반 최종 선택함으로써 여러 기사에서 언급된 중요 키워드 포착하고자 했다. 

키워드 리스트를 전처리하고 중복을 제거하는 함수

처리 흐름:
    1. 전처리 단계
       - 각 키워드의 앞뒤 공백 제거
       - 이미 처리된 단어 추적을 위한 set 생성
    
    2. 중복 및 포함 관계 처리
       - 이미 처리된 단어 스킵
       - 다른 키워드의 부분 문자열인지 확인
       - 독립적인 키워드만 선택
    
    3. 결과 반환
       - 전처리된 고유 키워드 리스트 반환
    
    Args:
        keywords_list (list): 처리할 키워드 리스트
    
    Returns:
        list: 전처리된 고유한 키워드 리스트

 

키워드 랭킹을 기반으로 분석과 요약도 진행될 예정이다. 클린 코드의 중요성과 가장 단순한 곳에 해결책이 있다는 것을 느꼈던 한 주간이었다. 남은 일정동안 뉴스분석/요약 서비스를 배포하기를 기대해본다.