Celery는 Django의 비동기 & 백그라운드 작업을 효율적으로 처리하는 도구 이다.

 

주요기능

  •  웹 요청과 독립적으로 무거운 작업 처리 가능
  •  Django ORM과의 연계로 데이터베이스 처리 최적화
  • celery-beat를 사용해 주기적 작업 관리 가능
  • 분산 처리로 서버 부하 감소 및 성능 최적화
  • 태스크 체인을 활용한 비동기 워크플로우 구현 가능
  • Flower 같은 모니터링 도구를 활용해 작업 추적 가능

 

 

1. Celery 설치

pip install celery

 

 

2. Celery 설정 추가

CELERY_BROKER_URL = "redis://localhost:6379/0"

CELERY_ACCEPT_CONTENT = ['json']

CELERY_TASK_SERIALIZER = 'json'

 

 

3. Celery 파일 추가

import os
from celery import Celery

# Django의 기본 settings 모듈을 Celery 설정으로 사용
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "celery_test.settings")

app = Celery("celery_test")

# 설정 파일을 Celery에 로드
app.config_from_object("django.conf:settings", namespace="CELERY")

# Django의 모든 등록된 앱에서 task 자동 검색
app.autodiscover_tasks()

 

 

4. init 등록

# __init__.py 등록
from .celery import app as celery_app

__all__ = ("celery_app",)

 

 

5. Celery 기능

  • 기본적인 작업 큐(Task Queue)
  • 주기적 작업(Periodic Tasks)
  • 체인과 그룹(Chains & Groups)
  • 비동기 결과 백엔드(Async Results & Backends)
  • 리트라이(Retries) 및 예외 처리
  • 비동기 워크플로우(Workflows)
  • 모니터링(Flower, Prometheus 등)
import os
from celery import Celery

# Django settings 모듈 설정
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "celery_test.settings")

app = Celery("celery_test")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()

# 기본 작업 큐(Task Queue)
from celery import shared_task

@shared_task
def add(x, y):
    return x + y

# 주기적 작업(Periodic Tasks)
from celery.schedules import crontab

app.conf.beat_schedule = {
    'say_hello_every_minute': {
        'task': 'myapp.tasks.say_hello',
        'schedule': crontab(minute='*/1'),  # 1분마다 실행
    },
}

@shared_task
def say_hello():
    print("Hello, Celery!")
    return "Hello, Celery!"

# 체인과 그룹(Chains & Groups)
from celery import chain, group

@shared_task
def multiply(x, y):
    return x * y

@shared_task
def subtract(x, y):
    return x - y

# 체인 예제
chain_result = chain(add.s(4, 6) | multiply.s(2) | subtract.s(5))()

# 그룹 예제
group_result = group(add.s(2, 3), multiply.s(4, 5), subtract.s(10, 3))()

# 비동기 결과 백엔드(Async Results & Backends)
from celery.result import AsyncResult

def get_task_result(task_id):
    result = AsyncResult(task_id)
    return result.status, result.result

# 리트라이(Retries) 및 예외 처리
from celery.exceptions import Retry
import random

@shared_task(bind=True, max_retries=3)
def unstable_task(self):
    if random.choice([True, False]):
        raise self.retry(exc=Exception("Temporary Failure"))
    return "Task Succeeded"

# 비동기 워크플로우(Workflows)
@app.task(bind=True)
def complex_workflow(self, x, y):
    task_chain = (add.s(x, y) | multiply.s(2) | subtract.s(5))()
    return task_chain

# 모니터링(Flower 설정)
app.conf.update(
    CELERY_FLOWER_URL="http://localhost:5555"
)

 

1. Flutter 설치 

https://flutter-ko.dev/get-started/install

 

Choose your development platform to get started

Install Flutter and get started. Downloads available for Windows, macOS, Linux, and ChromeOS operating systems.

docs.flutter.dev

OS에 맞는 환경으로 설치

 

 

 

2. 환경변수 설정

 

 

3. Flutter doctor 이슈 검사

 

 

 

4. Visual Studio C++ 설치

Visual Studio 커뮤니티 버전 설치

 

설치 시 사용할 SW 개발 목적에 맞는 워크로드 추가

 

 

5. Android Studio 설치

https://developer.android.com/studio?gclid=CjwKCAjw1MajBhAcEiwAagW9MfszrJBGihqbCJHVR92_wHZvLSbepyopod1y84opOMCkiT0ZEmM5JxoCSpAQAvD_BwE&gclsrc=aw.ds&hl=ko

 

Android 스튜디오 및 앱 도구 다운로드 - Android 개발자  |  Android Studio  |  Android Developers

Android Studio provides app builders with an integrated development environment (IDE) optimized for Android apps. Download Android Studio today.

developer.android.com

 

 

 

6. Android SDK Manager 에서 Build Tool 설치

File -> Settings -> Languages & Frameworks -> Android SDK -> SDK Tools -> Goole USB Driver

 

 

 

7. Flutter 설정

- CMD 에서 flutter doctor 실행

- flutter config --android-sdk {Android SDK Location}

 

- flutter doctor --android-licenses

SDK 패키지에 대해 승인

 

- flutter doctor

마지막으로 flutter doctor를 실행해서 issue가 없으면 완료

 

 

8. Plug in 설치

Android Studio -> File -> Settings -> Plugins -> Flutter & Dart install

 

 

 

9. Flutter Project 설치

File -> New Project 에서 Flutter 프로젝트가 생성되면 Fluuter APP 개발 환경 세팅 완료

windows 기준 설치

https://gstreamer.freedesktop.org/download/#windows

 

Download GStreamer

If you're on Linux or a BSD variant, you can install GStreamer using your package manager. For other platforms listed below, we provide binary releases in the form of official installers or tarballs maintained by the GStreamer project. Choose your platform

gstreamer.freedesktop.org

msvc로 설치

 

설치할때 complete로 설치

gst-launch-1.0.exe --version

 

 

gst-launch-1.0.exe videotestsrc ! videoconvert ! autovideosink
 

 

 

 

 

 

 

 

참고자료

https://blog.naver.com/chandong83/222157959643

 

ffmpeg와 ONVIF를 사용한 RTSP 영상 스트리밍

ONVIF는 목적상 스트리밍 용도로 사용하지는 않지만 사용하는 경우가 있기에 이번기회에 둘다 정리하려고 쓰는 글입니다. ONVIF, RTSP에 대한 설명으로 시작해서 ffmpeg, ONVIF python 환경 세팅과 테스트 코드 실행까지 해보는걸로 마무리하겠습니다 

 

ONVIF와 RTSP

  1. ONVIF (Open Network Video Interface Forum):
    • ONVIF는 네트워크 카메라 및 비디오 장비 간의 상호 운용성을 보장하기 위해 만든 표준
    • 주로 카메라의 설정, 제어, 관리 등을 위해 사용함. 예를 들어, PTZ(팬, 틸트, 줌) 제어, 이벤트 알림, 비디오 분석 데이터 제공 등이 가능
    • ONVIF를 통해 네트워크 카메라에서 사용할 수 있는 스트리밍 프로파일과 스트리밍 URL을 얻어냄
  2. RTSP (Real-Time Streaming Protocol):
    • RTSP는 실시간 스트리밍 데이터를 전송하기 위한 프로토콜
    • 주로 비디오 스트리밍을 위해 사용되며, 클라이언트가 서버에 스트리밍 미디어 세션을 설정하는 데 사용
    • RTSP는 실시간 데이터를 제공하는 카메라와 같은 장치에서 데이터를 가져오는 데 사용

 

1. ffmpeg 스트리밍

Windows ffmpeg 설치

  • ffmpeg 다운로드 사이트 이동

https://www.ffmpeg.org/download.html

 

Download FFmpeg

If you find FFmpeg useful, you are welcome to contribute by donating. More downloading options Git Repositories Since FFmpeg is developed with Git, multiple repositories from developers and groups of developers are available. Release Verification All FFmpe

www.ffmpeg.org

 

  • OS 환경에 맞게 Windows 에서 'Windows builds from gyan.dev 클릭

 

 

  • ffmpeg 깃허브 사이트로 이동

 

 

  • fuil build.zip 다운로드

 

 

  • 압축풀면 다운로드 완료 

 

ffmpeg RTSP 연결 예시코드

import cv2
import numpy as np
import ffmpeg


def stream_f(stream_url):
    probe = ffmpeg.probe(stream_url)
    cap_info = next(C for C in probe['streams'] if C['codec_type'] == 'video')
    width = cap_info['width']
    height = cap_info['height']
    up, down = str(cap_info['r_frame_rate']).split('/')
    fps = eval(up) / eval(down)
    process = (
        ffmpeg
        .input(stream_url, fflags='nobuffer',flags='low_delay')
        .output('pipe:', format='rawvideo', pix_fmt='rgb24')
        .overwrite_output()
        .run_async(pipe_stdout=True)
    )

    while True:
        in_bytes = process.stdout.read(width * height * 3)
        if not in_bytes:
            break

        frame = np.frombuffer(in_bytes, np.uint8).reshape([height, width, 3])
        frame = cv2.resize(frame, (1280, 720))
        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
        cv2.imshow('Camera View', frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    process.stdout.close()
    process.wait()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    stream_url = "rtsp_url"
    stream_f(stream_url)

 

 

2. onvif 스트리밍

  • 설치
pip install onvif-zeep

 

  • 패키지 다운로드 (패키지 파일을 통해 사용하는 방법)
git clone https://github.com/FalkTannhaeuser/python-onvif-zeep.git
 

GitHub - FalkTannhaeuser/python-onvif-zeep: ONVIF Client Implementation in Python 2+3 (using https://github.com/mvantellingen/py

ONVIF Client Implementation in Python 2+3 (using https://github.com/mvantellingen/python-zeep instead of suds as SOAP client) - FalkTannhaeuser/python-onvif-zeep

github.com

 

  • 예시코드
import cv2
from onvif import ONVIFCamera

def get_rtsp_url(host, port, user, password):
    wsdl_dir = 'python-onvif-zeep/wsdl/'
    camera = ONVIFCamera(host, port, user, password, wsdl_dir=wsdl_dir)
    media_service = camera.create_media_service()
    profiles = media_service.GetProfiles()
    token = profiles[0].token


    stream_uri = media_service.GetStreamUri({
        'StreamSetup': {
            'Stream': 'RTP-Unicast',
            'Transport': {
                'Protocol': 'RTSP'
            }
        },
        'ProfileToken': token
    })

    return stream_uri.Uri


def stream_O(stream_url):
    cap = cv2.VideoCapture(rtsp_url)

    if not cap.isOpened():
        print("connect fail")
    else:
        while True:
            ret, frame = cap.read()
            if not ret:
                print("not frame")
                break

            cv2.imshow('ONVIF Camera Stream', frame)

            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
    
    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    host = "IP"
    port = "port"
    user = "USER"
    password = "PW"
    rtsp_url = get_rtsp_url(host, port, user, password)
    stream_O(rtsp_url)

 

IP, port, User, PW는 따로 입력해주셔야합니다. 그리고 카메라에 따라 ONVIF는 제어 가능하도록 설정하는 과정이 필요합니다. 대게는 테스트 모드를 켜거나 URL을 통해 권한을 설정하도록 되어있음

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

[python] Gstreamer  (1) 2024.09.05

머신러닝 분류 알고리즘 정리로 결정트리와 앙상블 학습에 대해 개념 정리로 어떠한 상황에 어떤 학습방법을 사용하는게 좋을까 라는 판단이 가능하도록 유도하는것이 목적인 정리

 

 

1. 결정트리

루트노드와 그아래 규칙 노드와 리프노드로 가지치기를 하듯 분류하는 알고리즘이다

결정트리의 올바른 방향은 지니계수가 작아지고 결정트리가 대칭을 유지하도록 데이터 전처리 및 엔지니어링 하는것이 바람직하다.

 

용어 정리

루트 노드 시작점
규칙 노드 가지 치기 규칙
리프 노드 분류 결정 값을 가짐
지니계수  정보이득 지수값 (값이 크면 불순도가 높음)

 

 

파라미터

min_samples_split  노드를 분할하기 위한 최소 샘플 데이터 수
min_samples_leaf  리프 노드의 최소 샘플 데이터 수
max_features  분할에 사용되는 최대 피쳐 수 (default는 모두사용)
max_depth  트리의 최대 깊이 설정
max_leaf_nodes  리프 노드 최대 개수

 

 

활용 방안

  • 결정 트리 시각화

 

 

  • 피쳐별 중요도 (Featuer Importance) 시각화

 

  • 산포도 기반 시각화

 

 

 

 

2. 앙상블 학습

앙상블 학습은 여러개의 알고리즘을 생성, 학습, 예측 값 처리 후 최종 결과를 도출하는 기법으로 방식에 따라 다음의 4가지로 구분한다. 쉽게보면 위의 결정트리가 학습 결과가 약한 모델이라면 이를 반복 혹은 계속적인 학습, 결합을 통해 강한 모델을 만드는 방식이다

  • 보팅

다른 알고리즘을 여러개 병렬 연결하여 사용하는 방법이다

 

종류에 따라 하드 보팅, 소프트 보팅으로 나눌수 있으며 방법은 아래의 사진과 같다.

하드 보팅 다수결, 최빈값
소프트 보팅 확률값 평균

하드 보팅은 상황에 따라 약한 분류 모델의 다수표를 받아 선정될 수 있기에 약점이 존재하여 소프트 보팅이 주로 성능이 더 높음으로 판단된다.

 

  • 배깅

개별 모델들이 서로 다른 샘플링 데이터를 훈련에 사용하여 병렬 연결하며 동일 알고리즘을 여러개 만들어서 소프트 보팅을 수행한다. 부스팅 모델에 비해 특수한 경우가 아니고선 성능이 좋을 확률이 낮음  EX) 랜덤 포레스트

 

샘플링 데이터는 위의 표처럼 중복된 샘플링일수 있음

 

  • 부스팅

현재는 가장 강한 분류 모델로 여러개의 약한 분류기를 순차적으로 학습 및 예측을 수행하며 잘못 예측한 데이터에 가중치를 부여하여 오류를 개선하여 다음 학습에 반영하는 방식이다.

 

모델 종류

AdaBoost  반복적인 가중치 계산을 통해 값들을 분류하며 성능 향상하는 방식
GBM (Gradient Boost Machine) 1. Ada에서 가중치를 업데이트 하는 방식으로의 개선 
2. 경사하강법 가중치 업데이트 방식
XGBoost 1. GBM의 느린학습속도와 과적합을 보완
2. 병렬 학습
3. 조기학습종료 기능
4. 과적합 방지 파라미터 (L1,L2) 
LGBM 비대칭형 분류
서드파티 CatBoost

 

 

XGBoost

  • 파라미터
booster  부스팅 알고리즘 트리기반 모델 : gbtree or dart
선형기반 모델 : gblinear 
dart : 과적합 방지를 위한 특정 비율 dropout 적용
objective 훈련 목적 회귀 :  reg:squarederror
이진분류 : binary:logistic
다중분류 : multi:softmax
확률값 다중분류 : multi:softprob
eta learning_rate
학습 비율 가중
부스팅을 반복 과정에서 모델 업데이트 비율
default : 0.3
범위 : 0 ~ 1
min_child_weight 과적합 방지 범위 0 ~ 1
하위 노드의 최소 가중치의 합 (리프 노드까지의 모든가중치의 합에 대한 제한값)
값이 크면 과소적합 우려가있음
max_depth 트리의 깊이 과적합 방지
분류가 깊어지면 메모리 사용량 증가로 학습 속도가 저하
max_leaf_nodes 리프 노드의 최대 개수 리프 노드의 최대 개수
gamma 노드 분할 시 최소 감소값 지정 default 0
노드 분할시 필요한 최소 감소값을 지정
손실 감소가 gamma보다 크면 노드 분할
값이 클수록과대 적합 방지 효과 
subsamplt 데이터 샘플링 비율 default 1
범위 0 ~ 1 (0.6~1 사용)
데이터의 샘플링 비율
colsample_bytree 각 트리 샘플링 비율 각 트리 샘플링 비율
범위 0~1
default 1
lambda 가중치에 대한 L2규제 조정값 가중치에 대한 L2규제 조정값 (릿지 알고리즘)
default 1
값이 크면 과대적합 방지효과
alpha 가중치에 대한 L1규제 조정값 가중치에 대한 L1규제 조정값 (라쏘 알고리즘)
값이 크면 과대적합 방지효과
default 1
scale_pos_weight 불균형 데이터 가중치 조정값 label값이 불균형할때 균형을 맞춤
random_state 랜덤 시드값 랜덤 시드

 

LGBM

  • 파라미터

  • 스태킹

2단계를 통해 모델을 생성하는 방법으로 1차 모델의 예측 결과를 2차 모델의 훈련 데이터로 사용하는 형태

 

 

3. 앙상블 학습 시 추가 방안

 

그리드서치 

- 하이퍼파라미터 튜닝

 

K폴드

- 데이터 분할 방식

 

'Python > 머신러닝' 카테고리의 다른 글

[XAI] XGBoost 분류 모델 시각화  (6) 2024.08.28
머신러닝 데이터 교차검증 python  (0) 2024.03.05
머신러닝 피쳐스케일링 python  (0) 2024.03.05

신호처리 AI 프로젝트를 시작하면서 프로젝트 초기 데이터 분석을 하던 중 레퍼런스 중 기본연구보고서에서 결정트리를 시각화 한 사진을 보고 좋은 방법이라는 생각이 들어서 머신러닝으로 데이터를 분석하기 시작했다

 

 

1. DecisionTreeClassifier plot_tree 방법

처음에는 기본연구보고서와 같은방법으로 결정트리로 시각화 해보았으나 아래의 사진처럼 분석하던 데이터는 아래의 사진처럼 단순 트리 구조만으로 시각화 하기에는 좋지 않아보였고 이보다는 차트나 군집으로 시각화 하는것이 맞겠다는 생각이 들어서 XAI 방법에 대해 찾아보던 중 XGBoost로 시각화하는 방법을 찾게 됐다.

 

 

2. XGBoost - importance feature, Decision Boundary

XGBoost의 XGBClassifier의 gbtree booster를 사용해 트리 모델을 사용하면 트리 결과를 사용하여 아래 사진과 같이 시각화가 가능했다. feature importance의 결과를 바탕으로 값이 높은 feature 2개를 사용해서 시각화 하도록 만들었다. 확실히 한눈에 잘 보여서 이후 데이터 수집에서의 문제점을 찾아 ETL 프로그램을 수정했다.

 

 

3. 마무리

시각화로 인한 문제점 파악의 힘은 굉장했고 바로 핵심이 파악되어서 피쳐 엔지니어링 + 데이터 수집 관점 변경 으로 원하는 결과를 찾아냈다 피쳐 엔지니어링을 통해 찾아낸 핵심 데이터로 만든 오른쪽의 한줄로 구분되는 분류 모델은 매우 정확한 데이터 분석이였다 

 

프로젝트 초기 가능성 검사였고 분류 모델 AI인 점 + 시각화의 시너지가 잘맞아서 좋은 효과를 낸것 같다

이후 프로젝트에서 회귀 모델 분석에서도 XAI 방식을 적용해보면 좋을것 같다

 

 

4. Code

XGB 사용되는 부분의 기본 코드입니다

# 훈련/테스트 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.7)#, random_state=1)

# XGBoost 모델 학습
xg_reg = XGBClassifier(
    booster='gbtree', 
    max_depth=20, 
    objective='binary:logistic', 
    eval_metric='logloss',
    verbosity=0,
    n_estimators = 100,
    device='cuda',
    validate_parameters = True)
xg_reg.fit(X_train, y_train)

pred = xg_reg.predict_proba(X_test)
pred_t = pred[:, -1]
fpr, tpr, _ = roc_curve(y_test.values, pred_t)

print('XGBoost AUC:', auc(fpr, tpr))

# 피처 중요도 시각화
plt.figure(figsize=(10, 6))
plot_importance(xg_reg, importance_type='weight', max_num_features=10, height=0.5)
plt.show()

# XGB 경계 시각화
xg_importantces_param_count = 2

xg_importances = xg_reg.feature_importances_
xg_indices = np.argsort(importances)[::-1]
xg_importances_param = X.columns[xg_indices[:xg_importantces_param_count]]

X_subset = X_train[[xg_importances_param[i] for i in range(xg_importantces_param_count)]]
xg_subset_reg = XGBClassifier(
    booster='gbtree', 
    max_depth=20, 
    objective='binary:logistic', 
    eval_metric='rmse',
    verbosity=0,
    n_estimators = 100,
    device='cuda',
    validate_parameters = True)
xg_subset_reg.fit(X_subset, y_train)

x_min, x_max = X_subset[xg_importances_param[0]].min() - 1, X_subset[xg_importances_param[0]].max() + 1
y_min, y_max = X_subset[xg_importances_param[1]].min() - 1, X_subset[xg_importances_param[1]].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),
                     np.arange(y_min, y_max, 0.01))
Z = xg_subset_reg.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

plt.figure(figsize=(10, 6))
plt.contourf(xx, yy, Z, alpha=0.4, cmap='viridis')
sns.scatterplot(x=X_train[xg_importances_param[0]], y=X_train[xg_importances_param[1]], hue=y_train, palette='viridis', edgecolor='k')
plt.title(f'Decision Boundary ({xg_importances_param[0]} vs {xg_importances_param[1]})')
plt.xlabel(f'{xg_importances_param[0]}')
plt.ylabel(f'{xg_importances_param[1]}')
plt.show()

 

1. 설치

https://www.postman.com/downloads/

 

Download Postman | Get Started for Free

Try Postman for free! Join 30 million developers who rely on Postman, the collaboration platform for API development. Create better APIs—faster.

www.postman.com

 

 

2. "+" 버튼을 클릭하여 새 요청 탭 생성

 

 

 

3. HTTP 메소드 설정

GET, POST, PUT , DELETE .... 등의 사용 할 HTTP 메소드 설정

 

 

4. 테스트 URL 입력 및 결과확인

테스트하려는 API 엔드포인트의 URL을 입력

 

프로그래머스 KAKAO WINTER INTERNSHIP도넛과 막대 그래프

 

문제 설명

도넛 모양 그래프, 막대 모양 그래프, 8자 모양 그래프들이 있습니다. 이 그래프들은 1개 이상의 정점과, 정점들을 연결하는 단방향 간선으로 이루어져 있습니다.

  • 크기가 n인 도넛 모양 그래프는 n개의 정점과 n개의 간선이 있습니다. 도넛 모양 그래프의 아무 한 정점에서 출발해 이용한 적 없는 간선을 계속 따라가면 나머지 n-1개의 정점들을 한 번씩 방문한 뒤 원래 출발했던 정점으로 돌아오게 됩니다. 도넛 모양 그래프의 형태는 다음과 같습니다.
  • 크기가 n인 막대 모양 그래프는 n개의 정점과 n-1개의 간선이 있습니다. 막대 모양 그래프는 임의의 한 정점에서 출발해 간선을 계속 따라가면 나머지 n-1개의 정점을 한 번씩 방문하게 되는 정점이 단 하나 존재합니다. 막대 모양 그래프의 형태는 다음과 같습니다.
  • 크기가 n인 8자 모양 그래프는 2n+1개의 정점과 2n+2개의 간선이 있습니다. 8자 모양 그래프는 크기가 동일한 2개의 도넛 모양 그래프에서 정점을 하나씩 골라 결합시킨 형태의 그래프입니다. 8자 모양 그래프의 형태는 다음과 같습니다.

도넛 모양 그래프, 막대 모양 그래프, 8자 모양 그래프가 여러 개 있습니다. 이 그래프들과 무관한 정점을 하나 생성한 뒤, 각 도넛 모양 그래프, 막대 모양 그래프, 8자 모양 그래프의 임의의 정점 하나로 향하는 간선들을 연결했습니다.
그 후 각 정점에 서로 다른 번호를 매겼습니다.
이때 당신은 그래프의 간선 정보가 주어지면 생성한 정점의 번호와 정점을 생성하기 전 도넛 모양 그래프의 수, 막대 모양 그래프의 수, 8자 모양 그래프의 수를 구해야 합니다.

그래프의 간선 정보를 담은 2차원 정수 배열 edges가 매개변수로 주어집니다. 이때, 생성한 정점의 번호, 도넛 모양 그래프의 수, 막대 모양 그래프의 수, 8자 모양 그래프의 수를 순서대로 1차원 정수 배열에 담아 return 하도록 solution 함수를 완성해 주세요.


제한사항
  • 1 ≤ edges의 길이 ≤ 1,000,000
    • edges의 원소는 [a,b] 형태이며, a번 정점에서 b번 정점으로 향하는 간선이 있다는 것을 나타냅니다.
    • 1 ≤ a, b ≤ 1,000,000
  • 문제의 조건에 맞는 그래프가 주어집니다.
  • 도넛 모양 그래프, 막대 모양 그래프, 8자 모양 그래프의 수의 합은 2이상입니다.

 

 

 

문제 풀이

output : 시작 정점 번호, 도넛 모양 그래프, 막대 모양 그래프, 8자 모양 그래프
시작 정점 번호 : 모든 edge[1] 값에 해당되지 않아야함
도넛 모양 그래프 : edge[0], [1] 이 같은 값이거나
막대 모양 그래프 : edge[1]을 따라 진행 시 마지막에 edge[0]에서 없는 값이 존재하는 형태
8자 모양 그래프 : edge[0]을 한개 값만 가지고 있으며 edge[1] 값을 추적하여 원래 edge[0]값으로 돌아오는 형태

 

 

해결 코드

1. Node 설치

Node와 npm을 다음 사이트에서 설치

https://nodejs.org/en/download/package-manager

 

Node.js — Download Node.js®

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

2. React 설치 및 실행

npm install -g create-react-app

mkdir -p book_trinity/frontend/chapter2/
cd book_trinity/frontend/chapter2/
create-react-app ex_f1_app

### React 서버 실행
cd ex_f1_app
npm start

 

다음의 웹페이지가 자동으로 로딩되면 React 환경 세팅 완료

 

3. Next 설치

npm install --save next react react-dom

 

 

 

Next 실행

package.json 하단 scripts ADD
"scripts":{
    ...
}
"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "export": "next export"
},

mkdir pages
cd pages
echo. > index.js

index.js에 다음 코드를 입력
'''
import React from 'react';

const IndexPage = () => {
  return (
    <div>
      <h1>Welcome to Next.js!</h1>
    </div>
  );
};

export default IndexPage;
'''

cd..
npm run dev

 

다음의 웹페이지가 켜지면 Next 환경 설정 완료

 

 

1. Django 기본 세팅

VScode 에서 Django 프로젝트를 생성할 폴더 를 만들고

 

Ctrl + ` or powershell을 켜서 다음의 명령어를 입력하면 기본 프로젝트 생성 완료

### Django 가상 환경 만들기
- pip install virtualenv
- python -m virtualenv zion_env
- Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
- zion_env/Scripts/activate

### Django 설치
- pip install django

### Django 프로젝트 생성
- django-admin startproject ex_project
- cd ex_project
- python manage.py runserver

 

정상적인 프로젝트 생성 사진

 

 

2. Django APP 추가

Django APP 을 생성하고 기본적인 메인 페이지와 예시 hello 페이지 생성

### APP 생성
python manage.py startapp ex_app

urls.py
from django.contrib import admin
from django.urls import path

from shop_app.views import hello
from shop_app.views import web_main

urlpatterns = [
    path("admin/", admin.site.urls),
    path('', web_main),
    path('hello/', hello)
    
    
views.py
from django.http import HttpResponse

def hello(request):
   return HttpResponse("Hi Hello, World!")

def web_main(request):
   return HttpResponse("main page")

 

 

 

3. DRF 설치

### DRF 설치
pip install djangorestframework

### settings.py 
INSTALLED_APPS =[
	"rest_framework"
]

 

다음은 DRF API 예제 코드이다

### DRF 사용

from django.http import HttpResponse
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import AllowAny

def hello(request):
   return HttpResponse("Hi Hello, World!")

def web_main(request):
   return HttpResponse("main page")

@api_view(['GET', 'POST'])
@permission_classes([AllowAny])
def hello_rest_api(request):
    data = {'message': 'db, REST API!'}
    return Response(data)

+ Recent posts