Algorithm/Programmers

[Python] 뉴스 클러스터링

느낌표 공장장 2021. 5. 28. 00:55
# 두글자씩 끊은 다중집합 만들기 
def make_set(str):
    str_set = []
    for i in range(len(str)-1):
        temp = str[i:i+2]   # 두글자씩 끊기 
        if temp.isalpha():  # 글자에 기호나 숫자 없다면
            str_set.append(temp)    # 추가 
    return str_set

def solution(str1, str2):
    str1 = str1.upper() # 대소문자 차이 무시하므로 둘다 대문자로 변환
    str2 = str2.upper()
    
    str1_set = make_set(str1)   # 각 문자열 다중집합으로 만들기 
    str2_set = make_set(str2)
    
    intersection = 0    # 교집합 계산
    for i in str1_set:
        if i in str2_set[:]:
            intersection += 1
            str2_set.remove(i)  # 중복 방지를 위해 삭제 
    
    union = len(str1_set) + len(str2_set)   # 합집합 계산 (str2_set는 str1_set과의 교집합 원소들이 제거된 상태)
    
    if union == 0:  # 합집합 0인경우 1로 처리 -> 따라서 65546 반환
        return 65536
    else:
        return int(intersection / union * 65536)

 


 

처음 코드 

import re

def solution(str1, str2):
    
    def comb(s) :
        temp = []
        s = s.lower()
        is_str = re.compile('[a-z]+')
        
        for i, j in zip(s[:-1], s[1:]) :
            i_str = is_str.match(i)
            j_str = is_str.match(j)
            if i_str == None or j_str == None:
                continue
            else :
                temp.append(i+j)
        return temp
    
    com_1 = comb(str1)
    com_2 = comb(str2)
    
    not_union = len(com_1 + com_2)
    intersection = []
    for i in com_1 :
        if i in com_2 :
            com_2.remove(i)
            intersection.append(i)
            
    union = not_union - len(intersection)           
        
    # 공집합의 경우
    if union == 0:
        return 65536
    else :
        return int((len(intersection) / union) * 65536)

최근 코드(맨 위의 코드)와 처음 코드(바로 위의 코드)와 비교해보니, 두 글자씩 끊은 다중 집합을 만드는 부분이 차이가 있었다.

  • 처음 코드에서는 왜 그랬는지 모르겠지만 정규식 연산을 써서 더 복잡하게 풀었다. ㅋㅋㅋ 아마 알파벳만 추려야하니 '무조건 정규표현식을 써야해'라고 생각했나보다. 
  • 최근 코드에서는 두 글자씩 끊고, 조건문과 isalpha() 함수를 사용해서 두 글자 모두 알파벳인지 확인하고 추가해주었다. 

 


풀이

1) 두 글자씩 끊는 다중 집합 만드는 함수

   def comb(s) :
        temp = []
        s = s.lower()
        is_str = re.compile('[a-z]+')
        
        for i, j in zip(s[:-1], s[1:]) :
            i_str = is_str.match(i)
            j_str = is_str.match(j)
            if i_str == None or j_str == None:
                continue
            else :
                temp.append(i+j)

        return temp

1. 다중집합 원소를 비교할때, 대소문자 구분은 무시하므로 입력받은 문자열(str1 또는 str2)을 소문자로 변환한다.

2. 소문자만(a-z)찾는 정규표현식을 저장하여, match 함수를 통해 입력받은 두 글자 모두 소문자라면(공백, 숫자, 특수문자가 아니라면) temp에 두 글자를 추가해준다.

 

2) 교집합, 합집합 계산

    com_1 = comb(str1)
    com_2 = comb(str2)
    
    not_union = len(com_1 + com_2)
    intersection = [] # 교집합
    for i in com_1 :
        if i in com_2 :
            com_2.remove(i)
            intersection.append(i)
            
    union = not_union - len(intersection) # 합집합

1. 먼저 위의 다중집합 만드는 함수를 str1, str2에 적용시켜준다.

2. 교집합 구하기

     * com_1의 원소가 com_2에 있다면 intersection 리스트에 넣어주고 중복을 방지하기 위해 com_2 에선 삭제한다.

3. 합집합 구하기

     * com_1 과 com_2를 합한 전체 길이에서 교집합의 길이를 빼주면 합집합이 된다.

 

3) 자카드 유사도 출력

    # 공집합의 경우
    if union == 0:
        return 65536
    else :
        return int((len(intersection) / union) * 65536)

1. 만약 합집합이 0인 경우는 두 문자열이 숫자 혹은 특수문자, 공백 등으로 섞여 있어 공집합이 된 경우이기 때문에 1 * 65536 인 65536을 반환한다.

2. 그게 아닐 경우에는 자카드 유사도 식(교집합 / 합집합 * 65536)을 따른다. ( 소수점 버리기 위해 int사용)

 

 

 

'Algorithm > Programmers' 카테고리의 다른 글

[Python] 위장  (0) 2021.06.02
[Python] 메뉴 리뉴얼  (0) 2021.06.02
[Python] 소수 찾기  (0) 2021.05.27
[Python] 전화번호 목록  (0) 2021.05.27
[Python] 괄호변환  (0) 2021.05.26