728x90

파이썬 pandas는 데이터 분석과 관련된 작업을 쉽게 처리할 수 있는 라이브러리입니다. 이번 글에서는 pandas의 주요 기능 중 하나인 데이터프레임(DataFrame)에 대해 알아보겠습니다.

 

데이터프레임(DataFrame)

데이터프레임은 엑셀과 유사한 형태의 2차원 자료구조입니다. 행과 열로 이루어져 있으며, 각 열은 서로 다른 데이터 타입을 가질 수 있습니다. 데이터프레임을 만들기 위해서는 리스트, 딕셔너리, 넘파이 배열 등 다양한 형태의 데이터를 활용할 수 있습니다.

 

데이터프레임 생성하기

아래는 딕셔너리를 이용하여 데이터프레임을 생성하는 방법입니다.

 

import pandas as pd

data = {'name': ['John', 'Mary', 'Peter', 'Jane'],
        'age': [28, 34, 29, 42],
        'city': ['Seoul', 'New York', 'Paris', 'London']}

df = pd.DataFrame(data)
print(df)

출력 결과는 다음과 같습니다.

    name  age      city
0   John   28     Seoul
1   Mary   34  New York
2  Peter   29     Paris
3   Jane   42    London

 

데이터프레임 인덱싱 및 슬라이싱

데이터프레임에서는 (column) (row) 각각 인덱싱할 있습니다. 열을 인덱싱하는 방법은 딕셔너리의 인덱싱 방법과 유사합니다.

 

print(df['name'])

# 출력결과
0     John
1     Mary
2    Peter
3     Jane
Name: name, dtype: object

 

행을 인덱싱하는 방법은 loc 메서드나 iloc 메서드를 사용합니다. loc 메서드는 행 인덱스를 기준으로 인덱싱하며, iloc 메서드는 행 번호를 기준으로 인덱싱합니다.

 
# loc 메서드를 사용하여 인덱싱하기
print(df.loc[0])  # 첫 번째 행을 출력합니다.

# iloc 메서드를 사용하여 인덱싱하기
print(df.iloc[0])  # 첫 번째 행을 출력합니다.

#출력결과-loc
name      John
age         28
city     Seoul
Name: 0, dtype: object

#출력결과-iloc
name      John
age         28
city     Seoul
Name: 0, dtype: object

 

아래 코드에서 iloc은 인덱스 번호를 사용하여 데이터프레임을 슬라이싱하며, loc은 열 이름을 사용하여 데이터프레임을 슬라이싱합니다.

iloc에서 [:, 1:3] 모든 (:)에서 1번째 열부터 3번째 (3번째 열은 포함되지 않음)까지 선택합니다.

loc에서 [:, 'name':'math'] 모든 (:)에서 'name'열부터 'math'열까지 선택합니다.

 

# 열 슬라이싱

# 인덱스를 사용하여 열 슬라이싱
df2 = df.iloc[:, 1:3] # 1번째 열부터 3번째 열(3번째 열은 포함되지 않음)까지 선택

# 열 이름을 사용하여 열 슬라이싱
df3 = df.loc[:, 'name':'math'] # 'name'열부터 'math'열까지 선택
728x90

파이썬 웹크롤링 패키지로 크게 BeautifulSoup과 selenium이 있습니다.

 

BeautifulSoup으로는 동적페이지를 파싱해오기 어렵기때문에

동적페이지에서는 selenium을 사용하고 정적페이지에서는 BeautifulSoup을 써도 무방합니다.

 

먼저 BeautifulSoup에 대해서 위키백과 설명을 보면

HTML과 XML 문서들의 구문을 분석하기 위한 파이썬 패키지이다

HTML로부터 데이터를 추출하기 위해 사용할 수 있는 파싱된 페이지의 파스 트리를 만드는데, 이는 웹 스크래핑에 유용하다

이렇게 나와있습니다.

 

BeautifulSoup을 사용하면 계층구조로 된 html태그를 바탕으로 쉽게 파싱을 해올 수 있는데

먼저 파싱해올 url을 아래와 같이 입력하여 가져옵니다.

 

from bs4 import BeautifulSoup
from urllib.request import urlopen

if __name__ == "__main__":
    url = 'https://naver.com'
    html = urlopen(url)
    bsObject = BeautifulSoup(html, "html.parser")

그 후 가져오고 싶은 영역이 있으면 .find()를이용해서 가져온 bsObject 안에서 해당 태그를 가져옵니다

print(bsObject.find('div', 'list_theme_wrap'))

만약에 li와 같은 리스트를 가져오고 싶으면 find_all()을 사용해서 list형식으로 가져올 수도 있습니다.

print(bsObject.find_all('li', 'theme_item'))

또 그안에 있는 text를 가져오려면 .text를 용한뒤 .strip()을 통해 좌우 공백을 지워줄 수 있습니다.

li_list = bsObject.find_all('li', 'theme_item')

    for li in li_list:
        print(li.text.strip())

 

728x90

소프트웨어 버전관리를 하게되면 현재버전이 최신버전인지 아닌지 비교해야할 경우가 생깁니다

 

현재버전이 1.0.0이고 최신버전이 1.0.1이라고 하면 

버전을 비교해서 현재버전이 최신버전보다 낮으면 업그레이드를 하라고 알림 줘야하기 떄문입니다 

 

그럴때 유용하게 쓸 수 있는 패키지가 semver패키지입니다

 

저도 앱 강제업데이트를 위해서 버전비교하는 로직을 만들다가 

버전에서 .로 나눈다음에 숫자로 바꿔서 크기비교를 해야하나 라는 고민을 하다가

semver 패키지를 알게되었고 아주 간단하게 버전비교를 할 수 있었습니다

 

 

먼저 pip install semver로 패키지 설치를 진행한 뒤 아래 코드처럼 import 해서 사용하시면 됩니다

import semver

def app_update_check(db, data):
    version = convert_data_app_version(AppDao.app_update_check(db))

    # 최소 버전보다 낮으면 강제 업데이트, 최소 버전보다 높은데 최신 버전보다 낮으면 선택 업데이트
    # result (-1: 왼쪽이 낮음, 1: 왼쪽이 높음, 0: 같음)
    # 강제업데이트
    isForceUpdate = semver.compare(data['version'], version['min_version'])

    # 선택 업데이트
    isUpdate = semver.compare(data['version'], version['newest_version'])

    return {"isForceUpdate": isForceUpdate, 'isUpdate': isUpdate}

소스를 보시면 클라이언트에게 현재버전을 받고, db에서 최소버전 최신버전을 가져와서 비교를 한뒤
강제업데이트를 할것인지 선택업데이트를 할것인지 응답을 주는 코드인데 semver.compare()를 사용하면
바로 결과값이 나오는걸 확인할 수 있습니다

728x90

fastapi에는 spring의 Interceptor와 같이 api호출 후 전/후처리를 할 수 있는 기능이 있습니다.

middleware를 적용하면 되는데

 

먼저 middleware/middleware.py를 생성해줍니다

from fastapi import Request
from chatterbot.utils import get_logger
import time

logger = get_logger(__name__)


class Middleware:
    def __init__(
            self,
            some_attribute: str,
    ):
        self.some_attribute = some_attribute

    async def __call__(self, request: Request, call_next):
        logger.debug("")
        logger.debug(" ******************** start ******************** ")
        logger.debug(" ***** request path : {} ".format(request.url.path))

        start_time = time.time()
        response = await call_next(request)
        process_time = time.time() - start_time
        response.headers["X-Process-Time"] = str(process_time)

        logger.debug(" ***** process_time : {} ".format(process_time))
        logger.debug(" ******************** end ******************** ")
        logger.debug("")

        return response

소스코드를 보시면 __call__함수가 있고, 그 안에서 
1. start_time 찍기
2. call_nest(request)호출
3. process_time찍기
순으로 실행을 하는데 이 과정을거쳐서 호출된 요청의 process_time을 찍을 수 있습니다.

 

await call_nest(reques)로 사용자가 요청하기 전에 전처리를 하고
응답값을 받아온 후에 후처리를 로직을 넣어서 구서을 하시면 됩니다.

 

 

이렇게 작성한 middleware를 router에 add해야하는데
main.py 소스에 아래부분을 추가하면 됩니다.

 

from middleware.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware

app = FastAPI()

middleware = Middleware(some_attribute="some_attribute_here_if_needed")
app.add_middleware(BaseHTTPMiddleware, dispatch=middleware)

+ Recent posts