텍스트 데이터 전처리를 위한 정규표현식을 알아보겠습니다

 

 

 

1. 사용 모듈

import re

 

 

 

 

2. 텍스트에서 알파벳만 가져오기

p = re.compile('[^a-zA-Z ]*')
p.sub('', text)

text에서 정규식 p에 해당하면 '', 지우기

 

 

 

3. 메타문자

3-1 |

if re.match( 'a|b|c', 'a' ): print('1')
if re.match( 'a|b|c', 'd' ): print('2')
if re.match( 'a|b|c', 'ad' ): print('3')
if re.match( 'a|b|c', 'da' ): print('4')

|는 or 조건

1, 3 : 1번은 a가 있어서 프린트 되었고 3번은 첫글자가 일치하여 match된다

 

 

3-2 []

if re.match( '[abc]', 'a' ): print('1')
if re.match( '[abc]', 'efz' ): print('2')
if re.match( '[abc]', 'abd' ): print('3')
if re.match( '[abc]', 'b56' ): print('4')
if re.search( '[abc]', '56b' ): print('5')

[]는 배열

1,3,4,5 : 1,3,4는 첫글자에 있음으로 출력, 5번은 search로 첫글자에 상관없이 []에 존재하면 출력된다

 

 

3-3 -

if re.match( '[ㄱ-힣]', '가123ABC' ): print('1')
if re.match( '[0-9a-z]', 'Aa' ): print('2')
if re.search( '[0-9a-z]', 'Aa' ): print('3')

-는 1234를 1-4로 표현하는 방식 처럼 사용된다

1, 3 : 1은 ㄱ-힣에 '가'가 포함되어서 출력, 3번은 search이기에 a-z중 a가 포함되어 출력된다.

 

 

 

3-4 .

if re.match( '[a.b]', 'ab' ): print('1')
if re.match( '[a.b]', 'a1b' ): print('2')
if re.match( '[a.b]', 'abc' ): print('3')
if re.match( '[a.b]', 'bcd' ): print('4')
if re.match( '[a.b]', 'cab' ): print('5')
if re.match( '[a.b]', '.ab' ): print('6')


----

if re.match( 'a.b', 'a' ): print('1')
if re.match( 'a.b', 'abc' ): print('2')
if re.match( 'a.b', 'a1b' ): print('3')
if re.match( 'a.b', 'a2be' ): print('4')

.은 .이라는 문자 하나이며 사용위치에 따라 해석이 달라지며 [], '' 두가지 방법으로 주로사용된다

match [문자.문자] : a, b로 시작되는 문자열

match '문자.문자' : a, b가 포함되는 문자열 \n 이스케이프 표현은 제외

 

 

 

3-5 ^

- 일반 문자열에서는 문자열의 맨 처음과 일치함을 의미

- 문자열 에서는 해당 문자는 제외함을 의미

 

 

3-6 $

if re.match( '^[0-9]+[a-z]+$', '1' ): print('1')
if re.match( '^[0-9]+[a-z]+$', '11' ): print('2')
if re.match( '^[0-9]+[a-z]+$', '111111A' ): print('3')
if re.match( '^[0-9]+[a-z]+$', '1111111a' ): print('4')

$은 문자열의 맨끝과 일치함을 의미합니다. 위 코드에서는 4번만 매치됩니다

 

 

 

 

3-7 *, +

if re.match( 'seo*ul', 'seul' ): print('1')
if re.match( 'seo*ul', 'seoul' ): print('2')
if re.match( 'seo*ul', 'seoooul' ): print('3')

----

if re.match( 'seo+ul', 'seul' ): print('1')
if re.match( 'seo+ul', 'seoul' ): print('2')
if re.match( 'seo+ul', 'seoooul' ): print('3')

*,+ 앞의 문자열은 다음의 특성을 가집니다 *는 -~ 무한대 반복 가능, +는 1~ 무한대 반복 가능하다

*는 모두, +는 2,3번 

 

 

 

3-8 {}

지정된 횟수 반복 표현식입니다

{2} 2회 반복

{2,3} 2~3회 까지 반복 가능

 

 

 

3-9 ?

{ 0,1 } 과 같은 의미를 가짐 2번 이상은 반복 불가한 표현식

 

 

 

쓰다보니 생각보다 길어져서 2편으로 이어서 작성하겠습니다!

오늘은 NLP, 챗봇 학습을 위한 텍스트 데이터 텍스트 마이닝을 진행하겠습니다

 

 

 

1. 데이터 준비

pip install Korpora
from import Korpora import Korpora
review_corpus = Korpora.load('nsmc')

nsmc는 네이버 영화 리뷰 데이터로 텍스트 마이닝 실습을 위해 사용해보겠습니다

데이터는 15만개 리뷰 데이터로 레이블은 긍정, 부정 입니다

 

 

 

2. 데이터 확인

import pandas as pd
review_corpus_df =  pd.DataFrame()

review_corpus_df['doc']   = review_corpus.train.get_all_texts()
review_corpus_df['label'] = review_corpus.train.get_all_labels()

review_corpus_df.head()

비어있는 데이터 프레임 review_corpus_df를 만든 후 글과 레이블을 추가해서 확인하는 코드입니다

리뷰 글과 부정 긍정을 0,1로 확인할 수 있습니다

 

 

 

 

3. 워드클라우드 시각화

pip install wordcloud

from wordcloud import WordCloud, STOPWORDS
from PIL import Image
import numpy as np

heart_mask = np.array( Image.open('heart.jpg') )

stopwords = set(STOPWORDS)

# 워드 클라우드
wc = WordCloud( 
  font_path = '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf',
  max_words = 300,
  stopwords = stopwords,
  mask = heart_mask,
  background_color='white'
)

wc_gen = wc.generate( review_posi_text )

# 시각화
plt.figure( figsize=(7,7) )
plt.imshow( wc_gen )
plt.axis('off')
plt.show()

heart 사진에 워드클라우드를 만드는 코드입니다

 

stopwords 불용어를 배제해줍니다

wc wordcloud로 font 설정, 시각화할 빈도개수 300개, 불용어, heart 그림에 시각화 하여 워드클라우드를 만들었습니다

 

wc_gen은 빈도 서열입니다

 

마지막으로 plot으로 시각화 한 이미지입니다

 

 

 

4. 말뭉치 분절

from konlpy.tag import Mecab
tokenizer = Mecab()

review_corpus_df.doc = review_corpus_df.doc.apply( 
                                           lambda x: ' '.join(tokenizer.morphs(x)) )

Mecab으로 불필요한 품사 제거 및 재조립을 진행합니다

 

 

 

 

5. 백터화

from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(min_df=1, decode_error='ignore')

X = vectorizer.fit_transform( review_corpus_df.doc )

데이터 백터화를 통해 len()로 확인 해보면 50991개의 토큰으로 백터화 되었음을 확인할 수 있습니다

 

 

 

 

 

6. 유사도 검사

def check_answer_sim( user_sentnece='' ):
  if not user_sentnece:
    return '입력 필요'
  
  chatbot_df['score'] = 0

  # 1. 입력 백터화
  user_sentnece_vec = vectorizer.transform( [ my_sentence_change(user_sentnece) ] ).toarray()[0]    

  # 3. 유사도 score 계산
  chatbot_df['score'] = chatbot_df.Q2_vec.apply( lambda x: cos_sim(user_sentnece_vec, x) )
  #print(chatbot_df['score'])

  # 4. 유사 문장 return
  return chatbot_df.loc[ chatbot_df['score'].idxmax() ]['A']

챗봇에서 주로 사용되는 방법이지만 문장 -> 분절 -> 백터화를 통해 유사도를 측정하여 비슷한 문장을 찾을 수 있으며 이를 통해 결론을 도출할 수 있습니다

 

max를 사용하면 챗봇의 형태가 되며 리뷰에서 max값 여러개를 통해 리뷰의 성격을 파악하여 결론을 도출할 수 있으며 또한 백터화된 토큰과 워드클라우드를 통해 리뷰 성격 파악을 할 수 있습니다

데이터 분석 관계 분석, 결론 도출을 위한 시각화 방법으로 matplolib, seaborn을 사용해보겠습니다

 

 

1. 패키지 설치

pip install matplotlib
pip install seaborn

 

 

 

 

 

2. 기본 사용법

from matplotlib import pyplot as plt

x = np.arange( 0, 12, 0.01 )
y = np.sin(x)

plt.figure( figsize=(10, 6) )

plt.plot( x, y,  label='sin wave')
plt.plot( x, np.cos(x), label='cos wave' )

numpy의 np.sin을 통해 0~12의 sin값을 예시 그래프 값으로 사용한 차트입니다

 

 

 

3. seaborn boxplot

import seaborn as sns

plt.figure( figsize=(10,6) )
sns.boxplot( x )
plt.show()

파란 박스 구간을 통해 데이터의 중간값들은 17 주변으로 확인되고 대부분 14 ~ 22 사이에 있음을 알 수있다

최대치는 52정도이고 40 이상의 데이터는 많이 없음을 알수있다

 

데이터 결론 도출로는 14 ~ 22의 데이터가 많이 사용되므로 중점적으로 해당 데이터는 가격대로 해당 층의 니즈를 공략해야한다는 결론이 나올수있다

 

 

 

4. seaborn swarmplot

plt.figure( figsize=(10,6) )
sns.boxplot( x='day', y='total_bill', data=tips, palette='Set3' ) 
sns.swarmplot( x='day', y='total_bill', data=tips, color='0.5')
plt.show()

day는 요일로 목금토일을 설정했으며 데이터를 통해 금요일에는 손님이 많이 없으며 주말에 조금 더 높은 가격대를 지출함을 알 수 있다

 

 

 

 

5. seaborn Implot

plt.figure( figsize=(10,5) )
sns.Implot( x='total_bill', y='tip', data=tips, size=10 )
plt.show()

Implot은 컬럼과의 관계 분석을 시각화한 차트로 total_bill 매출과 tip 팁의 관계를 도출한다

 

x로 설정한 매출과 산포도로 측정된 tip과의 관계차트이다

 

x, y 데이터가 얼마나 떨어져 있나와 파란색 영역을 통해 표준편차를 볼 수 있습니다

 

 

 

 

6. seaborn heatmap

plt.figure( figsize=(10,10) )
sns.heatmap(df, annot=True, fmt='d'  )
plt.show()

표는 x year, y month로 연도별 월 고객수를 시각화 한것으로 색이 밝아질수록 고객이 많음을 뜻합니다

 

차트에서는 연도가 지나갈수록 고객이 많아지고 여름에 가장 고객이 많음으로 여름장사에 집중됨을 알 수 있습니다

 

 

 

7. seaborn pairplot

sns.pairplot( iris, hue='species', x_vars=['sepal_width', 'sepal_length'],  y_vars=['petal_width', 'petal_length'])
plt.show()

산포 행렬 시각화 방법으로 데이터의 군집을 확인할 수 있습니다

 

군집데이터의 사용 능력치는 딥러닝에서 빛을 바라기에 활용 방법을 많이 익혀두는게 좋습니다 저 또한 군집데이터에 대한 이해도를 꾸준히 높이고 있습니다

 

 

 

 

8. seaborn 다중 histogram

for spec in iris.species.unique():  
  spec_df = iris[ iris.species == spec ]
  print( spec, spec_df.shape )
  spec_df[ 'petal_width' ].plot( kind='hist', alpha=0.4, label=spec)

plt.legend()
plt.show()

데이터의 분포를 확인하기 좋은 시각화 방법으로 Implot과 heatmap, histogram 시각화를 가장 많이 사용하게 되는것 같습니다

음원 데이터 music.xlsc 분석 실습

 

 

 

 

1. 데이터 확인

music_df = pd.read_excel('music.xlsx')

 

 

 

 

 

2. 데이터 구조 확인

music_df.shape

 

df.shape으로 데이터 개수 및 컬럼 수를 확인합니다

 

 

 

music_df.dtypes

df.dtypes 데이터의 타입을 확인합니다

 

 

 

 

3. 데이터 구조 변경

music['Date'] = music['Date'].astype( 'datetime64' )

Date는 object 타입이 아니라 datetime 형식이기에 바꿔줍니다

 

 

 

music.Distribution.unique(), len(music.Distribution.unique())

컬럼값과 컬럼 개수 확인 로엔 엔터테인먼트, 로엔엔터테인먼트 처럼 중복되지만 컬러명이 달라서 다른 데이터인 오류가 있음을 확인할 수 있습니다

 

 

def myChange( x ):
  x = x.replace(' ', '')
  x = x.replace('㈜', '(주)')
  x = x.replace('소니뮤직', 'SonyMusic')
  x = x.replace('유니버설뮤직', 'Universal')
  x = x.replace('(주)지니뮤직', '지니뮤직')
  x = x.replace('(주)미러볼뮤직', 'MirrorballMusic')
  return x

tmp = music.Distribution.apply( myChange )
tmp.unique(), len(tmp.unique())

컬럼값을 apply로 replace 후 추가로 확인할 컬럼이나 합쳐진 컬럼 값을 확인합니다

 

 

 

4. 피벗 테이블

music.groupby('Distribution').agg({
    'Rating':'mean',
    'Distribution':'count',
    'Music Count':'sum'
})

컬럼별로 평점은 평균, 제작 개수, 노래 개수합 등으로 컬럼에 알맞게 정리하면 데이터 분석 준비 완료입니다

 

이후 시각화와 조건에 따른 분류를 통해 데이터 분석을 진행하여 결론을 도출할 수 있습니다

안녕하세요 오늘은 데이터 분석을 위한 pandas 사용법에 대해 소개해보겠습니다

 

pandas는 데이터 분석에서 결과도출, EDA, 분석 등에 활용됩니다

 

 

 

1. 설치방법

pip install pandas

 

 

 

 

2. 자료구조

- Series : 1차원 배열

- DataFrame : 2차원 배열

 

 

 

 

3. Series

import pandas as pd

tmp = pd.Series([1,2,3,4,5])

pd.Series() 안에 배열을 넣어서 Series로 만들 수 있으며 이때 인덱스(순서?)가 생성됩니다

 

 

 

4. DataFrame

import pandas as pd

cols = list('ABCD')

indexs = pd.date_r('20240130', periods=7)

출력
DatetimeIndex(['2024-01-30', '2024-01-31', '2024-02-01', '2024-02-02',
               '2024-02-03', '2024-02-04', '2024-02-05'],
              dtype='datetime64[ns]', freq='D')

다음과 같이 선택일자부터 7일동안의 데이터를 임의 생성합니다

 

values = np.random.randn( len( indexs ), len(cols) )
df = pd.DataFrame( values, indexs, cols )
df

이후 indexs와 cols의 개수만큼 7,4 배열에 랜덤값을 만들어준 후 DataFrame으로 만들면 표로 시각화됩니다

 

pandas DataFrame으로 시각화한 표로 데이터 분석에 자주 사용되는 데이터 분석을 위한 확인 방법입니다

 

 

 

5. read_csv

csv_path = '/content/drive/MyDrive/res/data.csv'
df = pd.read_csv( csv_path )

csv 파일을 DataFrame으로 만드는 방법으로 인공지능 학습 데이터의 구조로 사용됩니다

 

 

 

 

6.df.head, df.tail

df.head()
df.tail()

DataFrame의 앞에서 5개의 데이터, 뒤에서 5개의 데이터를 뽑아오는 방법입니다

 

 

 

7. df.info

df.info()

빅데이터서 데이터의 구조를 쉽게 확인하는 방법으로 컬럼명, 데이터의 개수, 타입 확인을 쉽게 할수있습니다

 

 

 

8. sort_values

df.sort_values(by='age', ascending=Faslse)

age 나이를 기준으로 정렬하는 방법으로 내림차순, 오름차순 등으로 정렬 가능합니다

 

 

 

 

9. .columns, .values

df.columns
df.values

columns는 컬럼들을 나열하여 컬럼명을 확인하기 편합니다

values는 해당 값을 확인할 수 있으며 인덱스나 컬럼의 값을 통해 검색하는 방법처럼 사용됩니다

 

 

 

 

 

10. 인덱싱

10-1 컬럼 인덱싱

df.[['age', 'id']]

df의 컬럼이 여러개일때에 age, id 컬럼값만 인덱싱 하는 방법입니다

 

 

10-2 인덱스 인덱싱

df[1:10:2]

numpy를 공부하고 오셧다면 바로 이해할수 있습니다 1번부터 10번까지 2단위로 인덱싱합니다

 

 

10-3 인덱스 교체

data_size = df.shape

cus_indexs = pd.data_range('20240130',periods=data_size)

df.index = cus_indexs

df의 shape을 통해 날짜를 shape만큼 만들어서 index를 날짜로 변경하는 방법입니다

 

 

 

 

 

11 loc

df.loc['2024-05-05':'2024-10-10', 'age']

날짜로 바꾼 인덱스를 통해 loc.[날짜,컬럼] 방식으로 데이터를 추출합니다

 

위 코드는 5월5일부터 10월10일까지의 데이터를 나이만 가져오게 됩니다

 

데이터 분석으로 예시를 들면 5월5일 부터 10월10일 까지 유저들의 나이대를 알수있습니다

 

 

 

 

12 iloc

df.iloc[1:3, 1:3]
df.iloc[[4,5,2,6], [5,1,4,2]]

iloc를 사용한 슬라이싱(?) 방법으로

첫번째는 1번부터 3번전까지의 인덱스를 1번부터 3번전까지의 컬럼만 출력한다 입니다

 

두번째는 numpy에서도 비슷하게 사용했던 비연속적인 데이터 추출입니다 4,5,2,6 인덱스에서 5,1,4,2 컬럼을 가져옵니다

 

 

 

 

13.블리언 인덱싱

df2.is_deleted == 0

참, 거짓의 데이터에서 사용되며 0, True인 데이터만을 인덱싱 하는 방법입니다

 

예시로 loc와 함께 사용한다면 구매여부 True, 물건을 구입한 사람 중 5월 ~ 10월 사이의 유저 나이 처럼 응용할수있습니다

 

 

 

 

14. drop

df.drop(['age'], axis=1)

데이터에서 age 컬럼을 제거합니다

컬럼이 많을때에는 인덱싱 하기에 번거로울 수 있어서 사용됩니다

 

 

 

15. groupby

df.groupby(['purchase', 'gender']).count()

purchase 는 1,0 으로 대분류로 구분해주고 gender에 따라 중분류를 진행할 수있습니다

 

구매 여부에따른 여자와 남자의 수 를 확인할수있습니다

 

 

 

 

16. 컬럼추가

df['gender'] = data['gender']

df에 gender 컬럼이 없다는 가정하에 작성하는 코드로 data에 있는 젠더 값을 가져오는 코드입니다 다른방법으로는 Series를 컬럼으로 추가할 수 있습니다

이때 값의 수가 같아야 하며 다를경우 다른 컬럼들이 None으로 추가됩니다

 

 

 

17. merge

left_df  = pd.DataFrame({
    'key':list('1234'),
    'A':list('ABCD'),
    'B':list('EFGH'),
})
right_df = pd.DataFrame({
    'key':list('0123'), 
    'C':list('가나다라'),
    'D':list('WXYZ'),
})

pd.merge( left_df, right_df, on='key' )

차원이 같은 두 데이터를 병합하는 방법으로 key값을 기준으로 병합되며 A,B,C,D 컬럼이 생기게 됩니다

 

pd.merge( left_df, right_df, on='key', how='left' )

(3,4) 배열과 (4,3)의 배열을 merge 하게되면 Nan으로 채우게 됩니다 이는 16. 컬럼추가와 같습니다

Nan이 되면 결측치가 발생하게 되며 이는 제거하거나 값을 추가해서 사용할 수 있습니다

 

 

 

 

18 조건 인덱싱

df = df[df['age'] >= 20]

실무에서 가장 많이 사용되는 인덱싱 방법인데 공부할때는 기본적인 사용법만 학습하다 보니 내용이 따로 없어서 하나 추가해보았습니다 조건에 따른 인덱싱 방법으로

예시는 20살 이상이 데이터만 가져온다입니다

 

결측치를 그래프로 시각화하여 결측치를 제거하거나 필요한 데이터 조건을 설정하는데 많이 사용됩니다

안녕하세요 오늘은 데이터 수집을 위한 numpy에 대해 소개해보겠습니다

 

 

 

 

1. numpy 설치

$ pip install numpy



 

2. numpy 배열 생성

data = [5,6,7,8]

arr = np.array
print(arr)

기본적인 numpy 배열 생성 방법입니다

 

 

 

 

3. asarray()

arr3 = np.asarray( arr2 )
display_arr(arr3)

arr2 를 복사하는 방법이지만 array()와 다른점은 사본 변경 시 같이 변경됩니다

 

 

 

4. arange()

arr = np.arange(1, 5, 2)
arr

출력
array([1, 3])

1 부터 5 전까지의 숫자를 2의 간격으로 출력 python에서 기본적으로 사용되는 range와 사용방법이 같습니다

 

 

 

5. reshape()

np.arange(1, 17).reshape( (4,4) )

1 ~ 16까지의 숫자를 생성 후 4,4의 구조로 바꾸는 방법입니다 

 

reshape은 자주 쓸것같은데 저는 생각보다 쓸일이 많이 없었습니다

 

 

 

 

6. np.zeros((2,3))

arr = np.zeros( (2,3)  ) 
arr

배열 구조안에 값을 0으로 넣는 방법입니다

 

zeros는 생각보다 자주 사용하게 됩니다

 

 

 

7.astype()

tmp = arr.astype(np.int64)
tmp.dtype

출력 타입을 지정해주는 방법으로 간혹 사용됩니다

 

 

 

 

8. 인덱싱

arr[0], arr[0][-1]

출력
(array([1, 2, 3]), 3)

arr = [1, 2, 3] 배열에서 인덱싱 했을때의 결과로 0은 첫번째 숫자, -1은 뒤에서 첫번째 숫자를 의미하며 [ ]는 배열의 차원을 의미합니다

 

그러므로 [0][-1]은 첫번째 배열의 마지막숫자를 의미합니다

 

 

 

 

9. 슬라이싱

arr = np.arange( 16 ).reshape( (2,8) )

arr[ :-1 , 1:1+3 ]

출력
array([[1, 2, 3]])

슬라이싱은 의미 그대로 자르는 방법으로 사용됩니다

 

':-1' : 1차원 배열에서 마지막 전까지 즉 1차원이 2개이기 때문에 첫번째 배열만 불러옵니다

 

'1:1+3' : 2차원 배열에서 1, 두번째 숫자부터 1+3, 4번째 숫자까지 입니다

 

 

 

 

10.블리언 인덱싱

arr[ arr > 0 ]

arr[ (arr>1) | (arr<0) ]

블리언 인덱싱은 조건에 따라 나누는 방법으로 사용됩니다

 

arr > 0 이면 이라는 뜻으로 조건에 해당할 시 0이나 제거하여 결측치를 제거하는 방식으로 사용됩니다

 

두번째 또한 조건으로 1보다 크거나 0보다 작을 시 제거하거나 =0, 값을 0으로 만드는 방식으로 사용됩니다

 

 

 

 

 

11. 팬시 익덱싱

arr = np.arange(32).reshape(8,4)


----

arr[ [3,1, 0, 4] ]
출력
array([[12, 13, 14, 15],
       [ 4,  5,  6,  7],
       [ 0,  1,  2,  3],
       [16, 17, 18, 19]])
       
----

arr[ [3,1, 0, 4], [2,1,3,0]]
출력
array([14,  5,  3, 16])

----

arr[ [3,1, 0, 4] ][ : , [2,1,3,0] ] 
출력
array([[14, 13, 15, 12],
       [ 6,  5,  7,  4],
       [ 2,  1,  3,  0],
       [18, 17, 19, 16]])
       
----

arr[ [3,1, 0, 4] ][ : , [2,1,3] ]
출력
array([[14, 13, 15],
       [ 6,  5,  7],
       [ 2,  1,  3],
       [18, 17, 19]])

팬시 익덱싱은 비연속적인 데이터를 추출할때 사용됩니다

 

일명 마구잡이 순서로 있을때 필요한 데이터만 수집하도록 사용됩니다

 

arr는 2차원의 배열일때를 가정했습니다

 

arr[[3,1,0,4]] 1차원에서 인덱스를 기준으로 순서를 재배치 합니다

 

arr[[3,1,0,4], [2,1,3,0]] 값을 지정해서 가져옵니다

 

arr[[3,1,0,4]][:, [2,1,3,0]] 2차원 데이터는 모두, 그 순서들은 [2,1,3,0]

1차원 배열의 순서는 [3,1,0,4]의 구조로 변경됩니다

 

한번에 작성하고 설명을 작성하니 그리 보기 좋지가 않네요,,

 

 

 

12. 축변경 .T

arr.T

사실상 데이터 수집, 데이터 분석까지 생각해보면 가장 많이 사용하게 되는 기능입니다 축을 변경하는 방법으로

(2,8)의 구조를 (8,2) 처럼 바꾸는 방법입니다

 

가장 많이 사용되는게 의외인 기능이지만 데이터를 확인할때 많이 사용됩니다

 

 

 

 

 

13. 축이동

arr = np.arange(24).reshape( (2,3,4) )

arr.transpose( (2,0,1) ).shape,  arr.transpose( (2,0,1) )

출력
((4, 2, 3)

array([[[ 0,  4,  8],
         [12, 16, 20]],
 
        [[ 1,  5,  9],
         [13, 17, 21]],
 
        [[ 2,  6, 10],
         [14, 18, 22]],
 
        [[ 3,  7, 11],
         [15, 19, 23]]]))

3차원 배열의 축이동으로 2번축을 맨앞으로, 0번축을 그다음, 1번축을 마지막에 배치 하는 방법입니다

 

데이터 수집의 종류별 공부 중 API 형태의 데이터 수집으로 네이버 검색 API 수집을 완료했다 이후 웹 스크래핑 형식의 데이터 수집을 진행해보려 한다

웹 스크래핑은 웹 구조를 이용한 데이터 수집 방법으로 흔히 사이트를 긁어온다 라고 표현하며 사이트 별로 구조가 모두 다르기에 웹 페이즈에 대한 구조와 웹 스크래핑을 위한 BS4_BeautifulSoup 라이브러리 사용 경험치가 중요한 작업이다

간단 웹 페이지 구조

1. html5 : 데이터, 뼈대, 구조

2. css : 디자인, 레이아웃, 애니메이션, 반응형 (모바일<->PC)

  • bootstrap, 머터리얼 등의 디자인 템플릿도 가능

3. javascript, Ajax : 사용자 상호작용, 이벤트, 화면조작

웹 스크래핑 방법

  1. html 문자열
  2. BeautifulSoup 파싱
  3. html 구조로 메모리에 적재
  4. 탐색/검색
  5. 정보 추출

6. 데이터화

데이터 수집 타겟 사이트 선정

네이버 증권 환율 지표 데이터로 선정 'F12' 키 검사로 들어가서 확인해보면 네이버 환율 사이트는 친절이 document 사이트를 제공해 주어 손쉽게 데이터 수집이 가능 할 것으로 예상되며 최근 엔화의 하락이 있어서 엔화 변동성을 확인하여

엔화 ETF 매수 시점을 잡아보려고 시도중으로 네이버 환율 사이트를 타겟 사이트로 선정

 

 

친절히 환율 리스트만 따로 제공해주는 네이버 매매기준율을 기준으로 데이터 수집을 진행해보겠습니다

 

데이터 수집 코드 실습

  1. 모듈 가져오기
from urllib.request import urlopen from bs4 import BeautifulSoup

파싱을 위한 BeautifulSoup와 사이트 적솝을 위한 urlopen 모듈을 가져옵니다

2. 사이트 접속

target_site = 'https://finance.naver.com/marketindex/exchangeList.naver' res = urlopen( target_site )

타겟사이트인 네이버 증권 시장지표 환율정보이며 네이버에서는 따로 환율 리스트 정보만을 가지고있는 사이트를 제공해주기에 타겟사이트에 입력

3. 파싱

soup = BeautifulSoup( res , 'html5lib' )

BeautifulSoup로 html5lib을 사용한 파싱

4. 데이터 추출

사이트에서 데이터 수집 타겟인 매매기준율의 class 이름을 확인 'sale' 클래스로 확인

바로 옆의 통화명은 tit 입니다 사이트도 제공해주더니 데이터 수집도 간단하게 만들어 둔 사이트의 예시네요

for td_sale in soup.select('.sale'): print( td.text.strip() , end=" , " ) for td_tit in soup.select('.tit'): print( td.text.strip() , end=" , " )

클래스 값은 이름앞에 .을 붙혀서 .sale 의 형식으로 사용이 가능합니다

이제 soup를 사용해 통화명과 매매기준율 데이터 가져올 수 있습니다

 

네이버 증권 환율 정보를 가져오는 간단한 웹 스크래핑 방법 이였습니다

웹 스크래핑은 간단한 사이트에서 주로 사용하는 경우가 많아서 사이트도 간단한 사이트로 선정해서 진행해보았습니다

다음에는 조금더 고급(?) 스킬인 셀레니움을 통한 데이터 수집을 진행해보겠습니다

selenium을 사용해서는 데이터 수집이 조금은 더 까다로운 웹 페이지도 가능하니 세세하게 공부해두면 더 좋을것같습니다

데이터 분석을 위한 사전공부 데이터 종류와 데이터 수집에 대해 공부를 진행했다

데이터의 종류에 대한 생각과 데이터 수집중 API 형태의 데이터 수집 그 중 네이버 검색 API 내가 원하는 키워드대로 수집하는 코드를 작성한다

데이터 종류

  1. 정형
    • 구조화 된 데이터
    • RDMS를 통한 데이터일 확률이 높음
    • 데이터와 구조정보가 분리되어 있다
  2. 비정형
    • 구조가 없는 데이터
    • 바이너리 데이터 ( 비디오, 오디오, 문서파일 )
    • NoSQL
  3. 반정형
    • RDBMS에서 추출하진 않았지만, 어느 정도는 구조를 가지고 있음
    • JSON, XML -> 텍스트 기반 이기종, 플랫폼, 언어 독립적인 데이터 포멧
    • HTML 형식
    • 데이터 안에 데이터와 구조정보가 같이 존재함

데이터 수집 방법 : 네이버 open API를 활용한 뉴스 수집

뉴스 데이터 수집으로 자연어 처리 용도로 활용이 가능하다

API는 검색만 신청한 후 Client ID, Client Secret 필요

 

import sys import os import urllib.request

먼저 사용 할 모듈을 가져와 줍니다

CLIENT_ID = "" CLIENT_SECRET = ""

네이버 검색 API를 사용하기 위해 필요한 키로 네이버 개발자 센터에서 발급받을 수 있습니다

네이버 API를 사용하기 위해 네이버 개발자 센터 Naver Developer 에서 API 제휴 신청을 해줍니다

검색 API의 일 허용량은 25,000회로 자동화 하거나 추후 많이 사용하게 될때 참고해두세요

encText = urllib.parse.quote("키워드") url = "https://openapi.naver.com/v1/search/news.json?query=" + encText

키워드 입력하는 변수와 url 값을 만들어 줍니다


request = urllib.request.Request(url) # 프로토콜 헤더에 정보를 세팅한다 
request.add_header("X-Naver-Client-Id", CLIENT_ID) 
request.add_header("X-Naver-Client-Secret", CLIENT_SECRET) # 
urlopen() 실제적으로 서버에 요청하는 함수 
response = urllib.request.urlopen(request) 
rescode = response.getcode() 
if(rescode==200): 
	response_body = response.read() print(response_body.decode('utf-8')) 
	else: print("Error Code:" + rescode)

 

이후 네이버 API 사용 방법에 따라 response 해주고 코드 200으로 성공일때 작동하도록 만들어 줍니다

정상적으로 코드가 실행되면 5가지 값이 출력됩니다 title, originallink, link, description, pubDate

import sys import os 
import urllib.request 
CLIENT_ID = "" 
CLIENT_SECRET = "" 
encText = urllib.parse.quote("키워드") 
url = "https://openapi.naver.com/v1/search/news.json?query=" + encText 
request = urllib.request.Request(url) # 프로토콜 헤더에 정보를 세팅한다 
request.add_header("X-Naver-Client-Id", CLIENT_ID) 
request.add_header("X-Naver-Client-Secret", CLIENT_SECRET) # 
urlopen() 실제적으로 서버에 요청하는 함수 
response = urllib.request.urlopen(request) 
rescode = response.getcode() 
if(rescode==200): 
	response_body = response.read() 
	print(response_body.decode('utf-8')) 
else: print("Error Code:" + rescode)

1차 기본적인 네이버 API 테스트 총합 코드입니다

간단하게 API 형태 데이터 수집 방법을 작성해봤습니다 앞으로 웹 스크래핑, 크롤링, 자동화 까지 진행 후 본격적인 EDA 시작 해보겠습니다

Flask 보다 빠르고 기능이 많은 프레임워크 Fast API를 업무능력 향상과 자기개발을 위해 공부하기로 결심했다

그리하여 오늘부터 Fast API 공부 시작!

 

 

 

 


  1. Fast API란

Fast API는 빠른 성능, 타입 힌트 기반, 간결하고 직관적인 문법이 특징이다

  • 성능 및 빠른 속도 : 비동기 처리 및 Pydantic과 같은 최신 Python 라이브러리를 활용하여 빠른 속도와 뛰어난 성능을 보인다. asyncio를 활용하여 I/O 바운드 작업에서 높은 처리량과 낮은 지연시간을 가지는 특징
  • 타입힌트 기반 : Python의 타입 힌트를 사용하여 자동으로 API 문서를 생성하고, 타입 검사를 수행하여 개발자들의 안정적인 코드작성을 돕는다
  • 간결하고 직관적인 문법 : Swagger 및 OpenAPI를 자동으로 생성하며, 코드 작성을 위한 간결한 구문을 제공하여 빠른 API 개발이 가능!
  • Starletter 프레임워크 개발자가 개발하였으며 Python의 성능을 극대화하고 개발자 경험을 향상시키는 목표를 가지고 만들었다고합니다.

2. Fast API 장점

  • Starlette 프레임워크 기반 ASGI 비동기 처리로 대규모 트래픽 처리에 유리하다
  • 타입 힌트 기반의 자동 문서화한다. Pydantic을 사용하여 타입 힌트를 기반으로 자동으로 API 문서를 생성
  • OpenAPI 지원을 통한 자동 스웨거 생성
  • 직관적이고 간결한 문법으로 빠른 API 작성
  • Python 기반 라이브러리와 호환성이 높음

3. 관련 용어 정리

  • WSGI (Web Server Gateway Interface)

WSGI는 Python 웹 애플리케이션과 웹 서버 간의 표준 인터페이스를 제공한다. python 웹 프레임워크와 웹 서버가 상호 작용할 수 있도록 하는 규칙이며 여러 애플리케이션을 서로 다른 웹 서버에 배포할 수 있도록 표준화된 방법

  • ASGI (Asynchronous Server Gateway INterface)

ASGI는 WSGI의 비동기 버전으로 Python의 비동기 웹 애플리케이션을 위한 인터페이스이다. WSGI는 동기적 요청-응답 패턴에 적합하지만 ASGI는 비동기 요청-응답을 처리하며 WebSocket과 같은 실시간 통신을 처리하는데 적합하다

  • Cpython

Cpython은 Python 프로그램을 C나 C++로 코드를 변환하는 도구로 Python과 C언어 혼합 형태로 사용되며 Python 코드에 정적 타입을 추가하고 C 확자 모듈을 생성하여 Python 코드의 성능을 향상시킨다. 실행을 위해 CPython 인터프리터가 필요하다

  • uvloop

uvloop는 asyncio 이벤트 루프의 성능 향상을 위한 라이브러리로 libuv 이벤트 루프 라이브러리의 Python 바인딩을 제공하며, asyncio의 기본 이벤트 루프보다 성능이 좋다

  • coroutine

coroutine은 비동기 프로그래밍을 위한 개념으로, 실행이 일시 중지되고 다시 시작될 수 있는 함수이다. 이를 통해 비동기적인 작업을 간다하게 표현할 수 있다

  • Event loop

이벤트 루프는 비동기 프로그래밍에서 이벤트를 관리하고 처리하는 매커니즘이다. 비동기 코드에서는 이벤트 루프를 사용하여 작업 스케줄링을 관리한다

  • DI (Dependency Injection)

의존성 주입은 객체지향 프로그래밍에서 사용되는 패턴으로 객체가 필요로 하는 의존성을 외부에서 받도록 하는 것을 의미한다 이를 통해 객체간의 결합도를 낮추고 유연성을 높일 수 있다.

참고자료

  1. https://tech.madup.com/FastAPI/
  2. https://livvjh.com/posts/develop/fastapi-beginner/

'Python > FastAPI' 카테고리의 다른 글

FAST API get, post 사용방법  (1) 2024.01.29

안녕하세요 오늘은 FAST API의 get, post 사용방법에 대해 소개시켜 드리겠습니다

 

기본적인 설치 내용은 빼려고 했으나 다시 추가하기로 해서 넣어두겠습니닷

 

 

 

 

  1. FAST API 설치
pip install fastapi
pip install uvicorn

# 오늘 사용할 예정
pip install httpx
 

 

 

 

2. 기본적인 get 사용 방법

@app.get("/")
def main_re():
    return 'hello youngs'
 

실행해보면 웹페이지에 hello youngs가 출력되는 코드입니다.

 

 

 

 

3. URL 리다이렉트

@app.get("/")
def main_re():
    return RedirectResponse("http://127.0.0.1:8000/main/")
 

저는 루트 페이지가 메인이 아닐때 사용하는 URL 리다이렉트 방법입니다 들어올때는 URL이 적은게 복잡하지 않고 편리해 보이기에 사용할껄요? 다른분들은 어떻게 사용하는지 확인해 본적이 없습니닷

 

 

 

 

4. JSON 값을 리턴하기

# JSON 값을 리턴하는 API
@app.get("/items/", response_class=JSONResponse)
async def read_items():
    return {"item_id": "Foo"}
 

JSON 값을 출력하기만 하는 코드입니다

 

 

 

 

5. JSON 값을 리턴하는 함수를 통해 값 요청하기

async def call_main():
    async with httpx.AsyncClient() as client:
        response = await client.get('http://127.0.0.1:8000/items/')
        return response.json()

@app.get("/main/")
async def main_page(request: Request):
    client_host = request.client.host
    response_data = await call_main()
    return {"client_host": client_host, "response_data": response_data} #, "response_cal": response_cal}
 

client의 http 주소 출력과 4번에서 만든 items의 JSON 값을 요청받는 함수를 통해 값을 요청하는 코드입니다

간단히 get API에 JSON형식 리턴값을 요청 및 응답받아 출력하는 방식입니다

 

 

 

 

6. get URL을 통해 값 받아오기

@app.get("/items/line/{item_id}")
async def get_line(item_id: int):
    return item_id
 

조금 고전적이지만 쉽고 보안성이 보장되지 않는 방법인 get URL을 통한 값 받아오기 방법입니다

 

 

 

 

7. BaseModel로 값을 정의하고 값을 포함한 post 요청과 값에 대한 리턴을 출력하기

# 7-BaseModel : 값 정리역할
class Item(BaseModel):
    price: int
    cnt: int
    name: str

# 7-response : post test 받은 값을 리턴
@app.post("/items_test/")
async def items_test(item: Item):
    # dict_price = {"item_price": item.price, "item_cnt": item.cnt}
    return item.price * item.cnt, item.name


# 7-requestpost : test json 값과 함께 post 요청
@app.get('/ii/')
async def read_item():
    # POST 요청을 생성하여 /items_test 엔드포인트에 데이터 전송
    async with httpx.AsyncClient() as client:
        item_data = {"price": 10, "cnt": 5, "name":"youngs"}  # 원하는 데이터 설정
        try:
            response = await client.post("http://127.0.0.1:8000/items_test/", json=item_data)
            response.raise_for_status()  # HTTP 오류가 있는 경우 예외 발생
            return {"item_from_post": response.json()}
        except httpx.HTTPError as e:
            return {"error": f"HTTP error occurred: {str(e)}"}
        except Exception as e:
            return {"error": f"An error occurred: {str(e)}"}
 

BaseModel을 통해 데이터 유효성 검사를 하고 post items_test 에서 간단한 곱셈을 통해 기능을 부여한 후에 리턴하여 ii에서 받도록 하는 이제조금 API를 사용하는 형태의 구조입니다

get ii 쪽에 예외처리는 대부분 BaseModel에서 유효성 검사가 되지않는 경우를 위한 예외처리를 추가했습니다

 

 

 

오늘은 웹에서 아주 기본적으로 사용되는 get, post를 소개해보았습니다 이제 앞으로 restful을 간단히 정리해보고 필요한 API를 하나씩 구현해보면서 프로젝트를 완성해보도록 하겠습니다

 

프로젝트는 데이터 분석에서 사용한 네이버 API를 연동해서 자동화를 통한 데이터 수집 까지만 구상해서 만들어보도록 하겠습니다

데이터는 추후 어떻게 활용되는지 조금 더 생각해보고 Slack을 사용하여 알림을 주는 느낌으로 구상하고있습니다!

 

다음에는 아마 RESTFULL API 일것같습니다

 

 

 

마지막으로

 

공부에 사용한 코드 전체 올려드립니다!

import httpx
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.responses import RedirectResponse
from pydantic import BaseModel

app = FastAPI()

# 2. 기본형
@app.get("/")
def main_re():
    return 'hello youngs'

# 3. 루트 접속 시 main 으로 리다이렉트
@app.get("/")
def main_re():
    return RedirectResponse("http://127.0.0.1:8000/main/")

# 4. JSON 값을 리턴하는 API
@app.get("/items/", response_class=JSONResponse)
async def read_items():
    return {"item_id": "Foo"}


# 5-함수 : JSON 값을 리턴하는 API 값 call 함수
async def call_main():
    async with httpx.AsyncClient() as client:
        response = await client.get('http://127.0.0.1:8000/items/')
        return response.json()

# 5-API : API Call 함수로 값 요청하기
@app.get("/main/")
async def main_page(request: Request):
    client_host = request.client.host
    response_data = await call_main()
    return {"client_host": client_host, "response_data": response_data} #, "response_cal": response_cal}

# 6. get URL
@app.get("/items/line/{item_id}")
async def get_line(item_id: int):
    return item_id

# 7-BaseModel : 값 정리역할
class Item(BaseModel):
    price: int
    cnt: int
    name: str

# 7-response : post test 받은 값을 리턴
@app.post("/items_test/")
async def items_test(item: Item):
    # dict_price = {"item_price": item.price, "item_cnt": item.cnt}
    return item.price * item.cnt, item.name


# 7-requestpost : test json 값과 함께 post 요청
@app.get('/ii/')
async def read_item():
    # POST 요청을 생성하여 /items_test 엔드포인트에 데이터 전송
    async with httpx.AsyncClient() as client:
        item_data = {"price": 10, "cnt": 5, "name":"youngs"}  # 원하는 데이터 설정
        try:
            response = await client.post("http://127.0.0.1:8000/items_test/", json=item_data)
            response.raise_for_status()  # HTTP 오류가 있는 경우 예외 발생
            return {"item_from_post": response.json()}
        except httpx.HTTPError as e:
            return {"error": f"HTTP error occurred: {str(e)}"}
        except Exception as e:
            return {"error": f"An error occurred: {str(e)}"}
 

 

'Python > FastAPI' 카테고리의 다른 글

Fast API 장단점  (0) 2024.01.29

+ Recent posts