파이썬 회문 판별, N-gram만들기

Yeonu·2020년 11월 21일
0

Python 이론

목록 보기
15/30
post-thumbnail
post-custom-banner

회문은 유전자 염기서열 분석에서 많이 쓰고, N-gram은 빅 데이터 분석, 검색 엔진에서 많이 쓰인다.

회문

회문(palindrome)은 순서를 거꾸로 읽어도 제대로 읽은 것과 같은 단어와 문장을 말한다. ex) "level", "SOS", "rotator", "nurses run"
회문 판별하기 : 회문은 첫 번째 글자와 마지막 글자가 같다. 그리고 안쪽으로 한 글자씩 좁혔을 때 글자가 서로 같으면 회문이다.

반복문으로 문자 검사하기

word = input('단어를 입력하세요: ')

is_palindrome = True                 # 회문 판별값을 저장할 변수, 초깃값은 True
for i in range(len(word) // 2):      # 0부터 문자열 길이의 절반만큼 반복
#첫번째, 마지막 문자열 비교를 위한 if문
    if word[i] != word[-1 - i]:      # 왼쪽 문자와 오른쪽 문자를 비교하여 문자가 다르면
        is_palindrome = False        # 회문이 아님
        break

print(is_palindrome)                 # 회문 판별값 출력
#회문이면 True아니면 False 반환

시퀀스 뒤집기로 문자 검사하기

word = input('단어를 입력하세요: ')
print(word == word[::-1])    # 원래 문자열과 반대로 뒤집은 문자열을 비교

word[::-1]은 문자열 전체에서 인덱스를 1씩 감소시키면서 요소를 가져오므로 문자열을 반대로 뒤집는다.

리스트와 reversed 사용하기

>>> word = 'level'
>>> list(word) == list(reversed(word))
True

문자열의 join 메서드와 reversed 사용하기

>>> word = 'level'
>>> word == ''.join(reversed(word))
True

문자열을 뒤집고 join으로 공백없이('')연결한다. 위 두 방법과 동일하다.


N-gram

N-gram은 문자열에서 N개의 연속된 요소를 추출하는 방법이다. 'Hello'라는 문자열을 문자(글자) 단위 2-gram으로 추출하면 다음과 같다.

He
el
ll
lo

반복문으로 N-gram 출력하기

text = 'Hello'
for i in range(len(text) - 1):  # 2-gram이므로 문자열의 끝에서 한 글자 앞까지만 반복함
				# Hello 01234 중 인덱스 3까지만 반복
   print(text[i], text[i + 1], sep='')  # 현재 문자와 그다음 문자 공백 없이 출력

3-gram이라면 반복 횟수는 range(len(text) - 2))와 같이 되고, 문자열 끝에서 두 글자 앞까지 반복하면 된다. 문자열을 출력할 때는 print(text[i], text[i + 1], text[i + 2], sep='')가 된다.

text = 'this is python script'
words = text.split()            # 공백을 기준으로 문자열을 분리하여 리스트로 만듦
for i in range(len(words) - 1): # 2-gram이므로 리스트의 마지막에서 요소 한 개 앞까지 반복
   print(words[i], words[i + 1]) # 현재 문자열과 그다음 문자열 출력

zip으로 2-gram 만들기

zip 함수는 반복 가능한 객체의 각 요소를 튜플로 묶어준다.

 ```
text = 'hello'
two_gram = zip(text, text[1:])
for i in two_gram:
    print(i[0], i[1], sep='')
```

zip(text, text[1:])은 문자열 text와 text[1:]의 각 요소를 묶어서 튜플로 만든다. text[1:]은 인덱스 1(두 번째 문자)부터 마지막 문자까지 가져온다. 따라서 text와 text[1:]을 zip으로 묶으면 문자 하나가 밀린 상태로 각 문자를 묶는다.

 ```
>>> text = 'hello'
>>> list(zip(text, text[1:]))
[('h', 'e'), ('e', 'l'), ('l', 'l'), ('l', 'o')]
```

이렇게 2-gram 리스트가 만들어진다. 이 리스트를 출력할 때는 for i in two_gram:와 같이 for로 반복하면서 print(i[0], i[1], sep='')로 튜플의 요소를 출력한다.
3-gram을 만들고 싶다면 zip(words, words[1:], words[2:])와 같이 word, word[1:], word[2:] 3개의 리스트를 넣으면 된다.

zip과 리스트 표현식으로 N-gram 만들기

아래는 3-gram에 필요한 슬라이스다. [text[i:] for i in range(3)]처럼 for로 3번 반복하면서 text[i:]로 리스트를 생성했다. 여기서 for i in range(3)는 0, 1, 2까지 반복하므로 text[i:]는 text[0:], text[1:], text[2:]가 된다.

>>> text = 'hello'
>>> [text[i:] for i in range(3)]
['hello', 'ello', 'llo']

리스트 ['hello', 'ello', 'llo']를 zip에 넣는다.

>>> list(zip(['hello', 'ello', 'llo']))
[('hello',), ('ello',), ('llo',)]

3-gram이 아니다. zip은 반복 가능한 객체 여러 개를 콤마로 구분해서 넣어줘야 하는데 ['hello', 'ello', 'llo']은 요소가 3개 들어있는 리스트 1개이기 때문이다.
zip에 리스트의 각 요소를 콤마로 구분해서 넣어주려면 리스트 앞에 *를 붙여야 한다.

>>> list(zip(*['hello', 'ello', 'llo']))
[('h', 'e', 'l'), ('e', 'l', 'l'), ('l', 'l', 'o')]

리스트 표현식(comprehension)을 바로 zip에 넣어주려면 리스트 표현식 앞에 *를 붙이면 된다.

>>> list(zip(*[text[i:] for i in range(3)]))
[('h', 'e', 'l'), ('e', 'l', 'l'), ('l', 'l', 'o')]
post-custom-banner

0개의 댓글