코딩의 기록

따라하며 배우는 파이썬과 데이터과학 -9. 텍스트를 처리해보자-

모루우 2025. 2. 13. 23:12
728x90
반응형

1. 텍스트 데이터란 무엇인가

텍스트: 인간이 오랫동안 정보를 효율적으로 교환하는 데에 가장 중요한 수단

구조화된 문서: HTML, XML, CSV, JSON

구조화되지 않은 문서: 자연어로 된 텍스트

 

2. 문자열에서 개별 문자들을 뽑아보자

텍스트 슬라이싱과 인덱싱

Monty python(-12 -11 ....... -1)

음수 슬라이싱도 양수 슬라이싱과 마찬가지로 작은 것에서 부터 큰 것으로

 

3. split() 메소드는 문자열을 잘 잘라줘요

문자열을 토큰들의 리스트로 반환

list()로 주어진 객체를 리스트화 할 수 있음 문자열을 개별 문자로 분해하는데 사용

 

4. 문자열을 이어붙이는 것은 파이썬한테는 쉬운 일

join()은 부분 문자열을 모아서 하나의 문자열로 만드는 역할을 하는 함수

','.join([a, b, c])

문자를 문자열 사이에만 넣고 문자열의 앞이나 뒤에는 넣지 않음

replace()로 문자열 사이 사이의 것을 다른 문자로 바꿀 수도 있음

 

5. 대문자와 소문자 변환, 그리고 문자열 삭제

대문자를 소문자로 lower() / 소문자를 대문자로 upper()

첫번째 문자만 대문자로 capitalize()

strip()는 문자열의 첫부분과 끝부분의 공백만 처리, 문자 사이의 공백은 제거하지 않음

lstrip(), rstrip()는 각각 왼쪽 오른쪽

find() 문자열에서 지정된 부분 문자열을 찾아서 그 인덱스를 반환함

 

6. 다양한 문자열 처리 함수와 string 모듈

len(), max(), min(), ord(), chr()은 파이썬 내장 함수로

ord()는 문자에 대한 유니코드 값, chr()은 입력된 유니코드 값에 해당하는 문자를 반환

string 모듈의 ascii_upperence는 알파벳 대문자를, ascii_lowercase는 소문자를 가지고 있음

user = input("문장을 입력하시오: ")

new = ""

for x in user:
    if x.isalpha():
        if ord(x) >= 87:
            new += chr(ord(x) - 22)
        else:
            new += chr(ord(x) + 3)
    else:
        new += x

print("암호화된 문장: ", new)

나는 유니코드의 숫자를 이용해서 풀었는데 odr()로 유니코드로 변환하고 수를 더한 다음 chr로 다시 변환해서 붙임

import string

src_str = string.ascii_uppercase
dst_str = src_str[3:] + src_str[3:]

def cipher(a): # 사용자가 입력한 문자를 uppercase에서 인덱스를 찾은 다음 그거를 암호화 문자열에 그대로 대입해서 리턴
    idx = src_str.index(a)
    return dst_str[idx]

src = input("문장을 입력하시오: ")
print('암호화된 문장 : ', end ='')

for ch in src:
    if ch in src_str:
        print(cipher(ch), end = "")
    else:
        print(ch, end = '')

print()

근데 답지에서는 몇 칸 옮긴 새로운 문자열을 슬라이싱을 통해서 만들고 인덱싱을 한 후 새로운 문자열에서 똑같이 대입하는 수를 사용

 

t = "There's a reason some people are working to make it harder to vote, especially for people of color. It's because when we show up, things change."

tset = set()

tlist = t.split()

for x in tlist:
    x = x.strip().strip(".").strip(",").lower()

    if x in "'":
        xlist = x.split("'")
        tset.add(xlist[0])
        tset.add(xlist[1])
    else:
        tset.add(x)

print("word count: ", len(tset))

나는 정말 중복되는 단어 심지어 줄임말 까지 포함해서 하니까 24단어가 나왔는데 내가 원한 결과는 맞는듯?

근데 실제론 그냥 단어의 개수를 세는 것이었음 그러면 26개임

t = "200820 BLACKPINK Jennie is regarded to have great efeect on KT Mystic Red as it was chosen by 50% of those who prebooked for the Samsung Galaxy Note 20 (LG U+ Mystic Pink 30%, SKT Mystic Blue not disclosed)"

censored_list = ['SKT', 'KT', 'Samsung', 'LG']


for x in censored_list:
    t = t.split(x)
    newt = ""
    for y in t:
        newt += y
        newt += "*"
    t = newt[:-1]

와 이건 좀 빡셌던게 검열하려는 단어 양옆에 뭐가 있으면 안되고 또 strip 해서 그런 부분을 제거한다고 해도 출력할 때는 들어있어야 하므로 strip 했던걸 기억해야 하는데 문제는 그게 또 앞에 있었는지 뒤에 있었는지도 판단해야 하고 그러면 if를 너무 많이 써야 되서 좀 아닌거 같아서 생각을 했는데 그냥 리스트를 만들고 그거를 기준으로 잘라서 자른 문장 앞에 *을 넣어서 대체하는 방식으로 만듦

근데 이렇게 하면 마지막에 항상 *이 들어가게 되서 마지막 거만 슬라이싱 해줌

l = t.lower()
t = "It's Not The Right Time To Conduct Exams. MY DEMAND IN BOLD AND CAPITAL. NO EXAMS IN COVID!!!"

tlist = list(t)

count = 0

for x in tlist:
    if x.isupper():
        count += 1

print("느낌표 개수 :", t.count("!"))
print("대문자 개수 :", count)
import random

while True:
    n = int(input("몇 자리의 비밀번호를 원하십니까? "))
    st = ""
    for i in range(n):
        ch = random.randrange(0, 10)
        st += str(ch)
    print(st)
import random
import string

while True:
    n = int(input("몇 자리의 비밀번호를 원하십니까? "))
    st = ""
    for i in range(n):
        EorM = random.randrange(0,2)
        if EorM == 0:
            ch = random.randrange(0,10)
            st += str(ch)
        else:
            LorU = random.randrange(0, 2)
            if LorU == 0:
                st += random.choice(string.ascii_lowercase)
            else:
                st += random.choice(string.ascii_uppercase)


    print(st)

choice로 string 모듈의 lowercase uppercase 인자?들을 불러왔음

 

7. 정보를 한 눈에 보여주는 워드 클라우드

워드 클라우드(word cloud): 각 단어의 크기가 빈도 또는 중요성을 나타내는 텍스트 데이터 시각화 기술

page(title)을 통해 title을 제목으로 하는 위키백과 페이지를 얻을 수 있고 content를 통해서 텍스트 데이터를 얻을 수 있음

 

WordCloud 클래스로 가로와 세로 길이를 넘겨주고 generate()로 텍스트 데이터를 불러주면 만들어짐

 

이를 이제 화면에 그리면 되는데 이때  맷플롯립을 사용함 imshow()를 이용하여 그릴 수 있음

 

matplotlip(맷플롯립): 시각화와 차트를 그리기 위한 파이썬의 외부 라이브러리

 

import wikipedia
import wordcloud
import matplotlib.pyplot as plt
import namuwiki 

wiki = wikipedia.page('maplestory')
text = wiki.content

wordcloud = wordcloud.WordCloud(width = 2000, height = 1500).generate(text)

plt.figure(figsize = (40, 30))
plt.imshow(wordcloud)
plt.show()

그래서 해봤는데 참고로 파이참에서는 SETTING -> python interreter 에 +를 누르면 된다

근데 이게

WordCloud Only Supported for TrueType fonts

 

WordCloud Only Supported for TrueType fonts

I am trying to generate a word cloud using the WordCloud module in Python, however I see the following error whenever I call .generate Traceback (most recent call last): File "/mnt/6db3226b-...

stackoverflow.com

이 에러가 뜨는데 pip을 업그레이드 하고 pillow라는 라이브러리를 업그레이드 해줘야지 풀림

 

참고로 pillow는 이미지 처리를 위한 라이브러리임

https://search.naver.com/p/crd/rd?m=1&px=468&py=814&sx=468&sy=434&vw=1760&vh=849&bw=672&bh=857&bx=147&by=660&p=iIvjDwpzLiwssKnLT3lssssssao-393403&q=%ED%8C%8C%EC%9D%B4%EC%8D%AC+pillow&ie=utf8&rev=1&ssc=tab.nx.all&f=nexearch&w=nexearch&s=1PwclWnt8k7g4sQJ1XSZLw%3D%3D&time=1738594972159&a=web_gen*w.link&r=4&i=a00000fa_302e24db66e88befd1b183d4%5Efa&u=https%3A%2F%2Fbacktohome.kr%2Fentry%2F%25ED%258C%258C%25EC%259D%25B4%25EC%258D%25AC%25EC%259C%25BC%25EB%25A1%259C-%25EC%259D%25B4%25EB%25AF%25B8%25EC%25A7%2580-%25EC%25B2%2598%25EB%25A6%25AC%25ED%2595%2598%25EA%25B8%25B0-Pillow-%25EC%2582%25AC%25EC%259A%25A9%25EB%25B2%2595&cr=1

 

페이지 이동 알림

 

cr.naver.com

 

pip(python index package): 이름 처럼 수 많은 패키지가 저장되어 있는 곳

파이썬 패키지 관리 프로그램으로 웹브라우저에서 어떻게 어떻게 라이브러리를 다운받는 것 보다 명령어로 간편하게 관리할 수 잇도록 하는 것

 

중지어(stop word):특별한 의미를 갖지 않는 단어들을 자연어 처리에서 일컫는 말

wordcloud 모듈의 STOPWORDS에 집합 데이터로 정의되어 있으며 추가하고 싶으면 합집합을 구해서 새로 만들어서 사용하면 됨

 

https://stackoverflow.com/questions/75888799/wikipedia-api-not-searching-specified-term

 

Wikipedia API not searching specified term

I'm using the Wikipedia API wrapper for Python, and for some queries, it's not searching the term I specified. For example, when I execute the function below: import Wikipedia wikipedia.summary('ma...

stackoverflow.com

import wikipedia
import matplotlib
import wordcloud

s_words = wordcloud.STOPWORDS.union({'one', 'using', 'first', 'two', 'make', 'use'})

wiki = wikipedia.page('Python (programming language)')
text1 = wiki.content

wiki = wikipedia.page('machine learning',auto_suggest=False) #machine learning의 제안이 machine ;earning 이따구로 오류가 나있어서 auto_suggest를 꺼줘야 함
text2 = wiki.content

wordcloud1 = wordcloud.WordCloud(width = 2000, height = 1500, stopwords = s_words).generate(text1)
wordcloud2 = wordcloud.WordCloud(width = 2000, height = 1500, stopwords = s_words).generate(text2)

matplotlib.pyplot.figure(figsize = (40, 30))
matplotlib.pyplot.imshow(wordcloud1)

matplotlib.pyplot.figure(figsize = (40, 30))
matplotlib.pyplot.imshow(wordcloud2)

matplotlib.pyplot.show()

음 일단 figure()를 통해 그림 객체를 생성하고 여기다가 imshow()를 써서 이미지 같은 2d 화상을 출력하는 것을 2번 반복해줘야 함 그다음에 마지막에 show()를 써서 모든 figure들을 보여주게함

 

8. 규칙을 이용해서 문자를 추출하는 정규식과 메타문자

정규식(regular expression): 복잡한 문자열을 처리할 때 사용하는 기법, 문자열을 처리하는 모든 곳에서 사용하는 일종의 형식 언어임

정규식을 사용하려면 re 모듈을 사용해야함

re.search(탐색문자열, 원본문자열)를 사용하면 정규식에 매치되는 문자열을 찾을 수 있음 life가 여기서는 정규식인가?

 

group() 메소드는 정규표현식의 검색 결과가 여러 개일 경우 묶음 (이게 뭔 말인지 모르겠다)

start()와 end()는 정규표현식을 통해 일치하는 문자의 시작과끝 인덱스를 나타냄 0/4

span()은 일치하는 구간을 슬라이싱하기 위한 인덱스를 나타냄 [0, 4]

 

메타문자(meta character):정규표현식에서 [], -, | 같은 특별한 의미를 가지는 문자들

^는 첫단어, $는 끝단어

 

9. 메타문자를 좀 더 상세하게 알아보자

가장 중요한 메타문자는 .과 *

.는 어떤 문자가 와도 상관없다는 의미이고 *은 몇 번 반복되어도 상관없다는 의미

예) A..B = AXXB 즉 ..이 2개라면 어떠한 문자 2개가 와도 상관없다 즉 조건에 맞는다

예) AB* = AXXXXX 즉 어떤 문자에 A다음에 B가 0번 이상 나오면 조건에 맞는다고 판단

 

?메타문자

?는 직전의 문자가 0회 또는 1회 반복한 패턴에 매치됨

위의 *와 비슷해보이나 *는 ABBBB라면 이 전체가 매치된다고 판단하고 ?는 AB만 매치된다고 판단

 

+메타문자

직전의 문자가 1회 이상 많이 반복되는 패턴에 매치됨

 

findall()
정규식을 만족하는 모든 문자열들 추출 가능

search()는 가장 먼저 나타나는 인덱스만 가져오지만 findall()은 이름에 걸맞게 전부 가져옴

 

10. 정규식을 활용해서 멋지게 검색을 하자

import re

f = open('C:/rowna_tracker/UNDHR.txt') # 백슬레시는 이스케이프 시퀀스랑 헷갈릴 수 있어서 \\ 이렇게 쓰거나 r() 로 r문자를 덧붙여줘야함

for line in f:
    line = line.rstrip()
    if re.search('^\([0-9]+\)', line): #첫 시작이(^) ( 0 - 9 숫자([0-9]가 1번 이상 반복된(+) ) 일 경우에
        print(line)
import re

str = """101 COM PythonProgramming
102 MAT LinearAlgebra
103 ENG ComputerEnglish"""

lst = str.split("\n")

num_lst = []

for x in lst:
    match = re.search('^[0-9]+',x)
    num_lst.append(x[match.start(): match.end()])
    print(match.start(), match.end())

print(num_lst)


나는 findall()이 생각이 안나서 줜나 어렵게 짰는데

import re

str = """101 COM PythonProgramming
102 MAT LinearAlgebra
103 ENG ComputerEnglish"""

print(re.findall('\d+', str))


더 쉽게 짜는 방법은 이렇게

 

참고로 += 연산자는 문자열은 리스트로 취급되어 한문자 한문자 씩 따로 들어감 이 부분이 append랑 다른 점

import re

str = """101 COM Python Part1
102 MAT LinearAlgebra
103 ENG ComputerEnglish"""

lst = str.split("\n")

num_lst = []

for x in lst:
    match = re.search('^[0-9]+',x)
    num_lst.append(x[match.start(): match.end()])

print(num_lst)


findall(\d+)의 문제점은 숫자가 하나라도 반복되면 다 찾아버리기 때문에 과목이름에 숫자가 들어있으면 출력이 오염됨

그러면 나처럼 그냥 정석대로 적으면 됨 어차피 처음에 수강번호가 나오므로

import re

str = """101 COM Python Part1
102 MAT LinearAlgebra
103 ENG ComputerEnglish"""

lst = str.split("\n")

num_lst = []

for x in lst:
    match = re.search('[A-Z]{3}',x)
    num_lst.append(x[match.start(): match.end()])

print(num_lst)

숫자가 [0-9]이렇게 되는 거처럼 영어도 [A-Z]가 되는 거 같음 그리고 {n}는 책에는 없지만 중괄호 직전의 문자를 반드시 3번 포함해라는 뜻임

원래는 ...이렇게 했는데 이러면 [A-Z]이걸로 대문자 찾고 그 후에 문자 3개를 찾는다는 의미 그리고 여기에 .에는 공백도 포함됨 이게 search라서 가장 앞에 있는 수강코드를 가져오는 거 같은데 뭐 그걸 이용해서 그냥 [A-Z].. 하거나 [A-Z]\s{2}해도 되지만 그것보단 정확하게 하는게 아무래도 더 낫지 않을까 싶다

import re

txt = 'abc@facebook.com와 bbc@google.com에서 이메일이 도착하였습니다.'

print(re.findall('\S+@[a-z.]+', txt))

이거를 범용적으로 쓸려면 사실 별로인거 같긴 함 왜냐하면 txt가 지금은 추출하기 쉽게 저렇게 되어있지만 이메일 앞에 숫자가 올 수도 있고 문자가 올 수도 있고 지금은 한국어로 에서 와 이렇게 되어있지만 영어로 되어 있을 수도 있어서 완전히 정교하게 추출은 안될듯

import re

txt = 'abc@facebook.com와 bbc@google.com에서 이메일이 도착하였습니다.'

lst = re.findall('\S+@[a-z.]+', txt)

for x in lst:
    lst2 = x.split("@")
    print("추출된 아이디:", lst2[0],", 도메인:", lst2[1])

import re

while True:
    password = input("패스워드를 입력하세요 : ")

    if re.search('\S{8}', password) and re.search('[A-Z]+', password) and re.search('[a-z]+', password) and re.search('[0-9]+', password) and re.search('[_@$!]+', password):
        break;
    else:
        print("유효하지 않은 패스워드!")

print("유효한 패스워드")

긴 조건문을 여러줄로 나누기 위해선 조건문 기호 앞에 \ 를 넣는다 그러나 그 조건문을 ()로 묶는걸 더 권장함 그러면 \ 없이도 조건문이 분리되있는 것이 허용 됨

 

11. 정규식에서 특정 문자를 대체하는 함수: sub()

re.sub(대체당할 문자, 대체 할 문자, 대상 문자열)

import re
s = "My lucky number 2 7 99"

def hash_by_mult_and_modulo(m):
    n = int(m.group())
    return str(n * 23435 % 973)

print(re.sub('[0-9]+', hash_by_mult_and_modulo, s))

re.sub(pattern, function, string)이 되면 function이 자동으로 re.Match 객체를 받음 즉 매치된 객체를 자동으로 받으며 group()은 여기서 매치된 객체가 여러가지 이므로 묶음을 위해서 필요함 group()이 찾은 패턴을 문자열로 바꾸는 역할을 한다고 한다...

import re

twt = input("트윗을 입력하시오: ")

twt = re.sub('RT|CC', '', twt)
twt = re.sub("\S+@[a-z]+", "", twt)
twt = re.sub("#\S+", "", twt)
twt = re.sub("@\S+", "", twt)
twt = re.sub("WWW\.+", "", twt)
twt = re.sub("https|htts+", "", twt)

print(twt)

re.sub()가 String에 직접적인 영향을 주지 않고 그냥 대체된 새로운 문자열을 만드는 거 같다 그래서 twt에 그 주소를 넣어줘야 하는듯

 

요약

1. 텍스트는 인간이 오랫동안 정보를 효율적으로 교환하는데 사용했던 수단으로 구조화된 문서와 구조화되지 않은 문서가 있다 전자는 HTML XML JSON 같은거고 후자는 자연어로 되어 있는 문서

2. 음수 슬라이싱도 작은거에서 부터 큰걸로 감

3. split()은 리스트로 반환 join()은 문자열을 합치기 replace()는 대체하기, capitalize()는 첫문자만 대문자로

4. len() max() 같은건 파이썬 내장함수이고 ord()는 문자에 대한 유니코드 값, chr()은 유니코드 값에 대한 문자를 반환

5. String 모듈은 ascii_lower ascii_upper 같이 소문자와 대문자만 모아놓은 문자열이 내장되어 있음

6. 워드 클라우드는 각 단어의 크기가 중요성이나 빈도를 나타내는 텍스트 데이터 시각화 기술 Wordcloud 클래스에 가로와 세로 길이를 넘겨준다음 generate()로 만들어주고 맷플롯립 라이브러리의 imshow()로 이미지를 만들어주고 show()로 화면에 출력하면 됨

맷플롯립은 시각화 차트를 그리기 위한 파이썬 외부 라이브러리

7. pillow 라이브러리는 이미지 처리를 위한 라이브러리이고 pip은 python install package로 파이썬 패키지 관리프로그램으로 명령어로 관리할 수 있게 해주는 도구

8. 워드클라우드의 중지어

9. 정규식 복잡한 문자열을 처리할 때 사용하는 기법 re 모듈을 이용해야 함 

메타문자: 정규식에서 특별한 의미를 가지는 문자들

10. lst.append()는 문자열을 그대로 리스트에 추가하지만 +=는 문자열을 리스트로 봐서 한 문자 씩 들어감

728x90
반응형