Now Loading ...
-
-
-
-
JAVA advance
Package
Package는 연관성이 있거나 유사한 class들을 하나의 집단으로 묶는 방법입니다. 같은 Package 내에서는 import 없이 사용이 가능합니다. 하지만 sub package의 경우에는 import가 필요합니다.
access modifier
접근 제어자는 변수나 메서드의 권한 설정을 하는 키워드 입니다.
private < default < protected < public의 순서로 권한이 약해집니다.
private
클래스에서만 사용가능한 가장 보안적인 권한입니다.
default
가장 기본적인 권한으로 access modifier가 없으면 적용됩니다. 동일한 package 내에서 사용이 가능합니다.
protected
동일한 package 내에서 또는 상속받은 class에서 사용이 가능합니다.
public
자유롭게 사용가능한 권한입니다.
static
클래스간의 공유가 필요한 인자의 경우 static을 사용합니다. 이는 메모리를 줄일 수 있으나 무분별한 사용은 인스턴스간의 간섭을 유발할 수 있습니다.
static method
static을 method에서 사용할 경우 인스턴스가 아니더라도 클래스인 상태에서 method를 직접적으로 사용이 가능합니다. 이는 모든 인스턴스에 공유됩니다.
singleton pattern
static의 개념을 확장하면 singleton pattern으로 사용이 가능합니다. 이 방식은 메모리낭비를 줄이며, 하나의 객체로 유지되어야하는 디자인 패턴에서 유용합니다. 아래는 singleton pattern을 만드는 방식입니다.
{% highlight java %}
class Singleton {
private static Singleton one;
private Singleton() {
}
public static Singleton getInstance() {
if(one==null) {
one = new Singleton();
}
return one;
} }
Singleton singleton = Singleton.getInstance();
{% endhighlight %}
exception
코드를 구성하다보면 다양한 예외 케이스들이 생길 수 있습니다. 그에 따라서 예외 처리를 핸들링 할 수 있어야합니다. 다음은 try except문을 활용하여 기본적인 exception 구조를 만드는 방법입니다. 이러한 구조를 통하여 transaction이 관리될 수 있습니다.
{% highlight java %}
try {
c = 4 / 0;
} catch(ArithmeticException e) {
c = -1; // 예외가 발생하여 이 문장이 수행된다.
} finally {
System.out.println(“end”)
}
{% endhighlight %}
{% highlight java %}
public void sayNick(String nick) throws ArithmeticException {
if(“a” == “b”) {
throw new ArithmeticException();
}
System.out.println(“hi”);
}
{% endhighlight %}
thread
프로그램이 동작하는 process에서 다중업무를 동작하는 방법을 threading이라고 합니다. 아래의 방식은 thread를 사용할 수 있는 방법을 나타냅니다.
{% highlight java %}
public class Sample extends Thread {
public void run() { // Thread 를 상속하면 run 메서드를 구현해야 한다.
System.out.println(“thread run.”);
}
public static void main(String[] args) {
Sample sample = new Sample();
sample.start(); // start()로 쓰레드를 실행
sample.join(); // 쓰레드가 종료될때까지 대기
} } {% endhighlight %}
위의 방식은 가장기본적인 방식이며, 확장성을 위하여 interface를 사용하는 방식을 권장합니다.
{% highlight java %}
public class Sample implements Runnable {
int seq;
public Sample(int seq) {
this.seq = seq;
}
public void run() {
System.out.println(this.seq+" thread start.");
try {
Thread.sleep(1000);
}catch(Exception e) {
}
System.out.println(this.seq+" thread end.");
}
public void main() {
Thread t = new Thread(new Sample(i));
} } {% endhighlight %}
functional style
lambda function
java에서 이제 lambda를 지원하고 있습니다. 아래는 그 예시이며, 주의할 점은 interface에 2개이상의 method를 허용하지 않습니다.
{% highlight java %}
@FunctionalInterface
interface Calculator {
int sum(int a, int b);
}
public class Sample {
public static void main(String[] args) {
Calculator mc = (int a, int b) -> a +b; // 람다코드
int result = mc.sum(3, 4);
}
}
{% endhighlight %}
stream
streaming과 같은것으로 오해할 수 있지만, stream은 말그대로 서순적인 흐름을 의미합니다. 아래는 stream을 사용하는 방법이며, 이와 같이 복잡한 변환을 가시성 있게 정리 할 수 있습니다.
{% highlight java %}
int[] data = {5, 6, 4, 2, 3, 1, 1, 2, 2, 4, 8};
int[] result = Arrays.stream(data) // IntStream을 생성한다.
.boxed() // IntStream을 Stream로 변경한다.
.filter((a) -> a % 2 == 0) // 짝수만 뽑아낸다.
.distinct() // 중복을 제거한다.
.sorted(Comparator.reverseOrder()) // 역순으로 정렬한다.
.mapToInt(Integer::intValue) // Stream를 IntStream으로 변경한다.
.toArray() // int[] 배열로 반환한다.
;
{% endhighlight %}
JAVA
/
basic
· 2024-04-09
-
-
-
-
JAVA types
type of JAVA
자바에는 다양한 타입이 있습니다. 이는 엄격하며, 규칙을 잘 지켜서 작성해야 합니다.
normal types
다음은 일반적인 type에 대한 설명입니다. 선언할때 final 키워드를 넣을 수 있는데 이는 값이 변환이 없어야 할때 사용됩니다.
int
-2147483648 ~ 2147483647를 표현 가능한 정수입니다.
{% highlight java %}
int num = 20;
{% endhighlight %}
long
-9223372036854775808 ~ 9223372036854775807를 표현 가능한 정수입니다.
{% highlight java %}
long num = 20L;
{% endhighlight %}
byte
-128 ~ 127를 표현 가능한 정수입니다.
{% highlight java %}
byte num = 20;
{% endhighlight %}
short
-32768 ~ 32767를 표현 가능한 정수입니다.
{% highlight java %}
short num = 20;
{% endhighlight %}
float
$-3.4^{38} \sim 3.4^{38}$를 표현 가능한 실수입니다.
{% highlight java %}
float num = 3.14F;
{% endhighlight %}
double
$-1.7^{308} \sim 1.7^{308}$를 표현 가능한 실수입니다.
{% highlight java %}
double num = 3.14;
{% endhighlight %}
boolean
true, false를 표현 가능한 자료형입니다.
{% highlight java %}
boolean isOkay = true;
{% endhighlight %}
char
단일 문자를 표현 가능한 자료형입니다. char는 다음과 같이 다양한 형태로 대입이 가능합니다.
{% highlight java %}
char data1 = ‘a’; // 문자
char data1 = 97; // 아스키 코드
char data1 = ‘\u0061’; // 유니 코드
{% endhighlight %}
String
다중 문자를 표현 가능한 자료형입니다. String은 다른 자료형과 다르게 객체입니다. 이러한 이유는 다중문자는 가변적인 사이즈를 가지기 때문입니다.
{% highlight java %}
String name = “Minsu”;
{% endhighlight %}
string은 객체이기 때문에 다음과 같은 method와 특징들을 가집니다.
a.equals(b) : a,b가 같은지 비교합니다.
a == b : a,b가 같은 객체인지 비교합니다.
a.indexOf(“name”) : name이 몇번째 위치에 있는지 확인합니다.
a.contains(“name”) : name이 포함되어 있는지 확인합니다.
a.charAt(num) : num에 있는 문자를 반환합니다.
a.replaceAll(“A”,”B”) : A를 B로 변환합니다.
a.substring(num1, num2) : num1에서 num2에 있는 문자들을 반환합니다.
a.toUpperCase() : 대문자로 변환합니다.
a.split(char) : char를 기준으로 문자를 잘라서 배열로 반환합니다.
StringBuffer
다중 문자를 표현 가능한 자료형입니다. String과 다른점은 수정을 할때 용이하다는 점입니다. String은 객체로 구성되어 있어 수정할때마다 객체가 생성되지만 StringBuffer는 1개의 객체로 수정이 가능합니다. 하지만 수정이 빈번하게 일어나는 경우가 아닌경우 오히려 메모리 사용량 효율이 좋지 않습니다.
{% highlight java %}
StringBuffer name = new StringBuffer();
name.append(“Minsu”);
name.insert(0, “Kim”);
name.substring(0, 10);
String result = name.toString();
{% endhighlight %}
StringBuilder
StringBuffer과 같습니다. 하지만 성능이 조금 더 좋습니다. 단점으로는 멀티 스레드환경에서 취약합니다.
Array
데이터의 집합을 표현 가능한 자료형입니다.
{% highlight java %}
int[] odds = {1, 3, 5}
String[] weeks = new String[7]; // 사이즈 지정 선언
weeks[0] = “월”;
{% endhighlight %}
List
Array와 같이데이터의 집합을 표현 가능한 자료형입니다. 다른점은 선언 이후 사이즈의 변경이 가능하다는 점입니다. List는 사용방법에 따라 ArrayList, LinkedList와 같이 다양한 자료형이 있습니다.
{% highlight java %}
import java.util.ArrayList;
ArrayList pitches = new ArrayList();
pitches.add(“138”);
pitches.get(1);
{% endhighlight %}
generic이라는 방식은 리스트 자료형에서 사용할 자료형을 정확하게 명시하는것입니다.
{% highlight java %}
ArrayList pitches = new ArrayList<>();
{% endhighlight %}
Map
{key, value} set을 표현 가능한 자료형입니다. map 또한 사용법에 따라 HashMap, TreeMap등 다양한 자료형이 있습니다.
{% highlight java %}
import java.util.HashMap;
HashMap<String, String> map = new HashMap<>();
map.put(“people”, “사람”);
map.getOrDefault(“java”, “자바”) // 일반적인 get은 값이 없으면 null 반환
{% endhighlight %}
Set
집합을 표현 가능한 자료형입니다. set 또한 사용법에 따라 HashSet, TreeSet등 다양한 자료형이 있습니다.
{% highlight java %}
import java.util.HashSet;
HashSet set = new HashSet<>(); // wrapper class 사용
set.add(5)
{% endhighlight %}
Enum
상수 집합을 표현 가능한 자료형입니다.
{% highlight java %}
enum Grades {A, B, C}
Grades.A
{% endhighlight %}
Advance Tip
각각의 type들은 일반적으로 사용하는 원시 자료형에 대응하는 Wrapper class가 존재하며 multi-thread의 상황에서는 Wrapper class로 사용해야합니다.
custom types
type을 custom하여 생성할 수 있습니다. 이는 class를 만드는것과 유사합니다.
{% highlight java %}
class Human {}
Human minsu;
{% endhighlight %}
changing types
다음은 형변환및 포멧팅에 대한 방법입니다.
다음은 string형으로 나타낼때 사용하는 형변환입니다.
{% highlight java %}
String.format(“I like %s”, “apple”)
{% endhighlight %}
%s : string
%d : decimal
%c : char
%f : float
%o : 8진수
%x : 16진수
%% : %
%10d : 10자리의 decimal 부족할경우 앞자리에 공백
%-10d : 10자리의 decimal 부족할경우 뒷자리에 공백
%.4f : 소숫점 4자리의 float
다음은 다양한 형변환을 하는 방법입니다. 이는 wrapper class를 사용하여 변환을 하며, 대부분의 형에서 사용이 가능한 폼입니다.
{% highlight java %}
Integer.parseInt(num) // string num to int num
Integer.toString(num) // int num to string num
…(Double …)
{% endhighlight %}
JAVA
/
basic
· 2024-04-03
-
-
-
CV
Young Jin Go
Developer / MLOps
저는 다양한 개발 경험과 AI 기술을 겸비한 개발자로서, 소통과 협업의 중요성을 깊이 인식하고 있습니다.
가치 있는 것을 만드는 것에 대한 열정을 가지고 있으며, 빠르게 변화하는 환경 속에서 지속적인 학습을 통해 새로운 기술을 습득하고 적용하고자 합니다.
최근 AI 및 MLOps 관련 경험을 쌓으며, 보다 다양한 가치를 창출할 수 있는 개발자로 성장하고 있습니다.
경험을 기반으로 더욱 다양한 가치를 이루어 내고 싶습니다.
: 서울 광진구 화양동
: wtmo_dev@naver.com
: +82 10 2363 1941
: gitwtmo
: gitblog
Main Project
2024.02.14 ~ 2024.10.31
사용자 친화적인 챗봇 만들기 (메인 개발자)
개요
Slack Bot을 활용하여 학생들이 강의 중 편리하게 Q&A를 할 수 있도록 지원하는 시스템 개발
주요 업무
FastAPI 및 MongoDB의 적용을 위하여 개발에 사용될 기반 코어의 유기적 오류점 체크
기반이 될 코어 코드 구조 제작
업무 결과
학생들의 참여도 증가로 중도 이탈율 25% 감소, 기존대비 학생들의 결과물 완성도 향상
2023.12.26 ~ 2024.02.08
YOLOv8 성능 향상을 통한 도로 위 사고 방지 (메인 개발자)
개요
자율주행 차량의 도로 안전을 위한 로드마크 탐지 AI 개발
주요 업무
YOLOv8 모델 분석 및 성능 최적화
업무 결과
CBAM(Attention) 기법을 적용하여 탐지 성능 3% 향상
2023.11.07 ~ 2023.12.06
에너지 소비, 생산량 예측 AI 제작 (메인 개발자)
개요
이미지로 구성된 무거운 기상 데이터를 활용한 에너지 소모 및 생산량 예측 모델 개발
주요 업무
수치화된 이미지 데이터를 고차원의 정보로 활용할 방법 모색
LSTM과 CNN을 결합하여 효율적인 데이터 분석 방식 도입
업무 결과
1시간 이상 걸리던 분석 시간을 5분 이내로 대폭 감소시켜 박사님이 실질적 도입을 연구중
2022.10.01 ~ 2022.12.20
장루 환자 관리 프로세스 개발 (개발 지원)
개요
장루 환자를 위한 디바이스 모듈과 함께 개발된 모바일 앱의 기술 부족해소
주요 업무
기존 모바일 앱의 모듈이 개발한 기기의 블루투스 모듈과 호환문제 해결
기존 코드 리펙토링으로 해상도 호환, 로딩시간 감축
기존 개발자에게 부족한 기술 스택 교육
업무 결과
기술의 부족으로 개발이 멈춰있었으나 문제 해결으로 제품의 출시
2020.11.15 ~ 2021.09.15
환자 관리 프로세스 개발 (메인 개발자)
개요
치과 환자의 비대면 예약 및 관리 시스템 개발
주요 업무
React, Node.js, Socket.io, React Native를 활용한 실시간 예약 시스템 구축
업무 결과
코로나 시대에 맞춘 병원 관리 시스템으로 확장 가능성 확보
Problem Experience
slack bot 응답시간 초과 에러
문제 : LLM 기반 Slack Bot의 응답 시간이 5초 이상 소요됨
해결 : Python 멀티스레딩을 활용하여 속도 문제 해소
성과 : LLM 도입에도 1초 내 응답으로 정상 운영 가능
비고 : LLM에서 답변의 생성시간이 오래 걸리기 때문에 해당 작업을 따로 작업을 시키면 응답에 문제가 없음
대용량 크롤링의 효율 증대
문제 : Selenium 기반 크롤링의 병렬 처리 부재로 속도 저하
해결 : Scrapy 프레임워크를 도입하여 병렬 처리 구현
성과 : 크롤링 속도를 기존 대비 40배 향상
비고 : 획기적인 시간 단축으로 효율 상승. 실시간 동작을 고려하면 시간을 들여 세부적인 리펙토링이 더 효과적
2중 병렬처리의 시간성 문제 유발
문제 : Scrapy와 FastAPI의 병렬 실행 충돌
해결 : Scrapy를 subprocess에서 실행하여 동기적 처리
성과 : 두 프레임워크를 효율적으로 결합하여 성능 최적화
비고 : 비동기적인 코드를 같이 활용하는것은 시스템적으로 문제가 발생가능, 시스템의 동작 방식으로 해결해볼 수 있음
History
2024.10.01 –
팀 GLEADA
유니티를 활용한 게임 개발
2024.02.14 – 2024.10.31
Coding Is Coffee
Slack Bot 서버 개발
FastAPI, Python 교육
코드 검토 및 사례들을 활용한 코드 규정 구축
원활한 소통을 위한 칸반보드 구축
2023.07.17 – 2024.02.08
패스트 캠퍼스 AI 부트캠프
AI 프로젝트 개발
2022.10.12 – 2022.12.20
(주) 다람지
크로스플랫폼 모바일 앱 개발
백엔드 개발
2021.09.16 – 2023.02.14
팀 버펙트
정부 부처 홈페이지 유지보수
크로스플랫폼 모바일 앱 유지보수
CRM 리팩토링 및 유지보수
2020.11.15 – 2021.09.15
원업크리에이티브
비대면 병원 예약 시스템 개발
모바일 앱 생성 플랫폼 리팩토링 및 수정
워드프레스 및 그누보드 기반 홈페이지 유지보수
Education
울산대학교
전기전자 공학 전공 (학점: 3.47 / 4.5)
학부 연구생으로 논문 분석 및 연구 경험
다양한 경험을 통해 소통과 협업의 중요성 인지
Why Me?
프론트엔드 & 백엔드 풀스택 개발 경험
웹 퍼포먼스 최적화 & 실시간 데이터 처리 경험
크로스 플랫폼 개발 경험
원활한 소통과 협업을 통한 팀워크 중시
AI & MLOps 지식 기반으로 차별화된 기술력 보유
다양한 언어 경험으로 빠른 적응
Skills
FrontEnd
BackEnd
AI
ETC
None
· 2024-04-01
-
-
Django advance
Advance
HttpRequest
HttpRequest.headers # request의 headers 객체
HttpRequest.body # request의 body 객체
HttpRequest.COOKIES # 모든 쿠키를 담고 있는 딕셔너리 객체
HttpRequest.method # reqeust의 메소드 타입
HttpRequest.FILES # 로 보낸 UploadFile!
HttpRequest.META # HTTP 헤더가 포함하는 모든 접근 가능한 정보를 담고 있는 dict, 메타 정보는 (당연히) web-server에 영향을 받는다.
HttpRequest.GET # GET 파라미터를 담고 있는 QueryDict instance
HTTpRequest.POST # POST 파라미터를 담고 있는 QueryDict instance
queryDict instance
Query Expression
F function
python에서 핸들링 하는것이 아닌 Query로 만들어서 database에서 핸들링을 할 수 있는 방법입니다.
{% highlight python %}
User.objects.all().update(user_id=F(‘user_id’) + 1) # Base
company = Company.objects.annotate(chairs_needed=F(‘num_employees’) - F(‘num_chairs’)) # annotate same field
from django.db.models import DateTimeField, ExpressionWrapper, F
Ticket.objects.annotate(
expires=ExpressionWrapper(
F(‘active_at’) + F(‘duration’),
output_field=DateTimeField()
)
) # annotate different field
{% endhighlight %}
Docs
Func function
Func 방식은 Django에서 구현되지 않은 query의 구문을 사용하고자 할때 활용 가능합니다.
{% highlight python %}
class UNNEST(Func):
function = ‘UNNEST’
temp = Test.objects.annotate(user=UNNEST(‘user’))
{% endhighlight %}
Func
Q function
Q 방식은 Django에서 구현되어 있는 구현체로 조건들을 활용할때 사용하기 좋습니다.
{% highlight python %}
Product.objects.filter(Q(category=’A’) & Q(sub_category=’AB’))
{% endhighlight %}
Value function
Value는 기본적인 형태로 단순한 값을 의미합니다.
{% highlight python %}
User.objects.filter(“user”, Value(“_”), “id”)
{% endhighlight %}
annotate function
annotate는 별칭을 주는것과 같으며 nested와 같은 구조에서 명칭이 복잡할때 사용 가능합니다.
{% highlight python %}
logs = OrderLog.objects.annotate(
name=F(“product__name”),
price=F(“product__price”)
).values(
‘created’, ‘name’, ‘price’
)
{% endhighlight %}
subquery function
subquery는 query를 사용하여 query를 만드는 복잡한 형태의 query를 구성할때 사용합니다.
{% highlight python %}
from django.db.models import OuterRef, Subquery
newest = Comment.objects.filter(post=OuterRef(‘pk’)).order_by(‘-created_at’)
Post.objects.annotate(newest_commenter_email=Subquery(newest.values(‘email’)[:1]))
{% endhighlight %}
Transaction
database에서 일관적으로 한번에 작업이 되어야하는 단위를 transaction 이라합니다. 이를 통하여 안정된 서비스를 구현할 수 있으나 과도한 transaction은 오히려 서비스를 느리게 만들 수 있습니다.
{% highlight python %}
from django.db import transaction
@transaction.atomic()
def update_user(user_id: int, updated_company_name: str):
Profile.objects.filter(user__id=user_id).update(company_name=updated_company_name)
User.objects.filter(id=user_id).update(company_name=updated_company_name)
{% endhighlight %}
commit()
transaction을 종료하며 저장합니다.
rollback()
transaction을 종료하며 처음으로 돌아갑니다.
on_commit()
transaction commit 종료 이후에 동작이 되야할 경우 사용
savepoint()
transaction 도중에 savepoint를 지정하여 commit 또는 rollback같은 작업을 할 수 있습니다.
Signal
signal은 main logic과 별개로 실행해야하는 작업이 있을때 사용할 수 있습니다. 하지만 비동기적으로 작동되는 로직이 아니라서 celery와 같은것을 활용하는것을 추천합니다.
{% highlight python %}
우선 signals.py 를 특정 앱(여기선 user) 안에 만든다.
from django.db.models.signals import post_save
from django.contrib.auth.models import User
def create_profile(sender, instance, created, **kwargs):
if created == True:
user = instance
profile = Profile.objects.create(
owner = user,
user_name = user.username,
email = user.email,
name = user.first_name,
)
post_save.connect(create_profile, sender=User)
아래에서 더 자세히 보겠지만, connect를 쓰기 싫으면, 아래 app config를 진행하면 된다.
signal의 코드 분리를 위해 app config에서, app이 load 될 때 signal을 import하게 한다.
(user) apps.py
class UserConfig(AppConfig):
name = ‘user’
def ready(self) -> None:
# DB signal
import app.user.signals
return super().ready() {% endhighlight %}
-
Django view
What is View
How to use View
view를 사용하는 방식은 Fuction, Class 두가지 방식이 있습니다. 원래의 Django는 Fuction으로 구성되어 있었으나 OOP의 장점을 이용하는 Class 형식이 추후에 추가 되었습니다.
FBV
다음은 Fuction을 사용한 View의 기본 예제입니다.
{% highlight python %}
@api_view([‘GET’, ‘POST’])
def index(request):
if request.method == ‘POST’:
return HttpResponse(“Post method”)
else:
return HttpResponse(“Get method”)
{% endhighlight %}
CBV
다음은 class를 사용한 View의 기본 예제입니다. 이러한 방식은 상속과 같이 확장성을 가지지만 모든 상황에서 최선은 아닙니다.
{% highlight python %}
from django.views import View
class ContactView(View):
def post(self, request):
return HttpResponse(“Post method”)
def get(self, request):
return HttpResponse(“Get method”)
{% endhighlight %}
{% highlight python %}
quickstart/views.py
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser # 그냥 json 파싱만 위해,,
@csrf_exempt
def snippet_list(request):
“””
List all code snippets, or create a new snippet.
“””
if request.method == ‘GET’:
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return JsonResponse(serializer.data, safe=False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = SnippetSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400) {% endhighlight %}
Prev(how to start)
Prev
-
Django serializer
What is serializer
Django의 serializer는 많은 역활을 담당합니다. 그중 대표적인 사용처는 json <-> dict 형태로의 치환을 주로 해주게 됩니다. 이러한 이유는 rest api에서 사용하는 형식과 python에서 사용하는 형식이 다르기 때문입니다.
normal serializer
일반적인 seriallizer는 serializers.Serializer의 상속을 받아 아래와 같이 작성하게 됩니다.
{% highlight python %}
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(required=False, allow_blank=True, max_length=10)
def create(self, validated_data):
return models.User.objects.create(**validated_data) {% endhighlight %}
위와 같은 방식은 model과 상관없이 serializer를 설정하고 싶을때 사용할 수 있으며, model을 활용하여 사용하는 방법도 있습니다.
model serializer
model seriallizer는 serializers.ModelSerializer의 상속을 받아 아래와 같이 작성하게 됩니다. 아래의 방식은 model이 선언되어 있을때 사용하기 용이하며 코드를 간편하게 해줍니다.
{% highlight python %}
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = [‘id’, ‘name’]
{% endhighlight %}
method field
method field는 다른 field를 활용하여 재가공하여 사용하는 방식입니다. 대표적으로 id값이 있고 id의 길이를 확인하는 방법입니다.
{% highlight python %}
class UserSerializer(serializers.ModelSerializer):
is_long = serializers.SerializerMethodField()
class Meta:
model = models.User
fields = ['id', 'name']
def get_is_long(self, instance: CheckedCrn):
if len(instance.id) > 2:
return "long"
else:
return "short" {% endhighlight %}
dict -> json -> dict
때에 따라서는 데이터의 형태가 계속 변경이 되어야 할 수 있습니다. 그에따라 형변환을 하는 법을 나타냅니다.
{% highlight python %}
import io
from rest_framework.renderers import JSONRenderer
content = JSONRenderer().render(serializer.data) # json
stream = io.BytesIO(content)
data = JSONParser().parse(stream)
serializer = UserSerializer(data=data)
serializer.is_valid()
serializer.validated_data # check data
serializer.save()
serializer.data # dict
{% endhighlight %}
nested serializer
N in (1:N)
1:N 의 형식에서 N의 입장은 다음과 같이 바로 활용이 가능합니다.
seriallizer
{% highlight python %}
class GroupOnlySerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserWithGroupSerializer(serializers.ModelSerializer):
product = GroupOnlySerializer(read_only=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserWithGroupSerializer
{% endhighlight %}
1 in (1:N)
1:N 의 형식에서 1의 입장은 역참조를 해야 하기 때문에 조금은 복잡합니다.
Read case
seriallizer
{% highlight python %}
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserSerializer(serializers.ModelSerializer):
product = GroupSerializer(read_only=True, many=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserSerializer
{% endhighlight %}
Write case
write case에서는 원래 read만 가능하기 때문에 create를 override하여 새로이 구성해줘야 합니다.
seriallizer
{% highlight python %}
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserSerializer(serializers.ModelSerializer):
product = GroupSerializer(read_only=True, many=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserSerializer
def create(self, validated_data):
groups = validated_data.pop(‘group’)
user = User.objects.create(**validated_data)
for group in groups:
Group.objects.create(user=user, **group)
return user
{% endhighlight %}
Prev(how to start)
Prev
-
Django models
What is model
Django에서 model은 DB의 구조를 나타내어집니다.
How to use model
model의 사용법은 다음과 같습니다.
<app-name>.models.py 생성
{% highlight shell %}
from django.contrib.auth.models import User
from django.db import models
class UserDetail(models.Model):
user = models.ForeignKey(
User, verbose_name=”user 정보”, on_delete=models.DO_NOTHING
)
user_email = models.IntegerField(verbose_name=”user email”, null=False, primary_key=True)
class Meta:
db_table = "userdetail"
managed = True
verbose_name = "user 상세 정보"
verbose_name_plural = "user 상세 정보 목록" {% endhighlight %}
<app-name>.admin.py 추가(case 1)
{% highlight shell %}
from django.contrib import admin
from .models import Cart
class CartAdmin(admin.ModelAdmin): # admin 페이지에 표기할 column 지정
list_display = (‘', '')
admin.site.register(Cart, CartAdmin) # admin page에 등록
{% endhighlight %}
<app-name>.admin.py 추가(case 2)
{% highlight shell %}
from django.contrib import admin
from .models import Cart
@admin.register(Cart) # admin page에 등록
class CartAdmin(admin.ModelAdmin): # admin 페이지에 표기할 column 지정
list_display = (‘', '')
{% endhighlight %}
Field of model
model의 column들을 정의 하는 field는 다음과 같이 사용할 수 있습니다.
ID Field
Field 타입
설명
AutoField
1에서 부터 자동적으로 증가합니다.
BigAutoField
1 ~ 9223372036854775807까지 1씩 자동으로 증가하는 필드입니다.
UUIDField
UUID 전용 필드입니다.
String Field
Field 타입
설명
CharField
적은 문자열을 저장하는 필드입니다.
TextField
많은 문자열을 저장하는 필드입니다.
URLField
URL을 저장하는 필드입니다.
EmailField
E-mail을 저장하는 필드입니다.
String Field
Field 타입
설명
CharField
적은 문자열을 저장하는 필드입니다.
Data Field
Field 타입
설명
BinaryField
Binary 데이터를 저장하는 필드입니다.
DecimalField
Decimal 데이터를 저장하는 필드입니다.
IntegerField
Interger 데이터를 저장하는 필드입니다.
PositiveIntegerField
양수만 취급하는 Interger 데이터를 저장하는 필드입니다.
FloatField
Float 데이터를 저장하는 필드입니다.
BooleanField
참/거짓 데이터를 저장하는 필드입니다.
NullBooleanField
Null값이 가능한 참/거짓을 저장하는 필드입니다.
Time Field
Field 타입
설명
DateField
날짜 데이터를 저장하는 필드입니다.
TimeField
시간 데이터를 저장하는 필드입니다.
DateTimeField
날짜와 시간 데이터 모두 저장할 수 있는 필드입니다.
File Field
Field 타입
설명
ImageField
이미지 데이터를 저장하는 필드입니다.
FileField
파일 업로드 데이터를 저장하는 필드입니다.
FilePathField
파일 경로 데이터를 저장하는 필드입니다.
Relation Field
Field 타입
설명
OneToOneField
일대일 관계를 저장하는 필드입니다.
ForeignKey
일대다 관계를 저장하는 필드입니다.
ManyToManyField
다대다 관계를 저장하는 필드입니다.
더 많은 정보는 다음에 포함되어 있습니다.
relations
Field Option
Field의 옵션은 다음과 같으며 모든 Field가 모든 옵션을 사용할 수는 없습니다.
Field 옵션
설명
기본값
default
필드의 기본값을 설정합니다.
-
help_text
도움말 텍스트를 설정합니다.
-
null
Null 값 허용 유/무를 설정합니다.
False
blank
비어있는 값 허용 유/무를 설정합니다.
False
unique
고유 키 유/무를 설정합니다.
False
primary_key
기본 키 유/무를 설정합니다. (null=False, unique=True와 동일)
False
editable
필드 수정 유/무를 설정합니다.
False
max_length
필드의 최대 길이를 설정합니다.
-
auto_now
개체가 저장될 때마다 값을 설정합니다.
False
auto_now_add
개체가 처음 저장될 때 값을 설정합니다.
False
on_delete
개체가 제거될 때의 동작을 설정합니다.
-
db_column
데이터베이스의 컬럼의 이름을 설정합니다.
-
Meta Option
Meta 옵션은 다음과 같습니다.
Meta 옵션
설명
기본값
abstract
추상 클래스 유/무를 설정합니다.
False
db_table
모델에 사용할 데이터베이스 테이블의 이름을 설정합니다.
-
managed
데이터베이스의 생성, 수정, 삭제 등의 권한을 설정합니다.
True
ordering
객체를 가져올 때의 정렬 순서를 설정합니다.
-
verbose_name
사람이 읽기 쉬운 객체의 이름을 설정합니다. (단수형으로 작성)
-
verbose_name_plural
사람이 읽기 쉬운 객체의 이름을 설정합니다. (복수형으로 작성)
-
model manager
model은 기본적으로 objects를 manager로 가지게 되어있습니다. 하지만 아래와 같이 override할 수 있습니다.
{% highlight shell %}
class DeletedManager(models.Manager):
use_for_related_fields = True # default manager로 사용시 관계에서 모두 활용 가능
def deleted(self, **kwargs):
return self.filter(is_deleted=False, **kwargs)
def get_queryset(self):
return super().get_queryset().filter(is_deleted=False) {% endhighlight %}
{% highlight shell %}
class Post(models.Model):
objects = DeletedManager()
{% endhighlight %}
structure of model
구조는 위에 나열한 Field를 추가하여 주면 되며, Meta를 사용한 abstract기능을 True로 해주면 상속을 할 수 있는 상태가 됩니다. 아래는 default로 있는 User정보의 abstract를 활용한 예시입니다. Mixedin은 2개이상의 상속을 받을때 사용하며, abstract와 같으나 명칭만 다릅니다.
{% highlight python %}
class User(AbstractBaseUser, PermissionsMixin):
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['nickname', ]
class Meta:
ordering = ('-date_joined',)
def __str__(self): # object 호출시 지정할 명칭
return self.nickname
{% endhighlight %}
migration
migration은 DB와 코드간의 상태를 확인하는 작업입니다. 아래의 코드는 migration을 하는데 있어 주로 사용되는 코드입니다.
{% highlight shell %}
python manage.py showmigrations # migration의 상태확인
python manage.py makemigrations # migration 생성
python manage.py migrate # migration 적용
python manage.py –fake zero # 의 migration 초기화
python manage.py --fake-initial # fake migration 생성
{% endhighlight %}
-
-
Django additional module
What is Django debug toolbar
Django의 webpage들에서 debug 정보를 바로 확인하기 위한 middleware입니다.
How to setting
다음은 Django debug toolbar를 설치하는 방법입니다.
django-debug-toolbar 설치
{% highlight shell %}
pip install django-debug-toolbar
{% endhighlight %}
<proj-name>.settings.py에서 확인, 추가
{% highlight python %}
INSTALLED_APPS = [
# …
“django.contrib.staticfiles”,
# …
]
STATIC_URL = “static/”
{% endhighlight %}
<proj-name>.settings.py에서 확인, 추가
{% highlight python %}
TEMPLATES = [
{
“BACKEND”: “django.template.backends.django.DjangoTemplates”,
“APP_DIRS”: True,
# …
}
]
{% endhighlight %}
<proj-name>.settings.py에 추가
{% highlight python %}
INSTALLED_APPS = [
# …
“debug_toolbar”,
# …
]
{% endhighlight %}
<proj-name>.urls.py에 추가
{% highlight python %}
from django.conf import settings
if settings.DEBUG:
import mimetypes
mimetypes.add_type(“application/javascript”, “.js”, True)
import debug_toolbar
urlpatterns += [
path(r’^debug/’, include(debug_toolbar.urls)),
]
{% endhighlight %}
<proj-name>.settings.py에 추가
{% highlight python %}
MIDDLEWARE = [
# …
“debug_toolbar.middleware.DebugToolbarMiddleware”,
# …
]
{% endhighlight %}
<proj-name>.settings.py에 추가
{% highlight python %}
INTERNAL_IPS = [
# …
“127.0.0.1”,
# ...
]
{% endhighlight %}
위의 방식을 전부 완료하고 나서 Django proj를 실행하면 오른쪽에 debug toolbar가 보여집니다. 혹시나 보여지지 않으시다면 아래의 코드를 추가해주세요.
<proj-name>.urls.py에 추가
{% highlight python %}
import mimetypes
mimetypes.add_type(“application/javascript”, “.js”, True)
{% endhighlight %}
What is Django celery
Django에서 celery를 활용하여 worker와 broker를 사용하는 기능입니다.
How to setting
다음은 Django celery(W.redis)를 설치하는 방법입니다.
<proj-name>.celery.py 생성
{% highlight python %}
import os
from celery import Celery
Set the default Django settings module for the ‘celery’ program.
os.environ.setdefault(‘DJANGO_SETTINGS_MODULE’, ‘mysite.settings’)
app = Celery(‘projs’)
Using a string here means the worker doesn’t have to serialize
the configuration object to child processes.
- namespace=’CELERY’ means all celery-related configuration keys
should have a CELERY_ prefix.
app.config_from_object(‘django.conf:settings’, namespace=’CELERY’)
Load task modules from all registered Django apps.
app.autodiscover_tasks()
@app.task(bind=True, ignore_result=True)
def debug_task(self):
print(f’Request: {self.request!r}’)
{% endhighlight %}
<proj-name>.settings.py에 추가
{% highlight python %}
CELERY_BROKER_URL = ‘redis://127.0.0.1:6379/0’
CELERY_RESULT_BACKEND = ‘redis://127.0.0.1:6379/0’
CELERY_ACCEPT_CONTENT = [‘application/json’]
CELERY_RESULT_SERIALIZER = ‘json’
CELERY_TASK_SERIALIZER = ‘json’
CELERY_TIMEZONE = ‘Asia/Seoul’
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True
{% endhighlight %}
<proj-name>.__init__.py에 추가
{% highlight python %}
from .celery import app as celery_app
all = (‘celery_app’,)
{% endhighlight %}
shared_task 데코레이터를 사용한 함수 delay로 실행
{% highlight python %}
from celery import shared_task
{% endhighlight %}
위와 같이 코드를 완성하고 나서 다음의 코드로 celery를 구동시키면 사용이 가능합니다.
{% highlight shell %}
celery -A worker -l INFO
{% endhighlight %}
-
Django intro
What is Django
Django python으로 구현된 web framework입니다.
Getting start
다음은 아주 기본적인 django 의 실행방식입니다.
{% highlight shell %}
pip install Django # Django 설치
python -m django –version # Django 설치 확인
django-admin startproject # 프로젝트 생성
cd
python manage.py runserver # 프로젝트 실행
{% endhighlight %}
다음은 startproject로 생성되는 파일의 구조입니다.
<proj-name>/
manage.py
<proj-name>/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
Creating App
다음은 django에서 App을 만들고 연결하는 방법입니다.
{% highlight shell %}
python manage.py startapp # create App
{% endhighlight %}
다음은 startapp으로 생성되는 dir의 구조 입니다.
<app-name>/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
urls.py
views.py
<app-name>/views.py
{% highlight python %}
from django.http import HttpResponse
def index(request):
return HttpResponse(“Hello, world. You’re at the polls index.”)
{% endhighlight %}
<app-name>/urls.py
{% highlight python %}
from django.urls import path
from . import views
urlpatterns = [
path(“”, views.index, name=”index”),
]
{% endhighlight %}
<proj-name>/urls.py
{% highlight python %}
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path(“/", include(".urls")),
path("admin/", admin.site.urls),
]
{% endhighlight %}
Setting database
다음은 django에서 database를 세팅하는 방법입니다. Django는 기본으로 SQLite를 활용하지만 설정을 변경하여 수정이 가능합니다.
mysql
다음은 mysql 예시입니다.
필수 모듈 설치
{% highlight shell %}
pip install mysqlclient
{% endhighlight %}
<proj-name>.settings.py에 DB 옵션변경
{% highlight python %}
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.mysql’,
‘NAME’: ‘',
'USER': '',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '3306',
}
}
{% endhighlight %}
postgre
다음은 postgre 예시입니다.
필수 모듈 설치
{% highlight shell %}
pip install psycopg2
{% endhighlight %}
postgre setting
{% highlight shell %}
sudo su - postgres # postgre 실행
psql
CREATE DATABASE django_test; # postgre 유저 및 DB 생성
CREATE USER django_user WITH PASSWORD ‘django_pass’;
ALTER ROLE django_user SET client_encoding TO ‘utf8’;
ALTER ROLE django_user SET default_transaction_isolation TO ‘read committed’;
ALTER ROLE django_user SET timezone TO ‘UTC’;
GRANT ALL PRIVILEGES ON DATABASE django_test TO django_user;
\q
{% endhighlight %}
<proj-name>.settings.py에 DB 옵션변경
{% highlight python %}
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.mysql’,
‘NAME’: ‘',
'USER': '',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '3306',
}
}
{% endhighlight %}
Next(Web page)
Next
Next(Rest API)
Next
-
-
-
-
Llamaindex pipeline
pipeline(W. document, node)
documentd와 node를 하나의 pipeline으로 엮어서 사용하는 방식을 말합니다.
{% highlight python %}
import re
from llama_index.core import Document
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.ingestion import IngestionPipeline
from llama_index.core.schema import TransformComponent
class TextCleaner(TransformComponent):
def call(self, nodes, **kwargs):
for node in nodes:
node.text = re.sub(r”[^0-9A-Za-z ]”, “”, node.text)
return nodes
use in a pipeline
pipeline = IngestionPipeline(
transformations=[
SentenceSplitter(chunk_size=25, chunk_overlap=0),
TextCleaner(),
OpenAIEmbedding(),
],
)
nodes = pipeline.run(documents=[Document.example()])
{% endhighlight %}
pipeline(W. document, node, index)
{% highlight python %}
from llama_index.core import VectorStoreIndex
from llama_index.core.extractors import (
TitleExtractor,
QuestionsAnsweredExtractor,
)
from llama_index.core.ingestion import IngestionPipeline
from llama_index.core.node_parser import TokenTextSplitter
transformations = [
TokenTextSplitter(chunk_size=512, chunk_overlap=128),
TitleExtractor(nodes=5),
QuestionsAnsweredExtractor(questions=3),
]
global
from llama_index.core import Settings
Settings.transformations = [text_splitter, title_extractor, qa_extractor]
per-index
index = VectorStoreIndex.from_documents(
documents, transformations=transformations
)
{% endhighlight %}
AI
/
NLP
/
llama index
· 2024-03-14
-
Llamaindex embedding
what is embedding
embedding은 입력을 받은 document or node에 있어서 vector로 나타내는것입니다. 이를 통하여 코사인 유사도와 같이 문서들간의 유사성을 계산하여 문서를 효율적으로 사용할 수 있게 됩니다. llama는 기본적으로 코사인 유사도를 사용하고 있으며 아래의 방식으로 다양한 embedding을 사용해 볼 수 있습니다.
W. OpenAI
OpenAI에서 사용하는 embedding을 사용하려면 아래와 같이 사용하면 됩니다. 하지만 유료인점을 참고해야합니다.
{% highlight shell %}
pip install llama-index-embeddings-openai
{% endhighlight %}
{% highlight python %}
import os
OPENAI_API_TOKEN = “sk-“
os.environ[“OPENAI_API_KEY”] = OPENAI_API_TOKEN
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core import Settings
global
Settings.embed_model = OpenAIEmbedding(embed_batch_size=42) # default is 10
per-index
index = VectorStoreIndex.from_documents(documents, embed_model=embed_model)
{% endhighlight %}
W. hugging face
hugging face를 사용하여 enbedding을 하는 방식은 아래와 같습니다.
{% highlight shell %}
pip install llama-index-embeddings-huggingface
{% endhighlight %}
{% highlight python %}
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.core import Settings
Settings.embed_model = HuggingFaceEmbedding(
model_name=”BAAI/bge-small-en-v1.5”
)
{% endhighlight %}
W. hugging face(W. ONNX)
hugging face를 ONNX로 사용하는 법은 아래와 같습니다.
{% highlight shell %}
pip install transformers optimum[exporters]
pip install llama-index-embeddings-huggingface-optimum
{% endhighlight %}
{% highlight python %}
from llama_index.embeddings.huggingface_optimum import OptimumEmbedding
OptimumEmbedding.create_and_save_optimum_model(
“BAAI/bge-small-en-v1.5”, “./bge_onnx”
)
Settings.embed_model = OptimumEmbedding(folder_name=”./bge_onnx”)
{% endhighlight %}
W. langchain
langchain에서 지원하는 다양한 embedding을 사용할 수 있습니다.
langchain embeddings list
{% highlight shell %}
pip install llama-index-embeddings-langchain
{% endhighlight %}
{% highlight python %}
from langchain.embeddings.huggingface import HuggingFaceBgeEmbeddings
from llama_index.core import Settings
Settings.embed_model = HuggingFaceBgeEmbeddings(model_name=”BAAI/bge-base-en”)
{% endhighlight %}
W. custom embedding
위에서 사용할 수 있는 다양한 embedding 이외에 다른 embedding을 직접 만들어서 활용하려면 아래와 같이 해볼 수 있습니다.
{% highlight python %}
from typing import Any, List
from InstructorEmbedding import INSTRUCTOR
from llama_index.core.embeddings import BaseEmbedding
class InstructorEmbeddings(BaseEmbedding):
def init(
self,
instructor_model_name: str = “hkunlp/instructor-large”,
instruction: str = “Represent the Computer Science documentation or question:”,
kwargs: Any,
) -> None:
self._model = INSTRUCTOR(instructor_model_name)
self._instruction = instruction
super().__init__(kwargs)
def _get_query_embedding(self, query: str) -> List[float]:
embeddings = self._model.encode([[self._instruction, query]])
return embeddings[0]
def _get_text_embedding(self, text: str) -> List[float]:
embeddings = self._model.encode([[self._instruction, text]])
return embeddings[0]
def _get_text_embeddings(self, texts: List[str]) -> List[List[float]]:
embeddings = self._model.encode(
[[self._instruction, text] for text in texts]
)
return embeddings
async def _get_query_embedding(self, query: str) -> List[float]:
return self._get_query_embedding(query)
async def _get_text_embedding(self, text: str) -> List[float]:
return self._get_text_embedding(text) {% endhighlight %}
other embeddings
이외에도 다양한 embedding을 사용할 수 있으며 아래는 지원하는 embedding list 입니다.
embeddings list
AI
/
NLP
/
llama index
· 2024-03-13
-
Llamaindex index
what is index
index는 RAG와 같이 검색을 하는 구조에서 빠르게 검색하기 위한 구조입니다. 추가적인 활용처로는 채팅봇과 같이 QA로 사용할 수 있습니다.
vector store index
index 기법에서 가장 흔하게 사용이 되는 방법입니다. 이는 vector store를 활용하여 indexing을 하는 방법입니다.
아래와 같이 document을 바로 활용하는 방법과 node를 활용하는 방법 2가지로 이루어져 있습니다.
{% highlight python %}
from llama_index.core import VectorStoreIndex
index = VectorStoreIndex.from_documents(documents)
{% endhighlight %}
{% highlight python %}
from llama_index.core.schema import TextNode
node1 = TextNode(text=”", id_="")
node2 = TextNode(text="", id_="")
nodes = [node1, node2]
index = VectorStoreIndex(nodes)
{% endhighlight %}
default vectorstore이외에도 다양한 custom vectorstore를 사용할 수 있으며 아래는 간단한 예시를 나타냅니다.
{% highlight python %}
import pinecone
from llama_index.core import (
VectorStoreIndex,
SimpleDirectoryReader,
StorageContext,
)
from llama_index.vector_stores.pinecone import PineconeVectorStore
init pinecone
pinecone.init(api_key=”", environment="")
pinecone.create_index(
"quickstart", dimension=1536, metric="euclidean", pod_type="p1"
)
construct vector store and customize storage context
storage_context = StorageContext.from_defaults(
vector_store=PineconeVectorStore(pinecone.Index(“quickstart”))
)
Load documents and build index
documents = SimpleDirectoryReader(
“../../examples/data/paul_graham”
).load_data()
index = VectorStoreIndex.from_documents(
documents, storage_context=storage_context
)
{% endhighlight %}
other index guides
vector store가 가장 흔한 indexing 기법이지만 그 이외에도 아래와 같이 다양한 기법들이 있습니다.
other index guides
W. other embedding module
기본적으로 llama에서 제공하는 embedding으로 동작이 되지만 다른 embedding을 사용하고 싶으면 아래를 참고하여 변경이 가능합니다.
embedding module
pipeline
documents advance(1)와 nodes advance(1)까지 확인 이후 pipeline을 아래와 같이 도입 가능합니다.
document node index pipeline
AI
/
NLP
/
llama index
· 2024-03-12
-
Llamaindex nodes Advance(1)
create node by async
node를 만들때 다음과 같이 비동기로 만들 수 있습니다.
{% highlight python %}
from llama_index.core.node_parser import SentenceSplitter
node_parser = SentenceSplitter(chunk_size=512)
nodes = await node_parser.acall(documents)
{% endhighlight %}
file base node parser
노드를 생성하는데 있어서 document들이 다양한 형태의 데이터를 가질 수 있으며, 각 데이터에 최적화된 node parser를 사용하는것이 성능에 영향을 미칠 수 있습니다.
simple file
가장 기본적인 형태의 txt와 같은 파일에 적절한 파서입니다. 이는 flat document 와 같이 활용하기에 적합합니다.
{% highlight python %}
from llama_index.core.node_parser import SimpleFileNodeParser
parser = SimpleFileNodeParser()
md_nodes = parser.get_nodes_from_documents(md_docs)
{% endhighlight %}
html file
HTML 파일을 사용하는데 최적화된 파서입니다. tag들을 기본적으로 제공하며 custom tag를 세팅할 수 있습니다.
{% highlight python %}
from llama_index.core.node_parser import HTMLNodeParser
parser = HTMLNodeParser(tags=[“p”, “h1”]) # optional list of tags
nodes = parser.get_nodes_from_documents(html_docs)
{% endhighlight %}
json file
JSON 파일을 사용하는데 최적화된 파서입니다.
{% highlight python %}
from llama_index.core.node_parser import JSONNodeParser
parser = JSONNodeParser()
nodes = parser.get_nodes_from_documents(json_docs)
{% endhighlight %}
markdown file
markdown 파일을 사용하는데 최적화된 파서입니다.
{% highlight python %}
from llama_index.core.node_parser import MarkdownNodeParser
parser = MarkdownNodeParser()
nodes = parser.get_nodes_from_documents(markdown_docs)
{% endhighlight %}
text base node parser
노드를 생성하는데 있어서 text를 기반으로 생성이 필요한 경우 아래의 방식을 사용할 수 있습니다.
code splitter
code 파일을 사용하는데 최적화된 파서입니다. 지원되는 code 목록은 다음과 같습니다.
available code file
{% highlight python %}
from llama_index.core.node_parser import CodeSplitter
splitter = CodeSplitter(
language=”python”,
chunk_lines=40, # lines per chunk
chunk_lines_overlap=15, # lines overlap between chunks
max_chars=1500, # max chars per chunk
)
nodes = splitter.get_nodes_from_documents(documents)
{% endhighlight %}
langchain splitter
langchain에서 사용하는 textsplitter를 사용할 수 있는 파서입니다.
{% highlight python %}
from langchain.text_splitter import RecursiveCharacterTextSplitter
from llama_index.core.node_parser import LangchainNodeParser
parser = LangchainNodeParser(RecursiveCharacterTextSplitter())
nodes = parser.get_nodes_from_documents(documents)
{% endhighlight %}
지원하지 않는 langchain parser의 경우 아래와 같이 생성하여 사용할 수 있습니다.
create langchain parser
sentence splitter
문장과 문장의 끊어짐을 보장하며 분할을 할 수 있는 파서입니다.
{% highlight python %}
from llama_index.core.node_parser import SentenceSplitter
splitter = SentenceSplitter(
chunk_size=1024,
chunk_overlap=20,
)
nodes = splitter.get_nodes_from_documents(documents)
{% endhighlight %}
sentence window splitter
sentence splitter와 유사하지만 해당 노드 주변의 window_size만큼의 값을 가지게 됩니다. 이것은 다음 예시와 같이 활용이 가능합니다. MetadataReplacementNodePostProcessor
{% highlight python %}
import nltk
from llama_index.core.node_parser import SentenceWindowNodeParser
node_parser = SentenceWindowNodeParser.from_defaults(
# how many sentences on either side to capture
window_size=3,
# the metadata key that holds the window of surrounding sentences
window_metadata_key=”window”,
# the metadata key that holds the original sentence
original_text_metadata_key=”original_sentence”,
)
{% endhighlight %}
semantic splitter
고정된 크기의 chunk로 node가 구성이 되지만, embedding을 활용하여 유사성을 고려한 방식으로 효과적인 방식입니다.
{% highlight python %}
from llama_index.core.node_parser import SemanticSplitterNodeParser
from llama_index.embeddings.openai import OpenAIEmbedding
embed_model = OpenAIEmbedding()
splitter = SemanticSplitterNodeParser(
buffer_size=1, breakpoint_percentile_threshold=95, embed_model=embed_model
)
{% endhighlight %}
token splitter
token 크기에 기반하여 chunking을 하는 방식입니다.
{% highlight python %}
from llama_index.core.node_parser import TokenTextSplitter
splitter = TokenTextSplitter(
chunk_size=1024,
chunk_overlap=20,
separator=” “,
)
nodes = splitter.get_nodes_from_documents(documents)
{% endhighlight %}
relation base node parser
노드를 생성하는데 있어서 관계성을 기반으로 생성이 필요한 경우 아래의 방식을 사용할 수 있습니다.
hierarchical splitter
계층 구조로 chunking을 진행하여, 하위 레벨의 node는 상위 레벨의 node와 같이 활용 되어 좋은 결과를 도출할 수 있습니다. 다음의 예시와 같이 활용하면 적절합니다. AutoMergingRetriever
{% highlight python %}
from llama_index.core.node_parser import HierarchicalNodeParser
node_parser = HierarchicalNodeParser.from_defaults(
chunk_sizes=[2048, 512, 128]
)
{% endhighlight %}
pipeline
documents advance(1)까지 확인 이후 pipeline을 아래와 같이 도입 가능합니다.
document node pipeline
AI
/
NLP
/
llama index
· 2024-03-11
-
-
Llamaindex documents Advance(1)
documents loaders
flat document
documents는 다양한 형태를 가진 파일들을 불러오는데 사용이 될 수 있으나, 단순한 파일을 불러올 수도 있습니다. 단순한 파일을 불러올때는 아래와 같이 단순한 방식이 제공됩니다.
{% highlight python %}
from llama_index.readers.file import FlatReader
from pathlib import Path
md_docs = FlatReader().load_data(Path(“./test.md”))
{% endhighlight %}
other document loader
other document loader
metadata extraction usage pattern
다음과 같이 LLM을 사용하여 metadata를 추출해낼 수 있습니다.
{% highlight shell %}
pip install llama-index-extractors-entity
{% endhighlight %}
{% highlight python %}
import os
OPENAI_API_TOKEN = “sk-“
os.environ[“OPENAI_API_KEY”] = OPENAI_API_TOKEN
llm = OpenAI(temperature=0.1, model=”gpt-3.5-turbo”, max_tokens=512)
from llama_index.core.extractors import (
TitleExtractor,
QuestionsAnsweredExtractor,
SummaryExtractor,
KeywordExtractor,
BaseExtractor,
)
from llama_index.extractors.entity import EntityExtractor
class CustomExtractor(BaseExtractor):
def extract(self, nodes):
metadata_list = [
{
“custom”: (
node.metadata[“document_title”]
+ “\n”
+ node.metadata[“excerpt_keywords”]
)
}
for node in nodes
]
return metadata_list
title_extractor = TitleExtractor(nodes=5)
qa_extractor = QuestionsAnsweredExtractor(questions=3)
summary_extractor = SummaryExtractor(summaries=[“prev”, “self”,”next”])
keyword_extractor = KeywordExtractor(keywords=10, llm=llm),
custom_extractor = CustomExtractor()
entity_extractor = EntityExtractor(
prediction_threshold=0.5,
label_entities=False, # include the entity label in the metadata (can be erroneous)
device=”cpu”, # set to “cuda” if you have a GPU
)
{% endhighlight %}
pipeline
nodes advance(1)까지 확인 이후 pipeline을 아래와 같이 도입 가능합니다.
document node pipeline
AI
/
NLP
/
llama index
· 2024-03-07
-
Llamaindex documents
what is documents
documents는 다양한 NLP process에서 사용할 문서를 불러오는 방식을 말합니다.
How to use documents tutorial
documents를 사용하는데 있어서 가장 기초적인 예시는 아래와 같습니다.
{% highlight python %}
from llama_index.core import Document, VectorStoreIndex
document = Document.example()
build index
index = VectorStoreIndex.from_documents(documents)
{% endhighlight %}
read documents
documents를 사용하는방법은 다양하게 존재합니다. 다음은 documents를 만드는 두가지 방법을 나타냅니다.
Directory Reader
다음의 방식은 directory에 있는 문서들을 읽는 방식입니다. 해당방식은 지정한 폴더에 있는 문서는 읽을 수 있으나 하위 폴더에 있는 문서를 읽을 수는 없습니다.
{% highlight python %}
from llama_index.core import SimpleDirectoryReader
documents = SimpleDirectoryReader(“./data”).load_data()
{% endhighlight %}
custom setting
다음의 방식은 사용자가 직접 지정한 문서들을 입력하는 방식입니다. 이는 text를 하나씩 지정해야하는 방식입니다.
{% highlight python %}
from llama_index.core import Document
text_list = [text1, text2, …]
documents = [Document(text=t) for t in text_list]
{% endhighlight %}
documents metadata
문서들은 다양한 metadata를 가지게 됩니다. 해당하는 metadata는 NLP process에서 중요한 역활을 하게 되며 해당하는 값들을 상세히 지정하는것은 중요합니다.
add metadata(pre read)
document constructor를 만들기 이전에 metadata를 지정하는 방식은 다음과 같습니다.
W. dir reader
다음과 같이 dir reader를 사용하면서 metadata들을 지정 할 수 있습니다.
{% highlight python %}
from llama_index.core import SimpleDirectoryReader
filename_fn = lambda filename: {“file_name”: filename}
automatically sets the metadata of each document according to filename_fn
documents = SimpleDirectoryReader(
“./data”,
file_metadata=filename_fn,
filename_as_id=True,
).load_data()
{% endhighlight %}
W. custom reader
다음과 같이 custom reader를 사용하면서 metadata들을 지정 할 수 있습니다.
{% highlight python %}
document = Document(
text=”text”,
metadata={
“filename”: “",
"category": "",
"doc_id": ""},
)
{% endhighlight %}
add metadata(after read)
document constructor를 만든 이후에 잘못된 metadata를 변경하는 방식은 다음과 같습니다.
{% highlight python %}
document.metadata = {“filename”: “"}
document.doc_id = "My new document id!"
{% endhighlight %}
advance metadata setting
다양한 metadata는 NLP process에 다양한 강점을 가질 수 있지만, 오히려 과한 정보로 혼란을 줄 수 있습니다. 이럴 경우 필요없는 정보를 배제할 수 있습니다.
다음은 LLM이 metadata를 활용하는지 설정하는것입니다.
{% highlight python %}
document.excluded_llm_metadata_keys = [“file_name”]
{% endhighlight %}
다음은 embedding 과정에서 metadata를 활용하는지 설정하는것입니다.
{% highlight python %}
document.excluded_embed_metadata_keys = [“file_name”]
{% endhighlight %}
다음은 위에서 설정한 metadata 배제를 한 이외의 값이 어떻게 보여지는지 확인하는 방법입니다.
{% highlight python %}
from llama_index.core.schema import MetadataMode
print(document.get_content(metadata_mode=MetadataMode.LLM))
print(document.get_content(metadata_mode=MetadataMode.EMBED))
{% endhighlight %}
이외에도 metadata의 format을 설정 가능합니다. 다음 예시에서는 format을 사용한 전체적인 사용법을 나타냅니다.
advance metadata setting example
{% highlight python %}
from llama_index.core import Document
from llama_index.core.schema import MetadataMode
document = Document(
text=”This is a super-customized document”,
metadata={
“file_name”: “super_secret_document.txt”,
“category”: “finance”,
“author”: “LlamaIndex”,
},
excluded_llm_metadata_keys=[“file_name”],
metadata_seperator=”::”,
metadata_template=”{key}=>{value}”,
text_template=”Metadata: {metadata_str}\n—–\nContent: {content}”,
)
print(
“The LLM sees this: \n”,
document.get_content(metadata_mode=MetadataMode.LLM),
)
print(
“The Embedding model sees this: \n”,
document.get_content(metadata_mode=MetadataMode.EMBED),
)
{% endhighlight %}
Advance
documents advance(1)
AI
/
NLP
/
llama index
· 2024-03-06
-
Llamaindex intro
How to start
라마 인덱스를 활용하는 방법은 3가지가 있습니다. 첫번째는 initial setting, 두번째는 custom setting, 세번째는 source에서 직접 설치하는 방법입니다.
init install
기초적인 설치방법으로 OpenAI와 같이 대표적인 LLM을 활용하는데 있어서 적절합니다.
{% highlight shell %}
pip install llama-index
{% endhighlight %}
custom install
개별적 모델을 활용하기 위한 설치방법으로 OpenAI와 같이 대표적인 LLM 이외에도 다양한 모델을 Ollama 또는 huggingface등에서 가져와서 활용이 가능합니다.
{% highlight shell %}
pip install llama-index-core llama-index-readers-file llama-index-llms-ollama llama-index-embeddings-huggingface
{% endhighlight %}
source install
위 두가지 설치가 작동이 되지 않거나, source에서 직접 원하는것들만 설치를 하고 싶을때 사용할 수 있습니다.
{% highlight shell %}
git clone https://github.com/jerryjliu/llama_index.git
pip install -e llama-index-integrations/llms/llama-index-llms-ollama
{% endhighlight %}
simple start example
아래의 예시는 RAG를 활용한 예시입니다. ./data/paul_graham/ 폴더를 생성하여 RAG에 사용할 txt 데이터를 넣으면 됩니다. 또는 아래의 코드를 통하여 공식적인 예시 데이터를 사용할 수 있습니다.
{% highlight shell %}
mkdir -p ‘data/paul_graham/’
wget ‘https://raw.githubusercontent.com/run-llama/llama_index/main/docs/docs/examples/data/paul_graham/paul_graham_essay.txt’ -O ‘data/paul_graham/paul_graham_essay.txt’
{% endhighlight %}
W. OpenAI
OpenAI를 사용하여 활용을 하려면 우선 아래와 같이 환경설정이 필요합니다.
{% highlight shell %}
export OPENAI_API_KEY=XXXXX # linux
set OPENAI_API_KEY=XXXXX # window
{% endhighlight %}
이후 아래의 코드로 간단하게 활용이 가능합니다.
{% highlight python %}
import os
from llama_index.core import (
VectorStoreIndex,
SimpleDirectoryReader,
StorageContext,
load_index_from_storage,
)
check if local storage already exists
PERSIST_DIR = “./storage”
if not os.path.exists(PERSIST_DIR):
# load the documents and create the index
documents = SimpleDirectoryReader(“./data/paul_graham/”).load_data()
index = VectorStoreIndex.from_documents(documents)
# store it for later
index.storage_context.persist(persist_dir=PERSIST_DIR)
else:
# load the existing index
storage_context = StorageContext.from_defaults(persist_dir=PERSIST_DIR)
index = load_index_from_storage(storage_context)
Either way we can now query the index
query_engine = index.as_query_engine()
response = query_engine.query(“{Question}”)
print(response)
{% endhighlight %}
W. Custom model(ollama)
ollama를 사용하기 위하여 기본 설치 및 사용법을 알아야합니다. 사용법은 아래를 참고하면 됩니다.
how to use ollama
ollama 사용법 숙지 이후 사용할 모델을 다운 받고 아래의 코드로 진행이 가능합니다.
{% highlight python %}
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.core.embeddings import resolve_embed_model
from llama_index.llms.ollama import Ollama
documents = SimpleDirectoryReader(“./data/paul_graham/”).load_data()
bge embedding model
Settings.embed_model = resolve_embed_model(“local:BAAI/bge-small-en-v1.5”)
ollama
Settings.llm = Ollama(model=, request_timeout=30.0)
index = VectorStoreIndex.from_documents(
documents,
)
query_engine = index.as_query_engine()
response = query_engine.query(“{Question}”)
print(response)
{% endhighlight %}
W. Custom model(hugging face)
hugging face를 사용하기 위하여 기본 설치 및 사용법을 알아야합니다. 사용법은 아래를 참고하면 됩니다.
how to use hugging face
hugging face 사용법 숙지 이후 추가적으로 아래의 필요 모듈을 다운받아야 합니다.
{% highlight shell %}
pip install llama-index-llms-huggingface
pip install llama-index
{% endhighlight %}
이후 아래의 코드로 실행해 볼 수 있습니다.
{% highlight python %}
setup prompts - specific to StableLM
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings, PromptTemplate
from llama_index.llms.huggingface import HuggingFaceLLM
import torch
load documents
documents = SimpleDirectoryReader(“./data/paul_graham/”).load_data()
This will wrap the default prompts that are internal to llama-index
taken from https://huggingface.co/Writer/camel-5b-hf
query_wrapper_prompt = PromptTemplate(
“Below is an instruction that describes a task. “
“Write a response that appropriately completes the request.\n\n”
“### Instruction:\n{query_str}\n\n### Response:”
)
llm = HuggingFaceLLM(
context_window=2048,
max_new_tokens=256,
generate_kwargs={“temperature”: 0.25, “do_sample”: False},
query_wrapper_prompt=query_wrapper_prompt,
tokenizer_name=”Writer/camel-5b-hf”,
model_name=”Writer/camel-5b-hf”,
device_map=”auto”,
tokenizer_kwargs={“max_length”: 2048},
# uncomment this if using CUDA to reduce memory usage
# model_kwargs={“torch_dtype”: torch.float16}
)
Settings.chunk_size = 512
Settings.llm = llm
index = VectorStoreIndex.from_documents(documents)
set Logging to DEBUG for more detailed outputs
query_engine = index.as_query_engine()
response = query_engine.query(“What did the author do growing up?”)
print(response)
{% endhighlight %}
streaming service
스트리밍 서비스로 작동을 하기 위하여 index.as_query_engine()에서 부터 아래와 같이 변경을 해주면 됩니다.
{% highlight python %}
query_engine = index.as_query_engine(streaming=True)
set Logging to DEBUG for more detailed outputs
response_stream = query_engine.query(“What did the author do growing up?”)
can be slower to start streaming since llama-index often involves many LLM calls
response_stream.print_response_stream()
can also get a normal response object
response = response_stream.get_response()
print(response)
{% endhighlight %}
AI
/
NLP
/
llama index
· 2024-03-05
-
-
-
-
-
-
-
-
-
FastAPI SQL
SQL
SQL은 다음과 같이 구조화 하여 사용할 수 있습니다.
sql_app/__init__.py: empty
sql_app/database.py
sql_app/models.py
sql_app/schemas.py
sql_app/crud.py
sql_app/main.py
sql_app/database.py
database 파일은 다음과 같이 구성됩니다.
{% highlight python %}
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = “sqlite:///./sql_app.db”
SQLALCHEMY_DATABASE_URL = “postgresql://user:password@postgresserver/db”
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={“check_same_thread”: False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
{% endhighlight %}
sql_app/models.py
models 파일은 다음과 같이 구성됩니다.
{% highlight python %}
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from .database import Base
class User(Base):
tablename = “users”
id = Column(Integer, primary_key=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
is_active = Column(Boolean, default=True)
items = relationship("Item", back_populates="owner")
class Item(Base):
tablename = “items”
id = Column(Integer, primary_key=True)
title = Column(String, index=True)
description = Column(String, index=True)
owner_id = Column(Integer, ForeignKey("users.id"))
owner = relationship("User", back_populates="items") {% endhighlight %}
sql_app/schemas.py
schemas 파일은 다음과 같이 구성됩니다.
{% highlight python %}
from typing import Union
from pydantic import BaseModel
class ItemBase(BaseModel):
title: str
description: Union[str, None] = None
class ItemCreate(ItemBase):
pass
class Item(ItemBase):
id: int
owner_id: int
class Config:
orm_mode = True
class UserBase(BaseModel):
email: str
class UserCreate(UserBase):
password: str
class User(UserBase):
id: int
is_active: bool
items: list[Item] = []
class Config:
orm_mode = True {% endhighlight %}
sql_app/crud.py
crud 파일은 다음과 같이 구성됩니다.
{% highlight python %}
from sqlalchemy.orm import Session
from . import models, schemas
def get_user(db: Session, user_id: int):
return db.query(models.User).filter(models.User.id == user_id).first()
def get_user_by_email(db: Session, email: str):
return db.query(models.User).filter(models.User.email == email).first()
def get_users(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.User).offset(skip).limit(limit).all()
def create_user(db: Session, user: schemas.UserCreate):
fake_hashed_password = user.password + “notreallyhashed”
db_user = models.User(email=user.email, hashed_password=fake_hashed_password)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
def get_items(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Item).offset(skip).limit(limit).all()
def create_user_item(db: Session, item: schemas.ItemCreate, user_id: int):
db_item = models.Item(**item.dict(), owner_id=user_id)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
{% endhighlight %}
sql_app/main.py
main 파일은 다음과 같이 구성됩니다.
{% highlight python %}
from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session
from . import crud, models, schemas
from .database import SessionLocal, engine
models.Base.metadata.create_all(bind=engine)
app = FastAPI()
Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.post(“/users/”, response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
db_user = crud.get_user_by_email(db, email=user.email)
if db_user:
raise HTTPException(status_code=400, detail=”Email already registered”)
return crud.create_user(db=db, user=user)
@app.get(“/users/”, response_model=list[schemas.User])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
users = crud.get_users(db, skip=skip, limit=limit)
return users
@app.get(“/users/{user_id}”, response_model=schemas.User)
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id)
if db_user is None:
raise HTTPException(status_code=404, detail=”User not found”)
return db_user
@app.post(“/users/{user_id}/items/”, response_model=schemas.Item)
def create_item_for_user(
user_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db)
):
return crud.create_user_item(db=db, item=item, user_id=user_id)
@app.get(“/items/”, response_model=list[schemas.Item])
def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
items = crud.get_items(db, skip=skip, limit=limit)
return items
{% endhighlight %}
W. middleware
다음은 미들웨어를 사용한 예시를 제시합니다.
{% highlight python %}
@app.middleware(“http”)
async def db_session_middleware(request: Request, call_next):
response = Response(“Internal server error”, status_code=500)
try:
request.state.db = SessionLocal()
response = await call_next(request)
finally:
request.state.db.close()
return response
Dependency
def get_db(request: Request):
return request.state.db
{% endhighlight %}
-
FastAPI types
Enum
Enum 클래스는 다음과 같이 사용할 수 있습니다.
{% highlight python %}
from enum import Enum
class ModelName(str, Enum):
alexnet = “alexnet”
resnet = “resnet”
lenet = “lenet”
{% endhighlight %}
값을 사용하는 방식은 다음과 같이 사용 가능합니다.
model.value
Model.<key>
{% highlight python %}
app = FastAPI()
@app.get(“/models/{model_name}”)
async def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
{% endhighlight %}
Optional
Optional type의 경우 None일 수 있는 데이터를 의미하며 다음과 같이 작성할 수 있습니다.
{% highlight python %}
from typing import Optional
app = FastAPI()
@app.get(“/items/{item_id}”)
async def read_item(item_id: Optional[int]):
return {“item_id”: item_id}
{% endhighlight %}
httpUrl
httpUrl type의 경우 url형식을 받을 수 있는 형식입니다.
{% highlight python %}
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
@app.put(“/items”)
async def update_item(image: Image):
results = {“image”: image}
return results
{% endhighlight %}
output type
output type의 경우 일반적인 방식으로 활용이 가능합니다.
response_model=None은 2종류 이상의 타입이 가능할경우 pydantic의 규제를 피할때 사용할 수 있습니다.
response_model_exclude_unset=True은 output을 넘겨줄때 pydantic의 default value는 무시하는 방법입니다.
response_model_exclude={""}은 output을 넘겨줄때 넘겨주지 않을 value를 지정하는 방법입니다.
{% highlight python %}
from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get(“/portal”, response_model=None, response_model_exclude_unset=True, response_model_exclude={“tax”})
async def get_portal(teleport: bool = False) -> Response | dict:
if teleport:
return RedirectResponse(url=”https://www.youtube.com/watch?v=dQw4w9WgXcQ”)
return {“message”: “Here’s your interdimensional portal.”}
{% endhighlight %}
and others
이외에도 다양한 data type이 존재하며 다음과 같습니다.
datetime.datetime
datetime.date
datetime.time
datetime.timedelta
frozenset
bytes
Decimal
schema examples
pydantic으로 형식을 만들때는 다음과 같이 예시문을 만들 수 있습니다. 예시문을 활용하면 docs에서 예시문을 확인할 수 있습니다.
{% highlight python %}
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
]
}
} {% endhighlight %}
pydantic이 아닐경우는 Body, Query, …에서 직접 예시문을 작성할 수도 있습니다.
{% highlight python %}
Body(
examples=[
{
“name”: “Foo”,
“description”: “A very nice Item”,
“price”: 35.4,
“tax”: 3.2,
}
],
),
{% endhighlight %}
-
FastAPI intro Num.3
Security
API를 만드는데 있어서 보안사항은 매우 중요합니다. 아래의 순서를 따라 보안을 설정할 수 있습니다.
{% highlight shell %}
pip install python-jose # jwt token module
pip install passlib[bcrypt] # password hashing module
{% endhighlight %}
만약 (trapped) error reading bcrypt version과 같은 문제가 발생하면 아래의 코드를 작동시켜야 합니다.
{% highlight shell %}
pip install bcrypt==4.0.1
{% endhighlight %}
아래의 방법은 보안을 설정하는 방법들을 제안합니다.
{% highlight python %}
from datetime import datetime, timedelta, timezone
from typing import Annotated, Union
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel
to get a string like this run:
openssl rand -hex 32
SECRET_KEY = “09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7”
ALGORITHM = “HS256”
ACCESS_TOKEN_EXPIRE_MINUTES = 30
fake_users_db = {
“johndoe”: {
“username”: “johndoe”,
“full_name”: “John Doe”,
“email”: “johndoe@example.com”,
“hashed_password”: “$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW”,
“disabled”: False,
}
}
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: Union[str, None] = None
class User(BaseModel):
username: str
email: Union[str, None] = None
full_name: Union[str, None] = None
disabled: Union[bool, None] = None
class UserInDB(User):
hashed_password: str
pwd_context = CryptContext(schemes=[“bcrypt”], deprecated=”auto”)
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=”token”)
app = FastAPI()
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password):
return pwd_context.hash(password)
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
return False
if not verify_password(password, user.hashed_password):
return False
return user
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.now(timezone.utc) + expires_delta
else:
expire = datetime.now(timezone.utc) + timedelta(minutes=15)
to_encode.update({“exp”: expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=”Could not validate credentials”,
headers={“WWW-Authenticate”: “Bearer”},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get(“sub”)
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except JWTError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
raise credentials_exception
return user
async def get_current_active_user(
current_user: Annotated[User, Depends(get_current_user)],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail=”Inactive user”)
return current_user
@app.post(“/token”)
async def login_for_access_token(
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=”Incorrect username or password”,
headers={“WWW-Authenticate”: “Bearer”},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={“sub”: user.username}, expires_delta=access_token_expires
)
return Token(access_token=access_token, token_type=”bearer”)
@app.get(“/users/me/”, response_model=User)
async def read_users_me(
current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
@app.get(“/users/me/items/”)
async def read_own_items(
current_user: Annotated[User, Depends(get_current_active_user)],
):
return [{“item_id”: “Foo”, “owner”: current_user.username}]
{% endhighlight %}
Middleware
미들웨어는 다양한 작동에 있어서 중간에 행동을 하는 행동입니다. 현재 fastapi는 http protocol이 진행되는 시점의 middleware만 사용이 가능합니다. 사용방법은 다음 두가지 방법을 활용할 수 있습니다.
{% highlight python %}
class CustomMiddleware(BaseHTTPMiddleware):
def __init__(self, app):
super().__init__(app)
async def dispatch(self, request, call_next):
response = await call_next(request)
return response
app.add_middleware(CustomMiddleware)
{% endhighlight %}
{% highlight python %}
@app.middleware(“http”)
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers[“X-Process-Time”] = str(process_time)
return response
{% endhighlight %}
advance middleware
CORS
CORS는 Cross-Origin-Resource-sharing의 약자로 API를 호출하는 사용자의 ip를 관리하는 방법입니다.
{% highlight python %}
from fastapi.middleware.cors import CORSMiddleware
origins = [
“http://localhost”,
“http://localhost:8080”,
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=[“”],
allow_headers=[“”],
)
{% endhighlight %}
Background Task
main logic이 진행되는 것과 별개로 Background Task를 동작시킬 수 있습니다. 이렇게 동작되면 main logic에 영향을 주지 않는 동작을 빠르게 실행 할 수 있습니다.
{% highlight python %}
from fastapi import BackgroundTasks, FastAPI
app = FastAPI()
def write_log(message: str):
with open(“log.txt”, mode=”a”) as log:
log.write(message)
@app.post(“/send-notification/{email}”)
async def send_notification(
email: str, background_tasks: BackgroundTasks
):
message = f”message to {email}\n”
background_tasks.add_task(write_log, message)
return {“message”: “Message sent”}
{% endhighlight %}
Info
fastapi는 기본적인 info를 지정 할 수 있습니다. 이는 docs를 통하여 보여지며 아래와 같이 작성이 가능합니다.
{% highlight python %}
app = FastAPI(
title=”ChimichangApp”,
description=description,
summary=”Deadpool’s favorite app. Nuff said.”,
version=”0.0.1”,
terms_of_service=”http://example.com/terms/”,
contact={
“name”: “Deadpoolio the Amazing”,
“url”: “http://x-force.example.com/contact/”,
“email”: “dp@x-force.example.com”,
},
license_info={
“name”: “Apache 2.0”,
“identifier”: “MIT”,
},
)
{% endhighlight %}
static files
fastapi로 static file을 사용할 수 있습니다. 이러한 기능을 통하여 간단한 소개글이나 홈페이지 같은것도 제작이 가능해집니다.
{% highlight python %}
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount(“/static”, StaticFiles(directory=”static”), name=”static”)
{% endhighlight %}
API Test
fastapi를 작성하고나면 정상적으로 작성이 되었는지 걱정이 될 수 있습니다. 이럴때 test를 해볼 수 있는 기능을 지원합니다. 아래와 같이 작성 후 pytest를 통하여 확인을 해볼 수 있습니다.
test_*.py
{% highlight python %}
from fastapi import FastAPI
from fastapi.testclient import TestClient
app = FastAPI()
@app.get(“/”)
async def read_main():
return {“msg”: “Hello World”}
client = TestClient(app)
def test_read_main():
response = client.get(“/”)
assert response.status_code == 200
assert response.json() == {“msg”: “Hello World”}
{% endhighlight %}
run uvicorn(W. code)
다음과 같이 코드상에서 uvicorn을 작동하면 코드를 관리하는데 더욱 장점을 가질 수 있습니다.
{% highlight python %}
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get(“/”)
def root():
return {“value”: “hello world”}
if name == “main”:
uvicorn.run(app, host=”0.0.0.0”, port=8000)
{% endhighlight %}
Prev
Prev
-
FastAPI intro Num.2
Error handling
API를 만드는데 있어서 Error 상황이 있을 수 있습니다. 이런경우 error 상태를 요청자에게 안내와 함께 시스템의 결과 관리를 해줘야 합니다.
HTTPException
가장 일반적인 exception으로 아래와 같이 사용 가능합니다. 일반적으로 headers를 작성할 필요가 없으나 Token을 만들거나 하는 상황이나 보안적인 문제가 있을때 사용하기에 좋습니다.
{% highlight python %}
from fastapi import FastAPI, HTTPException
app = FastAPI()
items = {“foo”: “The Foo Wrestlers”}
@app.get(“/items/{item_id}”)
async def read_item(item_id: str):
if item_id not in items:
raise HTTPException(
status_code=404,
detail=”Item not found”,
headers={“X-Error”: “There goes my error”},
)
return {“item”: items[item_id]}
{% endhighlight %}
Custom Exception
Exception은 다음과 같이 custom해서 사용 가능합니다.
{% highlight python %}
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
class UnicornException(Exception):
def init(self, name: str):
self.name = name
app = FastAPI()
@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
return JSONResponse(
status_code=418,
content={“message”: f”Oops! {exc.name} did something. There goes a rainbow…”},
)
@app.get(“/unicorns/{name}”)
async def read_unicorn(name: str):
if name == “yolo”:
raise UnicornException(name=name)
return {“unicorn_name”: name}
{% endhighlight %}
다음 보여드릴 방식은 기본 설정된 starlette, RequestValidation을 custom해서 추가 기능을 구현하려고 할때 활용 가능합니다.
{% highlight python %}
from fastapi import FastAPI
from fastapi.exception_handlers import (
http_exception_handler,
request_validation_exception_handler,
)
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
app = FastAPI()
@app.exception_handler(StarletteHTTPException)
async def custom_http_exception_handler(request, exc):
print(f”OMG! An HTTP error!: {repr(exc)}”)
return await http_exception_handler(request, exc)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
print(f”OMG! The client sent invalid data!: {exc}”)
return await request_validation_exception_handler(request, exc)
{% endhighlight %}
Routing
routing을 하는 방식은 크게 2가지를 볼 수 있습니다.
use tags
{% highlight python %}
from fastapi import FastAPI
app = FastAPI()
@app.get(“/items/”, tags=[“items”])
async def create_item():
return None
{% endhighlight %}
use router
{% highlight python %}
from fastapi import FastAPI, APIRouter
app = FastAPI()
router = APIRouter(prefix=’/slack’, tags=[“items”])
app.include_router(user.router)
@router.get(“/items/”)
async def create_item():
return None
{% endhighlight %}
JsonEncoder
pydantic으로 인하여 dict형이 아니거나 2개이상의 dict형을 융합하여 활용하고 싶을때 사용할 수 있는 방법입니다.
{% highlight python %}
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
class Item(BaseModel):
title: str
timestamp: datetime
description: str | None = None
@app.put(“/items/{id}”)
def update_item(id: str, item: Item):
jsonable_encoder(item)
{% endhighlight %}
Dependencies
Dependencies는 FastAPI가 동작하는데 있어서 종속성을 주입하는 것입니다. 이는 더욱 안정적으로 동작할 수 있게 해줍니다. pydantic으로 사용하는것을 권장하나 아래와 같이 사용할 수 도 있습니다.
Function Dependencies
다음과 같이 함수형으로도 만들 수 있습니다.
{% highlight python %}
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(
skip: int = 0, limit: int = 100
):
return {“skip”: skip, “limit”: limit}
@app.get(“/items/”)
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
{% endhighlight %}
Class Dependencies
다음과 같이 클래스형으로 만들 수 있습니다.
{% highlight python %}
from typing import Annotated, Union
from fastapi import Depends, FastAPI
app = FastAPI()
class CommonQueryParams:
def init(self, skip: int = 0, limit: int = 100):
self.skip = skip
self.limit = limit
@app.get(“/items/”)
async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
return commons
{% endhighlight %}
Path Operation Dependencies
다음과 같이 함수의 입력이 아니라 path operation dependency에 입력하여 값을 검증 할 수도 있습니다.
{% highlight python %}
from typing import Annotated
from fastapi import Depends, FastAPI, Header, HTTPException
app = FastAPI()
async def verify_token(x_token: Annotated[str, Header()]):
if x_token != “fake-super-secret-token”:
raise HTTPException(status_code=400, detail=”X-Token header invalid”)
@app.get(“/items/”, dependencies=[Depends(verify_token)])
async def read_items():
return None
{% endhighlight %}
Global Dependencies
전역 Dependency도 사용할 수 있습니다. 이는 token 검증과 같은 활동에 있어서 유용합니다.
{% highlight python %}
app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])
{% endhighlight %}
Dependencies using yield
Dependency를 사용하여 DB의 무결성도 확인이 가능합니다. 아래의 예시는 sqlalchemy를 사용하였으나 다음과 같이 구성하면 활용성을 향상시킬 수 있습니다.
{% highlight python %}
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine(
,
pool_pre_ping=True
)
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db():
db = Session()
try:
yield db
finally:
db.close()
def router(s: Annotated[Service, Depends(get_db)]):
s.action()
{% endhighlight %}
{% highlight python %}
class MySuperContextManager:
def init(self):
self.db = DBSession()
def __enter__(self):
return self.db
def __exit__(self, exc_type, exc_value, traceback):
self.db.close()
async def get_db():
with MySuperContextManager() as db:
yield db
{% endhighlight %}
아래의 로직을 이해한다면 fastapi를 자유롭게 사용하는데 문제가 없다고 볼 수 있습니다.
Prev
Prev
Next
Next
-
FastAPI intro Num.1
What is FastAPI
FastAPI는 python으로 구현된 web framework입니다. FastAPI는 빠르게 개발이 가능하고 python으로 구현된 web framework중 가장 빠르다고 이야기 되고 있습니다.
type check를 해주는 pydantic과 Asynchronous Server Gateway interface로 구현된 starlette가 구성되어 있습니다. 그에 따라 다음과 같은 장점을 가지게 됩니다.
type check
비동기적 작업 지원
fast to create docs
FastAPI는 docs를 자체적으로 지원을 해줘서 빠른 문서작업이 가능해집니다.
FastAPI는 Swagger UI를 기반으로한 API docs를 지원해줍니다. 해당 자료는 FastAPI를 구동하면 https://localhost:port/docs에서 확인을 할 수 있습니다.
FastAPI는 ReDoc을 기반으로한 API docs 또한 지원을 해줍니다. 해당 자료는 FastAPI 구동이후 https://localhost:port/redoc에서 확인을 할 수 있습니다.
How to start FastAPI
FastAPI를 사용하기 위하여 우선 두가지 모듈을 다운 받아야합니다.
{% highlight shell %}
pip install fastapi
pip install uvicorn
{% endhighlight %}
이후 실행을 위하여 아래의 코드 작성 및 실행이 필요합니다.
main.py
{% highlight python %}
from fastapi import FastAPI
app = FastAPI()
@app.get(“/”)
async def root():
return {“message”: “Hello World”}
{% endhighlight %}
you should run in cli
{% highlight shell %}
uvicorn main:app –reload
{% endhighlight %}
main:app은 main.py에 있는 app을 실행한다는 의미입니다.
Input Datas
API의 데이터 입출력을 위하여 다양한 방식의 input data가 존재합니다. 아래는 해당 값들을 순차적으로 설명드리겠습니다.
Path Parameters
경로 파라미터라고 불리는 것으로 아래의 코드에서 item_id를 의미합니다. FastAPI는 type에 있어서 매우 엄격합니다. 그래서 아래의 코드와 같이 type hint(or pydantic)가 없거나 일치 하지 않을 경우 작동하지 않습니다. 주소창에 입력하는 값으로보면 숫자를 입력해도 문자로 보일 수 있으나 type hint에 따라서 숫자로 인식됩니다.
{% highlight python %}
@app.get(“/items/{item_id}”)
async def read_item(item_id: int):
return {“item_id”: item_id}
{% endhighlight %}
위와 같은 주소체계를 사용할때 주의 할점은 "/items/item"이라고 만약 새로운 주소체계를 선언할 경우 path parameter로 구성된 주소체계보다 상단에 존재하여야합니다. 이는 중복된 입력으로 판단이 될 수 있기 때문입니다.
Path Parameter가 "/"와 같이 경로 데이터가 포함이 되어있을 경우 starlette에서 지원해주는 type check 기능으로 :path를 추가해 아래와 같이 활용 가능합니다.
{% highlight python %}
@app.get(“/items/{item_id:path}”)
async def read_item(item_id: str):
return {“item_id”: item_id}
{% endhighlight %}
Path Parameter는 아래와 같이 상세한 유효성 검사를 지원하며 사용법은 다음과 같습니다.
gt: 보다 크다.
ge: 크거나 같다.
lt: 보다 작다.
le: 작거나 같다.
{% highlight python %}
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get(“/items/{item_id}”)
async def read_items(
q: str, item_id: Annotated[int, Path(title=”The ID of the item to get”)]
):
results = {“item_id”: item_id}
if q:
results.update({“q”: q})
return results
{% endhighlight %}
Query Parameters
Path Parameter이외에 입력값을 작성하면 Query Parameter로 인식됩니다. url로 값을 직접 전송하려면 URL/?data=data와 같이 전송이 가능합니다.
Query Parameter의 경우 default값을 제공해주지 않거나 Ellipsis를 주면 필수 입력 조건으로 사용이됩니다.
Query Parameter는 다음과 같이 유효성 검사를 추가적으로 진행 할 수 있습니다. 이것이 의미하는 바는 q는 str인데 None일 수 있으며 최대 글자수가 50이 넘으면 안되는 기본값 None을 가진 parameter라고 볼 수 있습니다.
{% highlight python %}
from typing import Annotated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get(“/items/”)
async def read_items(q: Annotated[str | None, Query(max_length=50)] = None):
results = {“items”: [{“item_id”: “Foo”}, {“item_id”: “Bar”}]}
if q:
results.update({“q”: q})
return results
{% endhighlight %}
Query에는 다음과 같이 다양한 입력을 줄 수 있습니다.
alias: 입력 명칭을 변경
deprecated: 사용 가능 여부
include_in_schema: 문서에 표현 여부
{% highlight python %}
Query(
alias=”item-query”,
title=”Query string”,
description=”Query string for the items to search in the database that have a good match”,
min_length=3,
max_length=50,
pattern=”^fixedquery$”,
deprecated=True,
include_in_schema=False
),
{% endhighlight %}
Body
다중 입력값이 존재할경우 흔하게 사용되는 방식입니다. fastapi에서 지원하는 Request를 사용해도 가능하지만 pydantic을 이용하는것이 무결성에 있어서 안전합니다.
{% highlight python %}
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.post(“/items/”)
async def create_item(item: Item):
return item
{% endhighlight %}
Single Body
Body를 사용하는데 있어서 단일값일 경우 아래와 같이 사용이 가능합니다.
{% highlight python %}
from typing import Annotated
from fastapi import Body, FastAPI
app = FastAPI()
@app.put(“/items”)
async def update_item(
importance: Annotated[int, Body()]
):
return {“importance”: importance}
{% endhighlight %}
Body Field
body도 query와 같이 Field를 사용하여 추가적인 무결성 검사를 할 수 있습니다.
{% highlight python %}
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
price: float = Field(gt=0, description=”The price must be greater than zero”)
tax: float
@app.put(“/items”)
async def update_item(item: Annotated[Item, Body(embed=True)]):
results = {“item_id”: item_id, “item”: item}
return results
{% endhighlight %}
Cookie
Cookie 데이터가 있을경우 아래와 같이 사용할 수 있습니다.
{% highlight python %}
from typing import Annotated, Union
from fastapi import Cookie, FastAPI
app = FastAPI()
@app.get(“/items/”)
async def read_items(ads_id: Annotated[Union[str, None], Cookie()] = None):
return {“ads_id”: ads_id}
{% endhighlight %}
Header
Header 데이터를 사용할 수 있습니다. Header의 경우 "-"이 "_"으로 자동 치환이 되기때문에 원본을 사용하려면 옵션을 추가해줘야 합니다.
{% highlight python %}
from typing import Annotated, Union
from fastapi import FastAPI, Header
app = FastAPI()
@app.get(“/items/”)
async def read_items(user_agent: Annotated[Union[str, None], Header(convert_underscores=False)] = None):
return {“User-Agent”: user_agent}
{% endhighlight %}
Form
Form data의 경우 우선 pip install python-multipart를 필요로 합니다. Form data는 아래와 같이 활용이 가능합니다.
{% highlight python %}
from typing import Annotated
from fastapi import FastAPI, Form
app = FastAPI()
@app.post(“/login/”)
async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]):
return {“username”: username}
{% endhighlight %}
File
File data의 경우 우선 pip install python-multipart를 필요로 합니다. File data는 2가지 방식으로 활용 가능합니다.
bytes: 이미지의 원본을 binary값으로 가져옵니다.
UploadFile: 이미지의 관련 정보들을 가져옵니다.
filename
content_type
file
read
write
seek
close
{% highlight python %}
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post(“/files/”)
async def create_file(file: Annotated[bytes, File()]):
return {“file_size”: len(file)}
@app.post(“/uploadfile/”)
async def create_upload_file(file: Annotated[UploadFile, File()]):
return {“filename”: file.filename}
{% endhighlight %}
Next
Next
-
-
-
-
-
-
-
1. blog
블로그를 만든 기념으로 파이썬을 이용해서 블로그가 운영되는 형식에 맞춰서 파이썬 사용법을 연습해봄
main.py
{% highlight python %}
from module.Blog import Blog
from module.Post import Post
MAIN_TEXT = ‘’’
블로그 글 작성
블로그 글 리스트
종료
’’’
MAIN1_TEXT = [
“타이틀: “,
“내용: “
]
MAIN2_TEXT = ‘’’
—————–
블로그 보기
블로그 편집
뒤로 돌아가기
’’’
MAIN2_DETAIL_TEXT = ‘id를 입력해주세요: ‘
MAIN1_END_TEXT = ‘’’
작성 완료했습니다.
——————
‘’’
class Main:
def init(self, blog_data) -> None:
self.blog_data = blog_data
pass
def call(self):
while True:
try:
handler = Handler()
post = Post()
blog = Blog()
(menu_num, input_data) = handler.get_input(text = MAIN_TEXT)
input_data = int(input_data)
if menu_num == “main”:
if input_data == 1:
(menu_num, input_datas) = handler.get_input(text = MAIN1_TEXT)
self.blog_data = post.create(data= self.blog_data, title= input_datas[0], content= input_datas[1])
print(MAIN1_END_TEXT)
elif input_data == 2:
(menu_num, input_data) = handler.get_input(text = MAIN2_TEXT)
blog.view_all(data= self.blog_data, state=”title”)
input_data = int(input_data)
elif input_data == 3:
break
else:
print("다시 선택해주세요.")
if menu_num == "main2":
if input_data == 1:
(menu_num, input_data) = handler.get_input(text = MAIN2_DETAIL_TEXT)
elif input_data == 2:
pass
elif input_data == 3:
pass
else:
print("다시 선택해주세요.")
if menu_num == "main2_1":
blog.view_all(data= self.blog_data, state="full", id=int(input_data))
(menu_num, input_data) = handler.get_input(text = "")
except ValueError:
print("숫자를 입력해주세요.")
class BlogDataSetting:
def init(self) -> None:
self.max_id = self.__get_default_id()
self.posts = self.__get_posts()
pass
def __get_default_id(self):
return 0
def __get_posts(self):
return []
class Handler:
def get_input(self, text):
if (text == MAIN_TEXT):
print(text)
return (“main”, input())
elif (text == MAIN1_TEXT):
input_list = []
for txt in text:
input_list.append(input(txt))
return (“main1”, input_list)
elif (text == MAIN2_TEXT):
print(text)
return (“main2”, input())
elif (text == MAIN2_DETAIL_TEXT):
return (“main2_1”, input(text))
else:
return (“main”, input(“돌아가기”))
if name == “main”:
blog_data = BlogDataSetting()
main = Main(blog_data)
main()
{% endhighlight %}
module/Blog.py
{% highlight python %}
class Blog():
“””
전체 리스트 보기(id 기준), 태그 리스트 보기
“””
def init(self) -> None:
super().init()
pass
def view_all(self, data, state="title", id=False):
posts = data.posts
print("-------------")
for post in posts:
if id:
if id == post['id']:
print(f"id: {post['id']}")
print(f"타이틀: {post['title']}")
if state == "full":
post['view_count'] += 1
print(f"내용: {post['content']}")
print(f"view: {post['view_count']}")
print(f"like: {post['like']}")
print(f"\t")
else:
print(f"id: {post['id']}")
print(f"타이틀: {post['title']}")
if state == "full":
print(f"내용: {post['content']}")
print(f"view: {post['view_count']}")
print(f"like: {post['like']}")
print(f"\t")
print("-------------") {% endhighlight %}
module/Post.py
{% highlight python %}
class Post():
def __init__(self) -> None:
super().__init__()
pass
def create(self, data, title, content):
data.max_id += 1
data.posts.append({
"id": data.max_id,
"title": title,
"content": content,
"view_count": 0,
"like": 0
})
return data
def edit():
pass {% endhighlight %}
-
-
-
3. Evaluation metrics of deep learning
mean_absolute_error(regression)
mse라고 불리는 지표로 결과값과 예측값간의 차의 절대값 평균이다.
{% highlight python %}
from sklearn.metrics import mean_absolute_error
mean_absolute_error(Y_test, pred_value)
{% endhighlight %}
mean_squared_error(regression)
mse라고 불리는 지표로 가장 일반적으로 사용되는 값으로 결과값과 예측값간의 차의 제곱합의 절대값이다.
{% highlight python %}
from sklearn.metrics import mean_squared_error
mean_squared_error(Y_test, pred_value)
{% endhighlight %}
accuracy_score(classification)
결과와 예측간의 정확도를 나타내는 지표이다.
{% highlight python %}
from sklearn.metrics import accuracy_score
accuracy_score(Y_test, pred_value)
{% endhighlight %}
confusion_matrix(classification)
예측값과 결과값간의 값을 matrix로 나타낸값
{% highlight python %}
from sklearn.metrics import confusion_matrix
confusion_matrix(Y_test, pred_value)
{% endhighlight %}
classification_report(classification)
{% highlight python %}
from sklearn.metrics import classification_report
classification_report(Y_test, pred_value)
{% endhighlight %}
precision -> 예측1(positive, type1) 정확도
recall -> 실제1(Type2) 정확도
F-1 Score precision, recall의 유사성 높으면 유사함(기하 평균)
roc_auc_score(classification)
{% highlight python %}
from sklearn.metrics import roc_auc_score
roc_auc_score(Y_test, pred_value, multi_class)
{% endhighlight %}
roc x축을 실제값이 1일때 예측값의 1의 비율, y축을 실제값이 0일때 예측값의 1의 비율로 하여 나타내지는 그래프를 의미한다.
auc -> roc그래프에서 desity를 나타내고, 0.5~1의 값을 나타내며 높을수록 정확도가 높다
multi_class는 1대1 매칭은 ovo 1대 다 매칭은 ovr로 입력값을 받는다.
silhouette_score(clustering)
{% highlight python %}
from sklearn.metrics import silhouette_score
for i in range():
model = KMeans(n_cluster=i)
model.fit()
pred = model.predict()
[].append(silhouette_score(, pred))
{% endhighlight %}
값이 높을 수록 효과가 좋은 결과
AI
/
DL
/
basic
· 2023-11-01
-
-
-
-
4. Models of machine learning
supervised Learning
LinearRegression
선형적인 모델로 예측이 될때 사용
{% highlight python %}
from sklearn.linear_model import LinearRegression
{% endhighlight %}
LogisticRegression
0과1 처럼 나뉘어지는 형태 또는 0~1로 나뉘어지는 모델
{% highlight python %}
from sklearn.linear_model import LogisticRegression
{% endhighlight %}
DecisionTreeRegressor
tree 형태로 구분이 되며 feature들에 따라 결과를 다각형의 직선으로 표현하는 형태이다
분류된 값의 평균
{% highlight python %}
from sklearn.tree import DecisionTreeRegressor
from sklearn.tree import export_graphviz
from graphviz import Source
model = DecisionTreeRegressor(random_state=100, min_samples_leaf=1, min_samples_split=5, max_depth=5)
export_graphviz(model, out_file=/.)
Source.from_file(/.)
{% endhighlight %}
random_state 시드값
max_depth 최대 깊이
min_samples_leaf 리프 원소의 최소갯수
min_samples_split root 원소의 최소갯수
export_graphviz tree를 그림으로 저장
Source.from_file tree를 저장된 그림 가시화
feature_importances_ 모든 decision tree가 가지는 특성
RandomForestClassifier
다수의 트리들을 랜덤하게 학습하는 방법으로 과적합을 방지하기 위해 탄생하였으나 비교적 느리다. feature들에 따라 결과를 구역으로 나뉘는 형태이다.
복원 추출하는것을 bootstrap이라하며 복원추출로 subset을만들어 모델을 만드는것을 bagging이라고 함.
subset을 만들기 때문에 특정 feature의 과적합을 조절할 수 있다.
트리들이 각각 독립적이다.
GINI index(default)
$1-\sum_{i=1}^n(p_i)^2$로 노드의 순도를 알 수있고 최하 0.5에서 최고 0까지 나타남
cross entropy
$-\sum_{i=1}^n(p_i)^2*\log_2(p_i)$로 노드의 순도를 알 수있고 최하 1에서 최고 0까지 나타남
{% highlight python %}
from sklearn.ensemble import RandomForestClassifier
{% endhighlight %}
XGBoost
boosting은 각트리가 이전 트리의 결과를 참조하는것.
gradient descent(경사하강법)
위의 기법들을 활용을 하며 level wise한 방법
LightGBM
boosting은 각트리가 이전 트리의 결과를 참조하는것.
gradient descent(경사하강법)
위의 기법들을 활용을 하며 leaf wise한 방법
{% highlight python %}
from lightgbm import LGBMClassifier
{% endhighlight %}
unsupervised Learning
KMeans
cluster형태의 문제에서 포인트를 지정 후 근처값을 찾고 중심이동을 반복해 최종값을 구하게된다.(거리 기반 측정법)
{% highlight python %}
from sklearn.cluster import KMeans
model = KMeans(n_clusters = )
model.fit(X)
model.inertia_
{% endhighlight %}
inertia_
얼마나 밀집해있는지 알 수 있음(n의 갯수가 높으면 낮아지는 문제도 있음)
survival analysis
KaplanMelerFitter(survival analysis)
구독시간과 이탈률만을 가지고 평가하는 기본형
{% highlight python %}
from lifelines import KaplanMelerFitter
model = KaplanMelerFitter()
model.fit(, )
model.survival_function_
model.event_table
{% endhighlight %}
survival_function_는 시간에 따른 이탈치
event_table
removed 이탈량
observed 데이터 내의 이탈량
censored 데이터 이후 이탈 예상량
entrance 유입량
at_risk 잔류량
CoxPH(survival analysis)
모든 데이터를 이용해서 평가하는 복합형으로 logistic regression에서 차용되었다.
{% highlight python %}
from lifelines import CoxPHFitter
model = CoxPHFitter()
model.fit(, , )
model.baseline_survival_
model.print_summary()
model.plot_partial_effects_on_outcome(covariates= , values= [0,1,...])
model.predict_survival_function()
{% endhighlight %}
baseline_survival_는 시간에 따른 이탈치
print_summary
coef의 값과 exp(coef)등등의 값을 알 수 있으며 exp(coef)이 1에서 차이나는 만큼이 이탈률의 변화량에 미치는 비율을 말한다.
plot_partial_effects_on_outcome
<column_name>이 value일때 미친 영향 그래프
predict_survival_function
추가적인 데이터의 예측값
AI
/
ML
/
basic
· 2023-10-26
-
3. Evaluation metrics of machine learning
mean_absolute_error(regression)
mse라고 불리는 지표로 결과값과 예측값간의 차의 절대값 평균이다.
{% highlight python %}
from sklearn.metrics import mean_absolute_error
mean_absolute_error(Y_test, pred_value)
{% endhighlight %}
mean_squared_error(regression)
mse라고 불리는 지표로 가장 일반적으로 사용되는 값으로 결과값과 예측값간의 차의 제곱합의 절대값이다.
{% highlight python %}
from sklearn.metrics import mean_squared_error
mean_squared_error(Y_test, pred_value)
{% endhighlight %}
accuracy_score(classification)
결과와 예측간의 정확도를 나타내는 지표이다.
{% highlight python %}
from sklearn.metrics import accuracy_score
accuracy_score(Y_test, pred_value)
{% endhighlight %}
confusion_matrix(classification)
예측값과 결과값간의 값을 matrix로 나타낸값
{% highlight python %}
from sklearn.metrics import confusion_matrix
confusion_matrix(Y_test, pred_value)
{% endhighlight %}
classification_report(classification)
{% highlight python %}
from sklearn.metrics import classification_report
classification_report(Y_test, pred_value)
{% endhighlight %}
precision -> 예측1(positive, type1) 정확도
recall -> 실제1(Type2) 정확도
F-1 Score precision, recall의 유사성 높으면 유사함(기하 평균)
roc_auc_score(classification)
{% highlight python %}
from sklearn.metrics import roc_auc_score
roc_auc_score(Y_test, pred_value, multi_class)
{% endhighlight %}
roc x축을 실제값이 0일때 예측값의 1의 비율(FPR), y축을 실제값이 1일때 예측값의 1의 비율(TPR)로 하여 나타내지는 그래프를 의미한다.
auc -> roc그래프에서 desity를 나타내고, 0.5~1의 값을 나타내며 높을수록 정확도가 높다
multi_class는 1대1 매칭은 ovo 1대 다 매칭은 ovr로 입력값을 받는다.
silhouette_score(clustering)
{% highlight python %}
from sklearn.metrics import silhouette_score
for i in range():
model = KMeans(n_cluster=i)
model.fit()
pred = model.predict()
[].append(silhouette_score(, pred))
{% endhighlight %}
값이 높을 수록 효과가 좋은 결과
AI
/
ML
/
basic
· 2023-10-25
-
2. EDA of machine learning
ordinal encoder
어떠한 컬럼값이 object형일 경우 학습을 시키기 힘들기 때문에 값들을 0, 1, … 으로 넘버링하는 방법(높고 낮음의 연관성이 있을때)
replace()
{% highlight python %}
data[] = data[].replace({"name": num})
{% endhighlight %}
OrdinalEncoder
{% highlight python %}
from sklearn.preprocessing import OrdinalEncoder
ohe = OrdinalEncoder()
train_ = ohe.fit_transform(train([])) # 분류된 데이터가 도출됨
{% endhighlight %}
factorize
{% highlight python %}
pd.factorize()
{% endhighlight %}
onehot encoder
어떠한 컬럼값이 object형일 경우 학습을 시키기 힘들기 때문에 값들을 0과 1로 이루어진 데이터로 변환하는 방법
train, test 카테고리 차이가 없을때 쉽게하는법
{% highlight python %}
pd.get_dummies(data=[], columns=[], drop_first=False)
{% endhighlight %}
data는 참조가 되는 데이터들을 나타낸다.
columns는 데이터중 onehotencoding을 하려는 컬럼값들을 나타낸다.
drop_first는 encoding하여 분할되는 컬럼들중 첫번째를 넣을지 뺄것인지 정하는것으로 선택적이다.
train, test 카테고리 차이가 있을때 진행하는법
{% highlight python %}
from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder(sparse=False)
train_ = ohe.fit_transform(train([])) # 분류된 데이터가 도출됨
ohe.categories_ # 카테고리 값이 도출됨
{% endhighlight %}
StandardScaler
평균이 0 분산이 1인 값으로 데이터를 표준화하는 작업으로 보통 정규분포의 경우에서 성능향상을 위해 사용이 된다.(outlier 영향 강함)
{% highlight python %}
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df)
{% endhighlight %}
min max scaler
데이터를 0~1의 값으로 변환을 하게 되며 정규분포가 아닐경우 사용하게 된다.
{% highlight python %}
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
df_scaled = scaler.fit_transform(df)
{% endhighlight %}
robust scaler
해당하는 값에서 중앙값을뺀값을 IQR로 나누어 만들어지며, ourlier 영향이 적게 스케일링이 가능하다.
{% highlight python %}
from sklearn.preprocessing import RobustScaler
{% endhighlight %}
train/test data split
데이터가 학습및 학습결과 확인을 위하여 데이터를 분할해주는 작업이다.
train_test_split
{% highlight python %}
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X ,y, test_size=0.2, random_state=54)
{% endhighlight %}
random_state는 일종의 시드값으로 변화가없으면 계속 같은 값이 나온다.
StratifiedShuffleSplit
특정 <data_>를 동일한 비율로 나누고 싶을때 사용
{% highlight python %}
split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=54)
for train_idx, test_idx in split.split(X, ):
X_train = X[train_idx]
X_test = X[test_idx]
y_train = y[train_idx]
y_test = y[test_idx] {% endhighlight %}
random_state는 일종의 시드값으로 변화가없으면 계속 같은 값이 나온다.
Kfold
StratifiedKfold
cross validation issue
train/test로 나누어서 진행함에 있어서 보면 매번 결과가 뒤죽박죽으로 나올 수 있다. 이러한 이유는 train, test에 해당하는값이 치우쳐진 값으로 가질 수 있기 때문이며 이를 위해 아래와 같이 여러갯수로 분할하여 시행하는것이 더욱 정확하다고 볼 수있다.
{% highlight python %}
from sklearn.model_selection import KFold
kf = KFold(n_splits=5, random_state=100)
for train_index, test_index in kf.split(range(len(data))):
{% endhighlight %}
AI
/
ML
/
basic
· 2023-10-24
-
1. Theory of machine learning
Linear Regression
종속변수와 독립변수간에 관계를 예측하는 모델로 선형적 모델을 가지고 종속변수와 독립변수의 관계를 도출하는 방법이다. 변수가 증가함에 따라 시간 복잡도가 많이 증가한다. 일반적으로 아래의 정규방정식을 통하여 계산이 가능하지만
\[\theta = (X^TX)^{-1}X^Ty\]
역행렬이 존재하지 않거나 하는 경우 유사 역행렬인
\[\theta = X^+y\]
를 이용하여 계산을 하며 이는 sklearn에서 기본으로 제공이 된다.(np.linalg.pinv()를 통하여 직접 계산도 가능)
Ridge Regression(규제형)
학습 모델의 가중치를 컨트롤하기 위한 모델로 규제항을 포함하여 훈련하고 성능평가에서 사라진다.
$MSE(\theta)$에 L2 norm(규제항)을 추가된 모형으로 아래와 같은 loss function을 가진다.
\[J(\theta) = MSE(\theta) + \alpha \tfrac{1}{2}\sum_{i=1}^n\theta_i^2\]
Lasso Regression(규제형)
학습 모델의 가중치를 컨트롤하기 위한 모델로 규제항을 포함하여 훈련하고 성능평가에서 사라진다.Ridge회기는 중요도가 낮은 변수를 규제하지만 Lasso는 0이 될수있다.
$MSE(\theta)$에 L1 norm(규제항)을 추가된 모형으로 아래와 같은 loss function을 가진다.
\[J(\theta) = MSE(\theta) + \alpha \sum_{i=1}^n|\theta_i|\]
Elastic Net Regression(규제형)
학습 모델의 가중치를 컨트롤하기 위한 모델로 규제항을 포함하여 훈련하고 성능평가에서 사라진다.Ridge, Lasso를 융합시킨 형태이다.
$MSE(\theta)$에 L2 norm(규제항)을 추가된 모형으로 아래와 같은 loss function을 가진다.(r=0에서 Ridge r=1에서 Lasso가 된다.)
\[J(\theta) = MSE(\theta) + r\alpha \sum_{i=1}^n|\theta_i| + \tfrac{1-r}{2}\sum_{i=1}^n\theta_i^2\]
Early Stopping Regression(규제형)
경사하강법과 같은 반복적 학습에서 과적합되기전에 멈추게 하는 방법
Gradient Descent
비용함수를 최소화하여 계산복잡도를 감소시킨 방법이다. 시간 및 정확도를 위하여 scaler를 통하여 특성을 유사하게 만들어야한다. $\eta$는 학습률을 의미한다.
\[cost \, function := MSE(\theta) = \tfrac{(\hat{y}-y)^2}{m}\]
\[\tfrac{\partial}{\partial\theta}MSE(\theta) = \tfrac{2X^T(X\theta-y)}{m}\]
\[\theta^{next step} = \theta - \eta\tfrac{\partial}{\partial\theta}MSE(\theta)\]
Batch Gradient Descent
전체 데이터셋의 에러를 통한 기울기로 한번만 모델의 파라미터를 업데이트하는 방법
장점
연산횟수가 적다.
전체 데이터셋을 활용하기 때문에 안정적으로 수렴한다.
단점
지역 최적화에 걸리기 쉽다.
스텝마다 학습량이 많아 시간이 오래걸린다.
Stomatic Gradient Descent
매 스탭마다 무작위 샘플을 구하여 미분을 취하는 방법
장점
알고리즘이 빠르다.
단점
최적의 값을 구하기 힘들다.
샘플 데이터를 활용하기 때문에 불안정적으로 수렴한다.
Mini-Batch Gradient Descent
임의의 작은 샘플 세트를 활용하여 기울기를 구하는 방법
장점
batch-size를 키우면 SGD보다 안정적이다.
단점
정해진 샘플의 사용으로 SGD보다 지역 최적화에 걸리기 쉽다.
PolynomialFeatures
다항 회기방법으로 변수들을 이용해 고차항을 만드는 방법
n이 변수의 갯수, d가 차원일때 아래와 같은 수의 변수가 생성이된다.
\[\tfrac{(n+d)!}{n!d!}\]
Logistic Regression
종속변수와 독립변수간에 관계를 예측하는 모델로 linear regression과 다르게 이항, 다항과 같이 항을 기준으로 classification을 한다.
odds
성공확률과 실패 확률의 비율
\[odds = \tfrac{p(y=1|x)}{1-p(y=1|x)}\]
logit
odds에 log를 취한 함수
\[logit(p) = log(\tfrac{p}{1-p})\]
sigmoid function
logit 함수의 입력과 출력을 바꾼함수
\[p(X) = \tfrac{1}{1+e^{-\beta X}}\]
logistic function
sigmoid 함수 만들어진 예측 모델
Logistic Regression은 $x$가 변할때 $y$가 1이 되는 경향성을 따지는 모델로서 아래와 같은 확률에서 시작된다.
\[p(X) = Pr(y=1|X)\]
우리가 parameter Estimation을 통하여 구하려고 하는 sigmoid의 $\hat{\beta}$는 이상 적으로 2가지 경우로 나뉜다.
$y=1$이라서 $\hat{Pr(y=1|X)}$이 1에 수렴하는 경우
$y=0$이라서 $1-\hat{Pr(y=1|X)}$이 1에 수렴하는 경우
1.의 경우 최대 확률은 $\prod_{s \, in \, y_i=1} p(x_i)$
2.의 경우 최대 확률은 $\prod_{s \, in \, y_i=0} (1-p(x_i))$
종합적인 최대 확률은 $L(\beta) = \prod_{s \, in \, y_i=1} p(x_i) \times \prod_{s \, in \, y_i=0} (1-p(x_i))$ 가 된다.
이 수식을 단순화 하면 아래의 수식이 된다.
\[L(\beta) = \prod_s p(x_i)^{y_i} \times \prod_s (1-p(x_i))^{1-y_i}\]
loss function을 활용해 최적의 함수를 찾아야하는 위의 수식은 미분에 있어서 쉽지 않다. 그래서 log를 이용한 log likelihood 함수를 만들고 음수를 취해주고 전체 샘플수로 나눠주면 loss function을 만들 수 있다.
\[J(\beta) = -\tfrac{1}{n}(\sum_{i=1}^n y_i log(p(x_i)) \times \sum_{i=1}^n (1-y_i) log(1-p(x_i)))\]
\[\tfrac{\partial}{\partial\beta_j}J(\beta) = \tfrac{1}{n}(\sum_{i=1}^n p(x^{(i)})-y^{(i)})x_j^{(i)}\]
SoftMax
Logistic Regression의 경우 binary classification의 방법을 위하여 고안이 되었으나 multinomial classificaion에 활용할 수 있게 하는 방법이 SoftMax 기법이다.
이는 도출된 경향성 점수를 $s(y_i) = \tfrac{e^{y_i}}{\sum e^y}$로 총합 1의 확률로 만들게된다.
이러한 확률을 이용하여 크로스 엔트로피(주어진 정답의 불확실성의 정도) 비용함수가 최소가 되게한다.
Decision Tree
Tree 구조로 형성된 의사결정 분류 알고리즘
데이터의 회전성에 취약하여 PCA(주성분 분석, 차원축소)를 사용하면 좋다
CART(Classification And Regression Tree)
tree가 subset을 나누는데 있어 gini가 작은 subset을 만드는 방법으로 greedy algorithm이다. loss function은 아래와 같다.
\[J = \tfrac{m_{left}}{m}G_{left}+\tfrac{m_{right}}{m}G_{right}\]
Naive Bayes
특성들 사이의 독립을 가정하는 베이즈 정리를 이용한 확률 분류기
Bayes Theorem
어떠한 기존의 확률을 토대로 새로운 데이터의 확률을 구하는 방법
\[P(c\|x)=\tfrac{P(x\|c)P(c)}{P(x)}\]
elements
$P(c|x)$ posterior probabillity
$P(x)$ predictor prior probabillity
어떠한 기존의 발생 확률
$P(c)$ class prior probabillity
어떠한 특성을 가질 확률
$P(x|c)$ likelihood
특성에서의 발생이 될 확률
Support Vector Machine(SVM)(SVC,SVR)
카테고리들이 있을때 데이터들의 사상된 공간의 경계중 가장 큰 너비를 가진 경계를 찾는 방법
(복잡, 작거나 중간 데이터셋에 적합, scaler를 하면 효율 증가)
(SVC는 kernel을 통해 PolynoialFeature없이도 고차원 적용가능, 실제로 변수가 만들어지지 않아 속도빠름)
margin
서로 다른 두가지 클래스의 데이터에서 어떠한 선으로 구분을 할경우 해당 선의 너비를 의미한다.
support vectors
margin에 해당하는 위치에 놓여있는 elements를 의미한다.
RBF(Radial Basis Fuction) Kernel
방사형 기저 함수라 불리며 비선형 데이터에서 차원을 높여서 margin을 설계하는 방법
Clustering
흩어져있는 원소들을 군집화하여 유사한 데이터끼리 묶는 방식으로 하는 비지도학습
K Nearest Neighbors(KNN)
새로운 데이터를 입력받을때 가까운 데이터들의 분포에 따라 통계적으로 분류를 하는 알고리즘
K means
임의의 centroid를 지정후 근접합 데이터를 군집화 한다음 centroid를 재설정하는것을 반복하여 군집을 구하는 방법(변수들의 스케일링을 하면 효과가 좋다)
DB Scan
밀도 기반 군집화 기법으로 범위내에 있는 샘플들의 갯수가 군집화가 되는 기준이다.
가우시안 혼합 모델(GMM)
Gaussian Mixture Model은 분류가될 집합이 가우시안 분포로 되어있다고 가정하여 클러스터를 구성하는 확률 모델이다.
흩어져있는 원소들을 군집화하여 유사한 데이터끼리 묶는 방식으로 하는 비지도학습
Bagging VS Boosting
bagging
분산을 감소시키는 방법으로
복원 추출을 통해 n개의 샘플을 만드는 boostraping을 통해 나온 샘플을 학습시켜서 선형 결합한것
boosting
편항을 감소시키는 방법으로
weak learner를 생성해서 구한 error를 토대로 가중치를 가해 error를 줄이는 방법이다.
Decision Tree ensemble
ensemble
우수한 모델들에서 나온 결과를 선형적으로 결합하여 성능을 향상하는 방법
Random Forest
bagging을 사용한 알고리즘으로 모든 변수를 기반으로 Tree 생성
Extra Trees
bagging을 사용하지 않는 random forest 알고리즘
AdaBoost
boosting을 사용하여 샘플의 가중치를 더해 순차적 학습을 하는 알고리즘
Decision Tree Gradient Boosting
Gradient Boosting은 미분을 통해 Residual을 줄이는 방향으로 weak learner들을 결합하는 방법(과적합 이슈의 발생)
Extreme Gradient Boosting(XGB)
Regularization과 다양한 loss function을 지원하여 과적합을 감소시킨 방법
Light Gradient Boosting
histogram-based/GOSS/EFB와 같은 알고리즘으로 학습데이터를 감소시켜 속도를 향상시킨 방법
GBM은 Level-wise한데 LGBM은 Leaf-wise해서 시간은 적게 걸려도 깊은 트리형으로 문제없이 작업한다.
GOSS(Gradient-based One-Side Sampling)으로 infomation gain을 계산할때 기울기(가중치)가 작은 변수에 승수 상수로 데이터를 증폭시킴
(데이터가 적으면 과적합 위험)
Categorical Gradient Boosting
범주형 변수를 위한 알고리즘으로 one-hot encoding사용시 증폭되는 메모리 이슈를 보완하였음
(oblivious Decision Tree, Feature Combination)
Natural Gradient Boosting
각 예측값에 대한 신뢰도를 도출해주는 알고리즘으로 시간이 오래걸리는 단점이 있음
차원축소
대부분의 데이터는 고차원으로 구성이 되어있어도 가까이에 있는 경향이 많아 저차원 공간으로 투영(projection)과 같은 차원축소 기법을 통해 해결할 수 있다.
매니폴트
고차원에서 휘어져있는 형태로 고차원에서 가까워 보이지만 실제로는 멀리있는 데이터를 효과적으로 차원 축소 하는 방법
주성분 분석(PCA)
Principal Component Analysis는 보편적인 차원축소 기법으로 분포도를 최대한 유지하는 방향으로 차원을 축소하는 방법이다.(평균이 0인 StandardScaler가 필요하다, sklearn은 자체 지원)
sklearn은 explained_variance_ratio를 통하여 축소한 차원에서 얼마나 분산의 손실이 발생했는지 알 수 있다.
특잇값 분해(SVD)
Singular Value Decomposition은 주성분을 찾는 방법으로 $m \times n$인 행렬 $A_1$에 대한 특잇값 분해는 $U_1\sum_1V_1^T$이다. 이는 유사역행렬을 구하는 방법과 유사하지만 유사역행렬의 $\sum$은 $k \times k$로 변동성이 있지만 SVD는 $m \times n$이다.(thin SVD와 같이 축소기법을 사용하면 크기가 감소하기도 한다.)
SVD를 통하여 구한 $V$의 각 열을 순서대로 $c_1, c_2, …$로 주성분의 축을 구할 수 있다.
$c_1, c_2, …$의 갯수를 통하여 투영하려는 차원을 정할 수 있다.
\[X_{d-proj} = XW_d\]
지역선형임베딩(LLE)
Locally Linear Embedding은 투영을 하지않고 매니폴드를 활용하는 기법이다. 이웃 원소와의 선형성을 측정하여 국부적 관계가 보존되는 저차원을 표현함
t-SNE
비슷한 샘플과 비슷하지 않은샘플로 구분하여 차원을 축소하는 방법
AI
/
ML
/
basic
· 2023-10-23
-
-
1. essay quality
kaggle-linking-writing-processes-to-writing-quality
Overview
글쓰기 품질을 예측하기 위한 모델을 만드는 대회이다.
데이터는 키스트로크 로그 데이터로 이루어져 있다.(시계열)
Description
글쓰기 과정을 정형데이터로 만들기가 쉽지 않다. 에세이별로 작성자의 특성(쉬는 타이밍, 수정법, …)을 파악하여 품질에 영향을 줄 수 있다. 하지만 실제는 결과물만 가지고 평가를 하게 되어서 실질적인 활용에 있어서는 고려해야할 사항이 많다.
Evaluation
평가지표로는 RMSE평가지표를 기반으로 사용한다. 이번대회는 특이하게 Efficiency RMSE 평가지표도 활용하여 추가 수상의 기회가 있다.
Data Collection Procedure
Keystroke Data Collection Procedure
SAT에서 사용하는 글쓰기 프롬프트를 기반으로 하여 글쓰기를 하였다. 4종류의 다른 프롬프트가 사용이되어서 편차가 발생할 수 있다.
30분이내에 3문단에 200단어이상으로 구성한 에세이를 작성해야한다. 또한 작성자가 2분이상 활동이 없거나 프롬프트 이외의 작업을 하려고 하면 경고창이 뜨게했습니다.
Keystroke Logging Program
키스트로크 정보를 수집하기위해 JS를 이용하여 만든 프로그램을 통하여 수집을 했다. JS에서 지원하는 addEventListener를 이용하여 수집을 하여 키 입력, 마우스 조작에 대한 값을 수집하게 된다. 이벤트는 순서대로 이벤트 ID에 라벨링을 하며 값을 가지게된다.
Keystroke Measures
Production Rate
글쓰기 생산 비율은 글쓰기 과정에서 시간을 기준으로한 특징(문자, 단어, 문장, …)을 나타내는 비율을 나타낸다.
글쓰기 과정에서 분당 특징(문자, 단어, …)의 갯수를 나타내는 비율
글쓰기가 완성된 상태에서 분당 특징(문자, 단어, …)의 갯수를 나타내는 비율
Pause
일시 중지행동은 2초의 임계값을 가지는 IKI(key down 입력 간의 간격)가 있는것을 의미한다. 이러한 일시중지 활동을 활용하여 아래와 같은 해석이 가능하다.
일시중시 횟수(전체, 분당)
일시중지 시간 비율(전체 시간 대비)
일시중지 길이(전체 일시중지 시간의 평균)
특징(단어, 문장, …)들 사이에서 일시중지 길이 또는 빈도수
Revision
글쓰기에서 수정과 관련된 항목이다. 삭제는 어디서든 단어를 지우는 행위를 칭하며, 삽입은 글쓰기의 마지막 위치가 아닌 위치에서 진행하는 입력을 칭한다.
삭제 횟수(전체, 분당)
삽입 횟수(전체, 분당)
삭제한 길이(단어수)
삽입한 길이(단어수)
삭제 시간 비율(전체 시간 대비)
삽입 시간 비율(전체 시간 대비)
글쓰기 완료 vs 글쓰기 진행에서 변경된 단어수의 비율 비교
글쓰기 완료 후 수정이 진행된 횟수와 길이
수정이 이루어진 직후 이루어진 수정의 횟수, 길이
현재 지점에서 발생한 수정의 횟수
다른 지점에서 발생한 수정의 횟수
Burst
일시 중지 및 수정없이 지속적으로 글쓰기를 진행하는것을 버스트라고 한다. P-버스트는 일시중지를 기준으로 분리가 되는것, R-버스트는 수정을 기준으로 분리가 되는 글씨기 행위이다.
P-버스트의 숫자(전체, 분당)
R-버스트의 숫자(전체, 분당)
P-버스트의 시간 비율(전체 시간 대비)
R-버스트의 시간 비율(전체 시간 대비)
P-버스트의 길이(단어수)
R-버스트의 길이(단어수)
Process Variance
글쓰기의 분산은 글쓰는 과정에서 작성자가 구간별로 유창하게 작성하는것을 보기 위한 기준이다. 5 또는 10과 같이 특정값을 기준으로 전체를 분할하고 분할된 구역에서 생성된 문자의 수(전체, 분당)를 의미한다.
simple EDA
키스트로크 로그 데이터는 아래와 같이 구성이 된다.
id는 에세이를 구별하는 인자
event_id는 해당하는 에세이에서 발생하는 서순을 확인하기 위한 인자
down_time은 해당 키는 누르는 시점의 시간
up_time은 해당 키를 떼는 시점의 시간
action_time는 up_time - down_time
activity는 취한 액션이 어떠한 활동인지를 구별하는 인자
down_event, up_event는 어떤 키스트로크인지 구별하는 인자(단순한 문자는 q로 마스킹 처리됨)
text_change는 해당 event를 통하여 변경된 logs를 나타내는 인자
cursor_position은 깜빡이는 커서가 현재 어디 있는지 나타내는 인자
word_count는 작성된 단어의 갯수
점수 데이터는 아래와 같이 구성이 된다.
id는 에세이를 구별하는 인자
score는 에세이의 점수
키스트로크 로그의 info는 아래와 같이 결측값은 없다.
점수 데이터의 info는 아래와 같이 결측값은 없다.
키스트로크 로그의 describe는 아래와 같다.
점수 데이터의 describe는 아래와 같다.
keystroke EDA
Production Rate
문자, 단어, 문단등의 상황에서의 갯수와 비율을 살펴본다.
Production Rate(character)
문자의 갯수를 따지는 행위를 보면 각 액션에서 text_change가 어떻게 되었는지를 확인하면 볼 수 있다. text_change를 살펴보면 q로 마스킹 된 값, copy&paste와 같이 여러문자를 다루는 “ => “로 구분하는값, Move행위를 통하여 문자들이 이동한 값, 특이값으로 크게 4종류로 구분을 할 수 있다.
이것이 삭제를 하는 행위인지 작성을 하는 행위인지를 확인하기 위하여 logs에 새로운 칼럼을 만드는데 remove, move, cut과 같은 행위는 삭제를 하는 행위로 취급하여 text_change의 길이를 넣고, 작성을 하는 행위는 input, move, paste와 같은 행위로 취급하여 text_change의 길이를 넣었다. move와 같은 행위는 삭제와 작성을 동시에 행하는 작업이기 때문에 두가지 종류에 같이 포함이 된다.
위의 작업을 진행하여보면 문제가 발생하게 된다. \n과 기타 특수문자가 여러개의 문자로 인식되는것이다. 그래서 전처리고 simple_text_change라는 column을 만들어서 \n과 기타 특수문자를 q로 마스킹하는 작업을 진행하고 분류를 하는 작업을 진행하게 되었다.
위의 문자의 변화를 구분하게 됨으로 인하여 우리는 문자의 갯수와 비율을 살펴 볼 수 있게 되었다. 하지만 아직 확장된 개념의 단어, 문단에 대한 이해는 조금 더 EDA를 진행해야 알 수 있다.
Production Rate(word)
Pause
다른 키스트로크와 다르게 가장 직관적인 탐색이 가능한 기법이다. IKI가 2초 이상인것이 pause이기 때문에 이전의 down_time을 down shift를 행하여 현재의 down_time과 비교를 했을때 2초이상의 차이가 나면 is_pause라는 column을 추가로 생성해 True값을 넣어주면서 시작을 한다.
Pause(count)
생성된 is_pause columns을 sum, 시간에 대하여 섹션을 나눠서 sum을 진행하면된다.
Pause(rate)
event_id의 시작과 끝의 시간 차이를 통하여 실제 작업시간을 확인하고 실제작업시간으로 일시중지한 시간의 합을 나눠서 구한다.
Pause(length)
is_pause에 해당하는 값들의 시간을 수치적으로 분석한다(mean, max, min, …)
Pause(per state)
단어의 경우 전, 후에 q의 입력이 있는지
문장의 경우 전, 후에 space의 입력이 있는지
문단의 경우 전, 후에 \n의 입력이 있는지
위의 케이스별로 빈도수와 길이를 구한다.
Revision
삭제의 경우 판단하기가 쉬우며 Production Rate단에서 생성한 삭제된 단어가 존재할 경우 is_deletion을 True로 이루어진 column을 만들면 된다.
삽입의 경우 판단하기가 쉽지 않다. 첫번째로 알아야하는것이 현재 내 커서의 위치가 마지막이 아닌지를 확인하고 Production Rate단에서 input에 해당하는 부분이 존재하는지 확인을 하면 된다.
하지만 이번 대회에서 데이터를 확인해본 결과 작성도중 맨뒤에 스페이스를 놔두고 그 직전에 입력을 하는 등 입력을 하는 위치가 신뢰성이 조금 떨어지는것이 확인 되어서 2가지 가설을 세워 보았다.
작성자가 실수를 한것이다.
맨뒤의 스페이스는 자동으로 지워지는 프롬프트를 사용한것이다.
이것은 cumsum을 이용한 누적글자수와 현재의 커서 위치를 분석하여 커서가 어디에 위치하는지를 분석해보고 스페이스 이후에 revision이 발생하면 스페이스를 제거하는 로직을 구성해 보았으나 오히려 정상적으로 작동하지 않은것을 확인하게 되었습니다.
이후 데이터를 수동으로 추적해본 결과 스페이스가 지워지지않음을 확인하게 되어서 작성자가 맨뒤에 스페이스가 있는것을 잊고 작업을 했음을 알 수 있었습니다. 그렇기 때문에 작성자가 실수한것을 고려하여 revision을 진행할지 아니면 고려하지 않고 진행할지 방향이 두가지로 나뉘어지게 되었습니다.
Revision(deletion)
is_deletion을 sum으로 전부 합한 값, per minute
Revision(insertion)
is_insertion을 sum으로 전부 합한 값, per minute
Revision(deletion length)
is_deletion일때 문자 삭제 columns의 수의 합
Revision(insertion length)
is_insertion일때 문자 생성 columns의 수의 합
Revision(deletion rate)
is_deletion일때 시간의 합을 전체시간으로 나눈값
Revision(insertion rate)
is_insertion일때 시간의 합을 전체시간으로 나눈값
Revision(revisioned character)
문자 생성 columns의 수의 합과 문자 제거 column의 수의 합을 column으로 생성
Revision(revision after producted)
current_cursor의 위치가 max_character의 위치와 같으면서 최대값인 이후에 진행된 event들에서 발생한 revision들의 횟수와 길이
Revision(revision after revision)
is_deletion or is_insertion의 이후에 연속으로 발생한 revision의 횟수, 길이
Revision(revision in same place)
current_cursor를 down diff로 값을 받아서 값이 변경하지 않았 했으면서 event가 Nonproduction가 아닌 revision이 발생하는 경우의 횟수현재 지점에서 발생한 수정의 횟수.
하지만 직전값을 인식하는 방식의 경우 올바르게 작동하지 않을 수 있기때문에 추가적으로 확인이 필요함
Revision(revision in different place)
current_cursor를 down diff로 값을 받아서 값이 변경을 했으면서 event가 Nonproduction(기타 키입력, 마우스 클릭) revision이 발생하는 경우의 횟수.
하지만 직전값을 인식하는 방식의 경우 올바르게 작동하지 않을 수 있기때문에 추가적으로 확인이 필요함
Burst
Burst(p number)
is_pause간의 거리가 1이상인 burst의 숫자(is_pause.sum + 1), 분당 카테고리화 하여 is_pause.sum + 1
Burst(r number)
is_revision간의 거리가 1이상인 burst의 숫자(is_revision.sum + 1), 분당 카테고리화 하여 is_revision.sum + 1
Burst(p rate)
is_pause의 시간의 합을 전체 시간으로 나눠준 값을 1에서 뺀값
Burst(r rate)
is_revision의 시간의 합을 전체 시간으로 나눠준 값을 1에서 뺀값
Burst(p length)
is_pause간의 상태에서 단어의 변화량의 합
Burst(r length)
is_revision간의 상태에서 단어의 변화량의 합
Process Variance
Process Variance(per state)
글쓰기의 분산은 글쓰는 과정에서 작성자가 구간별로 유창하게 작성하는것을 보기 위한 기준이다. 5 또는 10과 같이 특정값을 기준으로 전체를 분할하고 분할된 구역에서 생성된 문자의 수(전체, 분당)를 의미한다.
Review
-
-
-
3. 종합탐색(1)
개요
지금까지 파이썬을 이용한 몇몇가지 기능들을 공부했고 내용을 확립하기 위하여 간단한 프로젝트를 진행하기로 했다.
시리와 같은 AI 봇은 아니지만 pandas, tts, stt, 크롤링까지 지금까지 배운것들을 토대로 간단하게 챗봇느낌의 프로그램을 제작해보았다.
내용
자료 파트에서 참고하여 보면 아래와 같이 구성이 되어있다.
proj
|
|— main.py
|— const.py
|— bip.mp3
|— /module
— |— api.py
— |— data_search.py
— |— speech_service.py
기본적인 프로세스는 main.py에 변동성이 없는 데이터는 const.py에 그외 중복적으로 작동되는 함수들은 사용처 별로 정리하여 module폴더에 구성하였다.
main/Timo/waitInput
stt를 활용하기 때문에 입력을 받아서 컨트롤하는 함수가 필요함을 느껴서 만들게 되었으며, bip이라는 인자를 이용해서 stt의 입력을 받을 준비가 되어 있는지 사용자가 알 수 있게 만들었습니다.
main/Timo/sst_classifier
로직을 관장하는 주된 함수로 제작하였으며, 로그인, 로그아웃, 검색, 날씨, 미세먼지, 게임, 수위 조사에 접근하여 핸들링하는 것을 가능하게 한다. 검색, 날씨 미세먼지의 경우 XX 검색 또는 검색XX와 같이 사용자에 따라서 사용법이 다를 수 있기에 두가지 모두 가능하게 했습니다. 검색의 경우는 조금 더 나아가 XXX XX 검색과 같이 여러 키워드 검색을 지원합니다.
main/Timo/__sst_classifier_error
sst_classifier를 통하여 분류가 되지 않을때 접근하게 되며 다시 명령을 기다리는 상태가 된다.
main/Timo/__sst_data_error
api와 crawling과 같은 데이터 검색을 진행할때 서버오류나 기타 오류들이 발생하면 접근하게 되며 맨처음 상태로 돌아가게 됩니다.
main/Timo/login
로그인을 하게 되면 접근하게 되며 추가적인 핸들링이 필요할 경우를 대비하여 함수화 하였습니다.
main/Timo/logout
로그아웃을 하게 되면 접근되며 추가 핸들링이 필요하면 작성하게된다.
main/Timo/naver_search
네이버 크롤링을 사용하여 검색결과를 제공하여 준다.
main/Timo/weather_search
날씨를 검색하여 주는 함수로 현재시간을 기준으로 해당 지역의 기상정보를 제공해준다.
main/Timo/pm_search
미세먼지를 검색하여 주는 함수로 검색 방식에는 여러가지로 나뉘게 된다. 단순히 서울에 대한 검색도 가능하며 서울 강남구와 같은 세부 지역도 가능하다. 로직으로는 지명을 토대로 좌표를 구하여 좌표를 기준으로 해당하는 지역의 지역번호를 받게되며, 해당 지역번호로 미세먼지 정보를 받아서 상세분류 작업을 통하여 사용자에게 제공하게 된다.
main/Timo/follow_up_game
끝말 잇기 게임으로 컴퓨터와 단어를 주고 받게 되는데 단어는 일부 제한량을 두어서 컴퓨터도 패배할 수 있게 제작했다.
main/Timo/dam_check
요즘 기습적인 폭우와 같은 문제로 인하여 침수사고가 많이 발생하고 있어 댐정보를 통하여 비교적 미리 확인이 가능하지 않을까 해서 제작을 하게 되었으며, 댐마다 실시간 저수율과 방류량을 알 수있다.
module/api/Request
html, api 정보를 받아서 json의 형태로 변환시켜준다.
module/api/SgisApi/geoCoding
지역명을 받아서 해당지역을 좌표화해 반환해준다.
module/api/SgisApi/transformation
좌표계가 사용하고자 하는좌표계와 다를경우 좌표계를 변조할 필요가 있는데 해당 변조를 도와준다.
module/api/MetroApi
미세먼지 정보를 받아서 돌려주는 함수이다.
module/api/KorDictApi
사전에 단어가 있는지, 해당하는 글자로 시작하는 단어가 있는지 확인해주는 함수이다.
module/api/DamApi
댐정보를 받아오기 위한 함수이다.
module/data_search/Searching/bs_search
bs를 반복적으로 사용하기위하여 만든 함수이다.
module/data_search/Searching/selenium_search
셀레니움을 사용할 것을 대비하여 만든 함수이다.
module/speech_service/SpeechService/stt
stt를 제공하는 함수이다. bip 인자를 통해 bip음을 출력하기도 한다.
module/speech_service/SpeechService/tts
tts를 제공하는 함수이다.
자료
링크
-
2. 멜론차트
웹크롤링을 연습하기 위해서 멜론 1~50위의 내역을 추출해 csv파일로 저장하여 보았다.
{% highlight python %}
import requests
from bs4 import BeautifulSoup as BS
import pandas as pd
headers = {‘User-Agent’:’Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36’}
url = “https://www.melon.com/chart/index.htm”
data = requests.get(url=url, headers=headers)
soup = BS(data.text,’html.parser’)
datas = soup.select(“.service_list_song .wrap_song_info a”)
rows=[]
columns=[]
for index, i in enumerate(datas):
if index / 4 < 50:
if index % 4 == 0:
print(f”순위: {int(index / 4)+1}”)
print(f”제목: {i.text}”)
columns.append(str(int(index / 4)+1)+”위”)
columns.append(i.text)
elif index % 4 == 1:
print(f”가수: {i.text}\n”)
columns.append(i.text)
elif index % 4 == 2:
rows.append(columns)
columns=[]
data = pd.DataFrame(columns=[“순위”, “제목”, “가수”],data=rows)
data.to_csv(“melon_rank.csv”, encoding=”utf-8-sig”, index=False)
{% endhighlight %}
웹크롤링을 연습하기 위해서 셀레니움을 이용하여 월별로 멜론 1~50위의 내역을 추출해보았다.
{% highlight python %}
from bs4 import BeautifulSoup as BS
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
url = “https://www.melon.com/chart/month/index.htm”
if name == “main”:
driver = webdriver.Chrome()
driver.get(url)
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ‘#conts > div.calendar_prid > div’)))
a = driver.find_element(By.CSS_SELECTOR, value=’#conts > div.calendar_prid > div’)
a.click()
a = driver.find_elements(By.CSS_SELECTOR, value=’#conts > div.calendar_prid > div > div > dl > dd.month_calendar > ul > li’)
for month_index, month in enumerate(a):
month.click()
time.sleep(2)
data_raw = driver.page_source
soup = BS(data_raw, ‘html.parser’)
title_datas = soup.select(“#lst50 > td:nth-child(6) > div > div > div.ellipsis.rank01 > span > a”)
singer_datas = soup.select(“#lst50 > td:nth-child(6) > div > div > div.ellipsis.rank02 > span”)
real_singer_datas = []
for singer_data in singer_datas:
b=singer_data.select(‘a’)
a=””
try:
a = b.text
except:
for i in b:
a += f”{i.text}, “
real_singer_datas.append(a)
else:
real_singer_datas.append(a)
for index, i in enumerate(title_datas):
print(f”{month_index+1}월 {index+1}위 노래: {i.text} 가수: {real_singer_datas[index]}”)
time.sleep(5)
driver.quit()
{% endhighlight %}
-
-
-
-
Matplotlib & Seaborn
Matplotlib
파이썬 시각화 라이브러리로 matlab을 참고하여 제작함.
주로 논문에서 figure를 작성할때 사용함.
pyplot
빠르고 간단하게 그래프를 그릴때 사용
OOP-style
구체적으로 요소들을 손봐서 그래프를 그릴때 사용
pyplot
아래 3개와 같이 기본적인 형이 존재하며 추가적인 속성들을 변경하여 그래프를 그린다.
단일 plot 생성
{% highlight python %}
plt.figure()
plt.plot()
plt.show()
{% endhighlight %}
단일 plot에 그래프들 겹치기
{% highlight python %}
plt.figure()
plt.plot()
plt.plot()
plt.show()
{% endhighlight %}
다중 plot 작성
{% highlight python %}
plt.figure()
plt.subplot(,,)
plt.subplot(,,)
plt.show()
{% endhighlight %}
다음과 같은 데이터가 있을때
{% highlight python %}
x = [“data1”, “data2”, “data3”, “data4”]
y = [111, 156, 487, 445]
z = [50, 549, 450, 42]
{% endhighlight %}
아래와 같은 그래프들을 그릴 수 있으며
{% highlight python %}
plt.bar(, , *arg)
plt.barh(, , *arg)
plt.plot(, , *arg)
plt.scatter(, , *arg)
{% endhighlight %}
아래와 같은 옵션들을 사용이 가능하다
{% highlight python %}
plt.figure(figsize=(10,5))
plt.plot(x,y, label=”plot”, width=0.2, color=”red”, marker=”^”)
plt.title(“Title”, fontdict={‘fontsize’: 10}, loc=”center”)
plt.xlabel(“menu”, fontdict={‘fontsize’: 10}, loc=”left”)
plt.ylabel(“data”, fontdict={‘fontsize’: 10}, loc=”bottom”)
plt.legend(loc=”upper right”)
plt.yticks([1,2,5,50,100,200])
plt.ylim(0, 1000)
plt.grid(alpha=1, color=”red”, linewidth=10)
{% endhighlight %}
Seaborn(Statisical Data Visualization library based on Matplotlib)
Matplotlib를 참고하여 제작하였으나 파이썬의 라이브러리에 더 친화적이다.
pandas의 dataframe을 사용하는데 용이함
기본적인 세팅은 plt와 같으며 아래와 같이 제공하는 데이터를 불러올 수 있다.
{% highlight python %}
data = sns.load_dataset(“penguins”)
{% endhighlight %}
NaN 데이터는 아래와 같이 정리가 가능하며
{% highlight python %}
data = data.dropna()
data.isnull()
data[data.isnull().any(axis=1)]
{% endhighlight %}
plt외에도 아래와 같은 세팅도 가능하다.
{% highlight python %}
sns.set_palette(“bone”)
{% endhighlight %}
히스토그램
{% highlight python %}
sns.histplot(data=data, x=”body_mass_g”, bins=15, hue=”species”, multiple=”stack”)
{% endhighlight %}
밀도표
{% highlight python %}
sns.displot(data=data, kind=”kde”, x=”body_mass_g”, hue=”species”, col=”island”)
{% endhighlight %}
막대그래프
confidence interval(Default: 에러영역)를 가짐
{% highlight python %}
sns.barplot(data=data, x=”species”, y=”body_mass_g”, hue=”sex”, ci=”sd”)
sns.barplot(data=data, x=”body_mass_g”, y=”species”)
{% endhighlight %}
갯수표
{% highlight python %}
sns.countplot(data=data, x=”sex”)
{% endhighlight %}
박스 그래프
outlier를 확인할 수있음
{% highlight python %}
sns.boxplot(data=data, x=”sex”, y=”bill_depth_mm”)
{% endhighlight %}
violin 그래프
분포를 확인하는데 효과적임
sns.violinplot(data=data, x=”species”, y=”bill_depth_mm”)
라인 그래프
경향성과 confidence interval(Default: 에러영역)를 가짐
{% highlight python %}
sns.lineplot(data=data, x=”body_mass_g”, y=”bill_depth_mm”)
{% endhighlight %}
포인트 그래프
경향성과 confidence interval(Default: 에러영역)를 가짐
{% highlight python %}
sns.pointplot(data=data, x=”body_mass_g”, y=”bill_depth_mm”)
{% endhighlight %}
분산도 그래프
{% highlight python %}
sns.scatterplot(data=data, x=”body_mass_g”, y=”bill_depth_mm”)
{% endhighlight %}
페어 그래프
numeric value들의 비교표들 모음
{% highlight python %}
sns.pairplot(data=data, hue=”species”)
{% endhighlight %}
히트맵 그래프
상관관계를 색상으로 나타냄
상관계수 파악을 위해 corr matrix 생성하여 만듬
{% highlight python %}
corr = data.corr(numeric_only = True)
sns.heatmap(data=corr, square=True, cmap=”Blues”, annot=True, fmt=”.4f”)
{% endhighlight %}
PYTHON
/
Module
· 2023-09-01
-
Pandas
Pandas(Python Data Analysis Library)
정형데이터 조작에 최적화된 라이브러리
행렬로 이루어진 테이블 형태구조의 데이터 연산이 뛰어나다
json,html,csv,xlsx,sql등등 다양한 정형화 데이터를 통일하여 표현가능
기본구조
Pandas는 1차원 구조와 2차원 구조를 가지고 있으며 아래와 같다.
1차원 구조
pd.Series([1,3,5,np.nan, 78])
2차원 구조
pd.DataFrame(
data=np.arange(1, 49).reshape(12, 4),
index=np.arange(12),
columns=[“X1”,”X2”,”X3”,”X4”]
)
data= 구조를 만드는데 사용할 데이터 2차원구조 필요
index= 구조를 만드는데 사용할 인덱스명
data= 구조를 만드는데 사용할 컬럼명
pandas의 내부 구조는 numpy array기반으로 생성해서 universal function 같은 numpy array의 기능을 사용할 수 있다.
Fancy indexing
<pd.data>.<columnName> == <pd.data>[<columnName>]
<pd.data>의 해당 컬럼 기반의 시리즈 추출
<pd.data>.index[<num>]
<pd.data>에서 <num>번째 인덱스이름 가져오기
<pd.data>.loc[<indexName>, <columnName>]
<pd.data>의 (<indexName>, <columnName>)에 해당하는 값을 추출(차원 구조로 작성시 해당 차원의 값이 전부 나옴)
<indexName>임이 중요하다 n을 넣으면 n-1이 아님
<pd.data>.iloc[<indexNum>, <columnNum>]
loc과 작동이 같으나 Name이 아닌 Number를 기준으로 한다.
mask
조건식을 적용하면 조건의 만족여부를 확인가능한 mask가 생성되며 해당 마스크로 데이터를 가공할 수 있다.
<pd.data>[<pd.data>기반 조건]
<pd.data>에서 조건에 해당하는 데이터 추출
기본함수
<pd.data>.index
<pd.data>의 인덱스값 추출
<pd.data>.columns
<pd.data>의 컬럼값 추출
<pd.data>.values
<pd.data>의 값 추출
<pd.data>.apply(<func>)
<pd.data>의 값을 <func>을 통해 가공하여 추출
<pd.data>.str.contains(pat=<string>, regex=Bool)
<pd.data>에 <string>이 있는지 확인 regex=True(default)
<pd.data>[<columnName>]
<pd.data>의 해당 컬럼 기반의 시리즈 추출
<pd.data>.head(<num>)
<pd.data>의 인덱스 0에서 <num>(Null: 5)개 추출
<pd.data>.tail(<num>)
<pd.data>의 인덱스 뒤에서 <num>(Null: 5)개 추출
<pd.data>.info()
<pd.data>의 전반적인 정보를 제공
<pd.data>.describe()
<pd.data>의 전반적인 통계치를 제공
<pd.data>.groupby(<columns_name>)
<pd.data>에서 수치데이터를 <columns_name>의 기준으로 분별한다.
pd.to_numeric(<pd.data>, error=<state>)
<pd.data>를 숫자로 변환한다.
error=”ignore”: 숫자가 안되면 원본
error=”coerce”: 숫자가 안되면 NaN
error=”raise”: 숫자가 안되면 에러발생
pd.to_datetime(<pd.data>)
<pd.data>를 시간타입의 값으로 변환한다.
<pd.data>.dt.hour 과같이 원하는 값을 추출할 수 있다.
<pd.data>.sort_values(by=<pd.columnName>, ascending=False)
<pd.data>의 값에서 <pd.columnName>를 기준으로 정렬
ascending = True: 오름차순 False: 내림차순
Datafram 합치기
pd.merge(<pd.data>, <pd.data>, on=”A”, how=”outer”)
how=”outer”, “inner”, “left”, “right”
<pd.data>끼리 join을 이용한 합치기
pd.merge_asof(<pd.data>, <pd.data>, on=”A”, direction=”backword”)
direction=
backword는 left에 매칭하여 빈공간없이 합치기
forword는 left에 매칭하여 빈공간있게 합치기
nearest는 left에 매칭하여 근처값으로 합치기
pd.concat([<pd.data>, <pd.data>], axis=<num>)
<pd.data>들을 <num>차원으로 합치기
<pd.data>.reset_index(drop=Null)
<pd.data>의 인덱스를 재정의
drop= True는 기존 인덱스 삭제 False는 기존 인덱스 남겨둠
pivot table
특정 컬럼을 기준으로 통계량을 측정하여 판다스 테이블화 하는것
pd.pivot_table(data=<pd.data>, index=[<columnName>], values=[<columnName>], aggfunc=[<option>,<option>])
index에 입력한 <columnName>을 인덱스로 하고 values에 입력한 <columnName>이 columns가 되는 테이블을 만듬
aggfunc에 있는 <option>에 해당하는 값으로 column을 만듬 e.x. sum, mean, count 등등…
unpivot
pivot화 된 데이터를 풀어헤치는 행위
stack은 기준이 없을때 melt는 기준이 있을때 용이
(with)stack
stack -> columns to index / unstack -> index to columns
<pd.data>.stack(level=[0,…], dropna=True).reset_index().set_axis([], axis=1)
level은 columns의 최상단부터 0으로 매겨지며 해당하는 columns를 index로 보내고 인덱스를 리셋하여 다시 네이밍을 하는 방법
(with)melt
<pd.data>.melt(id_Vars=None, value_vars=None, var_name=None, value_name=”value”)
id_Vars를 기준으로 데이터를 풀어헤치며 데이터를 value, columns를 variable로 분배한다.
외부 Datafram 불러오기
colab
{% highlight python %}
from google.colab imort drive
drive.mount(‘/content/drive’)
data = pd.read_csv(“/dir/data.csv”)
{% endhighlight %}
window
{% highlight python %}
data = pd.read_csv(“/dir/data.csv”)
{% endhighlight %}
PYTHON
/
Library
· 2023-08-31
-
Numpy
Numpy(Numerical computing with Python)
수치연산과 벡터 연산에 있어서 강한 이점을 가진 라이브러리
np.array
최초 선언 후 사이즈 변경이 불가능
모든 원소의 데이터 타입이 동일해야한다 (homogeneous array)
Mixed Precision
numpy는 아래와 같이 다양한 데이터 타입을 가지고 있다.
np.int[8~64]
np.uint[8~64]
Mixed Precision은 32비트(고용량)에서 메모리가 너무 사용될때 비트수를 내려서 메모리 부담과 속도를 관리하는 방법
np.arange(<num>)
0~-1 의 array 생성
<np.array>.shape
<np.array>의 형태를 확인
<np.array>.reshape(x, y)
<np.array>의 형태를 (x, y)로 변경
(x, ) 1차원 x개원소
(x,1) 2차원 x개원소
(-1, ) 1차원 원소 전부
<np.array> 연산
연산은 벡터 연산으로 실행됨
np.concatenate([<np.array>, <np.array>])
+
-
@(dot product)
하지만 아래의 연산은 원소들 끼리 연산이됨
*
/
또다른 방법으로 연산을 붙이기 연산으로 사용하려면
np.concatenate([<np.array>, <np.array>], axis=<axis>)
해당 차원(<axis>)의 붙이기만 가능
np.vstack([<np.array>, <np.array>])
수직적인 붙이기(axis=1)
np.hstack([<np.array>, <np.array>])
수평적인 붙이기(axis=0)
broadcast
차원이 다른 array의 연산을 할 수있는데 첫번째 차원이라도 원소의 크기가 같아야한다
universal Function
broadcast의 확장적인 의미의 함수
1 / <np.array>는 각각의 원소가 1로 나뉘어진 array가 나옴
numpy indexing
python indexing과 같은 방법을 사용가능하며,
<np.array>[x, y]로 <np.array>[x][y]를 표현 가능하다.
Math Function
np.random.seed(0)
랜덤 생성함수의 시드 고정(테스트 결과 비교할때 좋음)
np.random.rand(<dimen>)
<dimen>에는 차원의 shape을 입력 e.x.(1,3)
0~1로 이루어진 지정 차원의 랜덤 array 생성
np.random.randn(<dimen>)
<dimen>에는 차원의 shape을 입력 e.x.(1,3)
평균 0, 표준편차 1로 이루어진 지정 차원의 랜덤 array 생성
np.abs(<np.array>)
절대값 생성
np.squre(<np.array>)
제곱값 생성
np.sqrt(<np.array>)
루트값 생성
np.abs(<np.array>)
절대값 생성
np.linalg.norm(<np.array>)
<np.array> 제곱합의 루트값 생성 (L2 norm)
np.linalg.eig(<np.array>)
<np.array> eigenvalue(고유값)와 eigenvector(고유 벡터)값을 생성
np.sum(<np.array>, axis=)
<np.array>의 차원에 따른 합
np.mean(<np.array>, axis=)
<np.array>의 차원에 따른 평균
np.std(<np.array>, axis=)
<np.array>의 차원에 따른 표준편차
np.min(<np.array>, axis=)
<np.array>의 차원에 따른 최소값
np.max(<np.array>, axis=)
<np.array>의 차원에 따른 최대값
np.argmin(<np.array>, axis=)
<np.array>의 차원에 따른 최소값의 인덱스
np.argmax(<np.array>, axis=)
<np.array>의 차원에 따른 최대값의 인덱스
np.sort(<np.array>, axis=)
<np.array>의 차원에 따른 정렬(오름차순)
np.sort(<np.array>, axis=)[::-1](내림차순)
np.argsort(<np.array>, axis=)
<np.array>의 차원에 따른 정렬한 값의 인덱스
PYTHON
/
Library
· 2023-08-30
-
멀티 스레드와 멀티 프로세스
threading&multiprocessing
threading
스레드를 늘려서 다른 코드들이 동시에 작동하는것 처럼 만들어주는 라이브러리
class threading.Thread(target=None, name=None, args=(), kwargs={}, *, daemon=None) ***
스레드 생성을 하는 클래스선언
target 매개변수는 스레드에 함수를 할당할 수 있다.
name 매개변수는 스레드에 이름을 할당할 수 있다.
args 매개변수는 스레드에 가변 매개변수들을 할당할 수 있다.
kwargs 매개변수는 스레드에 키워드 가변 매개변수들을 할당할 수 있다.
demon 매개변수는 True/false를 받으며 스레드를 데몬 스레드로 만들어서 메인스레드와 운명을 같이 하게 된다.
.start() ***
스레드 객체의 작동 메서드(.run() 메서드를 작동시킨다.)
.run()
스레드 서브 클래스를 만들때 추가적으로 작동 하고 싶은것을 선언할 수있다.
.join(timeout=None) ***
스레드가 종료 될때까지 이후의 코드를 작동하지 않는다.
timeout 매개변수는 스레드에 시간제한을 줄 수 있으며, 시간제한을 초과하면 스레드를 멈춰줘야한다.
.is_alive()
스레드가 작동중인지 확인 할 수 있으며, 작동시 True를 반환한다.
파이썬의 스레드는 하나의 프로세스에서 여러개의 스레드를 병렬 처리한다. 이때 공유되는 자원들을 동시에 변형가하면 충돌을 발생해 무시될 수 있다. 다음에 소개 할 threading.Lock() 클래스는 이를 해결해준다.
class threading.Lock() ***
스레드의 락 기능을 선언하는 클래스
.acquire(blocking=True, timeout=- 1) ***
락 기능이 작동중인지 작동중이지 않은지 수 있는 메서드.
blocking 매개변수가 True이면 락을 작동(코드 멈춤)하고 True를 반환하고, False이면 락을 작동시키지 않고(코드 진행) 추후에 True/False를 반환합니다.(default: true)
.release() ***
스레드의 락을 해제하며 해제된 스레드에서 작동시 런타임 오류발생.
with구문을 활용하여 acquire()과 release()를 한번에 관리가능하다.
.locked()
스레드가 잠겨있으면 True반환.
락을 사용하는데 A함수와 B함수를 사용하고 A함수가 B함수를 재사용하는 재귀형식의 스레드활용시에는 acquire의 사용에 있어 오류를 발생할 수 있는데 이때 사용하는것이 RLock이다.
class threading.RLock()
스레드의 락 기능을 선언하는 클래스
.acquire(blocking=True, timeout=- 1)
락 기능이 작동중인지 작동중이지 않은지 수 있는 메서드.
blocking 매개변수가 True이면 락을 작동(코드 멈춤)하고 True를 반환하고 재사용시에 1을 반환한다. False이면 락을 작동시키지 않고(코드 진행) 추후에 True/False를 반환합니다.(default: true)
.release()
스레드의 락을 해제하며 해제된 스레드에서 작동시 런타임 오류발생.
with구문을 활용하여 acquire()과 release()를 한번에 관리가능하다.
.locked()
스레드가 잠겨있으면 True반환.
이외에도 많은 함수들이 존재하지만 주로 사용하는 함수만 정리했으며 추가적인 자료는 아래를 참고한다.
원문
{% highlight python %}
from threading import Thread
def subthread():
worker = Thread(target=subthread) # worker에 서브쓰레드 할당
worker.daemon = True # 메인쓰레드가 종료될때 sub도 종료됨(선택)
worker.start() # worker 실행
worker.join() # worker가 끝날때까지 대기(선택)
{% endhighlight %}
---
## **multiprocessing**
---
프로세스를 늘려서 다른 코드들을 동시에 작동시켜주는 라이브러리
multiprocessing의 경우 threading보다 더 다양한 클래스와 메서드들을 가지고 있다.
> **class multiprocessing.Pool(processes=None)** \***
> * 멀티 프로세스중 초기 지정한 프로세스수를 활용하는 클래스선언
> * **processes** 매개변수는 멀티프로세스에서 사용할 프로세스의 갯수를 나타내며 os.cpu_count()를 활용하면 나내 컴퓨터의 최대 프로세스수를 알 수있다. 최대치를 넘는 프로세스는 오류를 유발할 수 있다.
{% highlight python %}
def subprocess():
if __name__ == '__main__':
with Pool(5) as p:
print(p.map(subprocess, ))
{% endhighlight %}
> **class multiprocessing.Process()** \***
> * 멀티 프로세스중 스레드와 유사한 작동방식을 가지며 각각의 프로세스를 관리하는 클래스선언
> [참조](/study/pythonModule/1_threading&multiprocessing#threading)
{% highlight python %}
import multiprocessing as mp
def subprocess():
if __name__ == "__main__":
worker = mp.Process(target=subprocess, args=(...)) # worker에 서브프로세스 할당
worker.daemon = True # 메인쓰레드가 종료될때 sub도 종료됨(선택)
worker.start() # worker 실행
mp.current_process() # PID값을 반환해줌(선택)
worker.is_alive() # PID값을 반환해줌(선택)
worker.terminate() # 강제종료(선택)
worker.join() # worker가 끝날때까지 대기(선택)
{% endhighlight %}
> **class multiprocessing.Queue(maxsize=0)** \***
> * 멀티 프로세스중 프로세스수간 FIFO 데이터 전송을 위한 클래스선언
> * **maxsize** 매개변수는 큐의 최대사이즈를 입력받으며 0은 제한없음을 의미한다.
>
> **.get()** \***
> * 큐에 있는 값을 하나 받아온다.
>
> **.put()** \***
> * 큐에 값을 하나 넣는다.
> **class multiprocessing.Pipe(duplex=None) return(conn1, conn2)** \***
> * 멀티 프로세스중 프로세스수간 한쌍으로 데이터 전송을 위한 클래스선언
> * **duplex** 매개변수는 True일 경우 양방향 통신 False일 경우 단방향 통신(conn1: reciver, conn2: sender)으로 활용된다.
>
> **conn.send()** \***
> * 파이프에 값을 넣는다.
>
> **conn.recv()** \***
> * 파이프에서 값을 받아온다.
> **class multiprocessing.Lock()** \***
> * 락을 관리하는 멀티 프로세스중 스레드 락과 유사한 작동방식을 가지며 각각의 프로세스를 관리하는 클래스선언
> [참조](/study/pythonModule/1_threading&multiprocessing#threading)
> **class multiprocessing.Manager()** \***
> * 멀티 프로세스의 자원을 안전하게 관리하기 위한 클래스선언
> * 다음과 같은 지원을 한다.(더 있음)
> * .list()
> * .dict()
> * .Lock()
> * .RLcok()
> * .Array()
이외에도 많은 함수들이 존재하지만 주로 사용하는 함수만 정리했으며 추가적인 자료는 아래를 참고한다.
[원문](https://docs.python.org/ko/3/library/multiprocessing.html)
PYTHON
/
Module
· 2023-08-29
-
-
Django init summary
Django
django-debug-toolbar -> 디버그 내용 확인 용이
INSTALLED_APPS “debug_toolbar”
MIDDLEWARE “debug_toolbar.middleware.DebugToolbarMiddleware”
INTERNAL_IPS “IP”
djangorestframework -> restAPI 제작에 용이
django-ninja ->
djangorestframework의 느린 serializer 대신 pydantic 사용
swagger 지원 POSTMAN 같은것
Async 지원
api version 지원
django-seed -> db에 임시 데이터 뿌려줌
INSTALLED_APPS “django_seed”
cmd: python manage.py seed <app_name> --number=<num>
서버 기본 세팅
{% highlight shell %}
프로젝트 생성 구문
django-admin startproject
프로젝프 앱 생성 구문
cd
python /manage.py startapp
프로젝프 슈퍼 유저 생성
python /manage.py createsuperuser
프로젝프 기본 마이그레이션
python /manage.py migrate
프로젝프 추가 제작한 마이그레이션
(오류발생시 setting.py -> INSTALLED_APPS에 추가)
python /manage.py makemigrations
서버 구동 구문
python \manage.py runserver
{% endhighlight %}
유저 테이블 제작(models)
커스텀 유저 테이블을 제작하는데 있어서 직접 제작이 가능하며 아래의 방법들이 있다.
추상화 유저 제작
{% highlight python %}
from django.contrib.auth.models import AbstractUser
class Users(AbstractUser):
pay_plan = models.ForeignKey(PayPlan, on_delete=models.DO_NOTHING)
{% endhighlight %}
setting.py에 AUTH_USER_MODEL = ‘<app_name>.Users’ 추가해야함
장고 모듈 활용 유저 제작
{% highlight python %}
from django.contrib.auth.models import User as U
class UserDetail(models.Model):
user = models.OneToOneField(U, on_delete=models.CASCADE)
pay_plan = models.ForeignKey(PayPlan, on_delete=models.DO_NOTHING)
{% endhighlight %}
두개를 모두 사용할 경우 oneToOneField의 입력이 추상화의 Users를 가르켜야한다.
view_html
urls.py
url 패턴을 이용하여 입력받는 주소로 부터 사용할 view단과 연결을 해준다.
{% highlight python %}
from app_test.views import index, redirect_test
urlpatterns = [
path(‘’, index , name=’index’),
path(‘redirect’, redirect_test),
]
{% endhighlight %}
view.py
urls.py에 연결된 view단을 세팅하는 부분
base.html과 같은경우는 <app_name>/templates 폴더에 둔다.
{% highlight python %}
모델(DB)에서 참조할시 해당 모델 추가사항
from .models import Users
모델에서 유저정보를 받아서 보여지는 결과를 다르게 한 예시
def index(request):
user = Users.objects.filter(username=”admin”).first()
email = user.email if user else “Nooooo”
print(email)
print(request.user.is_authenticated)
if not request.user.is_authenticated:
email = “NOoooooooooooooo”
print(email)
return render(request, “base.html”, {“welcome_msg”: f”Hello {email}”})
재참조 형식의 view단 예시
def redirect_test(request):
return redirect(“index”)
{% endhighlight %}
view_restAPI
urls.py
url 패턴을 이용하여 입력받는 주소로 부터 사용할 view단과 연결을 해준다.
<int:user_id>는 query string 사용법
{% highlight python %}
urlpatterns = [
path(‘get_user/', get_user),
]
{% endhighlight %}
view.py
urls.py에 연결된 view단을 세팅하는 부분
csrf_exempt는 token 인증을 임시로 풀기위한것
body가 아닌 JsonResponse는 보통 개발자들끼리 내용을 주고 받을때 사용하기도 한다.
{% highlight python %}
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def get_user(request, user_id):
print(user_id)
if request.method == “GET”:
abc = request.GET.get(“abc”)
xyz = request.GET.get(“xyz”)
user = Users.objects.filter(pk=user_id).first()
return render (request, “base.html”, {“user”: user, “params”: [abc, xyz]})
elif request.method == “POST”:
username = request.GET.get(“username”)
if username:
user = Users.objects.filter(pk=user_id).update(username=username)
return JsonResponse(status=201, data=dict(msg=”POST is”))
{% endhighlight %}
admin_handling1
admin.py
admin page에서 model을 핸들링 가능하게 해준다.
{% highlight python %}
from .models import PayPlan
Register your models here.
admin.site.register(PayPlan)
{% endhighlight %}
django original login setting
urls.py 세팅
views.py
{% highlight python %}
from django.contrib.auth import authenticate, login
from .forms import RegisterForm
def register(request):
if request.method == “POST”:
form = RegisterForm(request.POST)
msg = “not valid data”
if form.is_valid():
form.save() # db에 저장(commit=False로 임시저장가능)
username = form.cleaned_data.get(“username”)
raw_password = form.cleaned_data.get(“password1”)
user = authenticate(username= username, password= raw_password) # 인증
login(request, user) # 로그인
msg = “login”
return render(request, “register.html”, {“form”: form, “msg”: msg})
else:
form = RegisterForm()
return render(request, “register.html”, {“form”: form})
{% endhighlight %}
forms.py
{% highlight python %}
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import Users
class RegisterForm(UserCreationForm):
username = forms.CharField(max_length=20, required=True, help_text=”name”, label=”이름”)
email = forms.EmailField(max_length=20, required=False, help_text=”email”, label=”이메일”)
class Meta:
model = Users
fields = (
"username",
"email",
"password1",
"password2",
) {% endhighlight %}
paginator
views.py
페이지 분할 제작법
{% highlight python %}
from django.core.paginator import Paginator
def a(request):
page = int(request.GET.get(“page”, 1))
= <>.objects.all().order_by("-id") # 정렬해야 "-"내림차순
paginator = Paginator(, 5)
= paginator.get_page(page)
return render(request, ".html", {"args": <datas>}) {% endhighlight %}
login_required
setting.py
LOGIN_URL =”/<>”
views.py
로그인 필수 페이지 세팅
{% highlight python %}
from django.contrib.auth.decorators import login_required
@login_required
def a(request):
{% endhighlight %}
template tags
탬플렛을 제작하는데 있어서 조건이나 데이터 활용등을 위한 태그
{\% csrf_token \%}
csrf token을 필요로 하다는것을 나타낼때 사용
{\% cycle “a” “b” \%}
iter적인 상황에서 각 순서마다 서로 다른 영향을 주려고 할때 사용
{\% extends “.html" \%}
한 html에서 다른 html을 확장하여 사용할때 사용
자식페이지에 최상단에 필요하며 은 부모파일이다.
{\% block \%} {\% endblock \%}
한 html에서 다른 html을 확장하여 사용할때 사용
부모페이지에서 자식을 넣을공간에, 자식페이지에서 넣을 내용을 감싼다.
{\% if \%}{\% elsif \%}{\% else \%}{\% endif \%}
조건문을 사용할때 사용
{\% for i in items \%}{\% endfor \%}
for문을 사용할때 사용
forloop.counter 루프의 인덱스(1시작)
forloop.counter0 루프의 인덱스(0시작)
forloop.first 루프의 첫번째 True
forloop.last 루프의 마지막 True
{\% includes “<filename>.html” \%}
html에서 html 파일을 사용할때 사용할 <filename>을 작성
extends보다 느리다.(랜더링이 느리다.)
{\% url “<namespace>” \%}
<namespace>로 이동하게 할때 사용
{\% static “<filepath>” \%}
<filepath>에 있는 static 파일 사용
<app_name>/static/<filepath>으로 구성
{\% load static \%}을 최상단에 작성해야함
custom tags
탬플렛을 제작하는데 있어서
<app_name>/templatetags/custom_tags.py
{% highlight python %}
from django import template
from django.utils.html import mark_safe
register = template.Library()
@register.simple_tag(name=, takes_context=True)
def tags_test(context): # context에는 해당 페이지 정보가 있으며 상세히 다룰 수 있다.
tag_html = "태그"
# mark_safe는 html로 사용해도 안전함을 알려줌 사용안하면 string으로 사용
return mark_safe(tag_html) {% endhighlight %}
{\% load custom_tags \%}
태그 사용할 html 최상단에 적용
{{data|<tag_name>}}
태그 사용할 html 코드에 사용
custom filter
탬플렛을 제작하는데 있어서 원하는 내용만 보여주기 위하여 사용
<app_name>/templatetags/custom_filters.py
{% highlight python %}
from django import template
register = template.Library()
@register.filter(name=)
def email_masker(value):
email_split = value.split("@")
return f"{email_split[0]}@******.***"
{% endhighlight %}
{\% load custom_filters \%}
필터 사용할 html 최상단에 적용
{{data|<filter_name>}}
필터 사용할 html 코드에 사용
-
고급 활용
삼항연산자
단순 True or False 인 상황에서 가독성을 높이는데 좋음
{% highlight python %}
if :
else:
----------------
if else
{% endhighlight %}
# **리스트 컴프리헨션(list comprehension)**
---
리스트를 만드는데 있어서 효과적으로 제작하는방법
{% highlight python %}
list1 = []
for i in range(1, 11):
list1.append(i)
----------------
list1 = [i for i in range(1, 11)]
{% endhighlight %}
# **삼항연산자 & 리스트 컴프리헨션**
---
{% highlight python %}
= [ for in if ]
{% endhighlight %}
# **딕셔너리형 합치기**
---
{% highlight python %}
= {'am': 10}
= {"a": 20, "b": 50}
.update()
----------------
= {'am': 10}
= {"a": 20, "b": 50}
= {**, **}
{% endhighlight %}
# **정규표현식**
---
[참고사이트](https://regexr.com/)
{% highlight python %}
import re
{% endhighlight %}
re.match(\<str\>, \<data\>) 문자열 처음부터 검색(객체)
re.search(\<str\>, \<data\>) 문자열 전체 검색(객체)
re.findall(\<str\>, \<data\>) 문자열 전체를 검색(list형)
re.finditer(\<str\>, \<data\>) 문자열 전체를 검색(iter형)(객체)
re.fullmatch(\<str\>, \<data\>) 완벽한 일치하는 검색(객체)
\<object\>.group() 객체에서 매칭된 문자열을 반환
\<object\>.start() 객체에서 매칭된 문자열의 시작 위치
\<object\>.end() 객체에서 매칭된 문자열의 끝 위치
\<object\>.span() 객체에서 매칭된 문자열의 시작과 끝(tuple형)
re.sub(\<from\>, \<to\>, \<data\>) data에서 \<from\>을 \<to\>로 변환
PYTHON
/
Basic
· 2023-08-24
-
-
-
라이브러리 이해
라이브러리
인코딩(encoding) & 디코딩(decoding)
인코딩(encoding)은 사람이 인지하거나 사용하는 데이터를 컴퓨터가 인지하고 사용하는 0,1의 데이터로 변경하는 과정을 칭한다.
$e.x.,\;$ ASCII, Base64, unicode
{% highlight python %}
data.encode(‘utf-8’)
b.’xxx’ 처럼 byte형식으로 변경이된다.
{% endhighlight %}
디코딩(decoding)은 컴퓨터가 인지하고 사용하는 0,1의 데이터를 사람이 인지하거나 사용하는 데이터로 변경하는 과정을 칭한다.
{% highlight python %}
data.decode(‘utf-8’)
byte형식이 기존의 코드로 변경이된다.
{% endhighlight %}
python은 utf-8(3.x) ASCII(2.x)을 기본 인코딩으로 사용한다.
{% highlight python %}
디폴트 인코딩을 따르지만 선언시 선언한 형식으로 인코딩한다
-- coding: utf-8 --
data = “hello world”
{% endhighlight %}
인코딩과 디코딩은 서로 다른 형식으로 변환을 할경우 에러를 유발한다.
클로저(closure) & 데코레이터(decorator)
클로저(closure)는 함수안의 함수를 결과로 반환할때 출력되는 함수를 클로저 라고 부른다. 클로저는 아래와 같은 경우에 사용한다.
콜백함수
함수 실행 순서 조정
데코레이터 함수
{% highlight python %}
def func1():
def func2():
return
return func2
if name==”main”:
data1 = func1()
real_data = data1() #클로저 사용법
{% endhighlight %}
데코레이터(decorator)는 함수를 인수로 받는 클로저를 의미하며, 함수를 꾸며주는 함수로 어노테이션으로 @를 사용해서 표현이 가능하다.
{% highlight python %}
def func3()
return
def func1(func3):
def func2():
func3()
return
return func2
data1 = func1(func3)
real_data = data1()
—————————#same
def func1(func3):
def func2():
func3()
return
return func2
@func1
def func3()
return
real_data = func3()
{% endhighlight %}
이터레이터(iterator) & 제너레이터(generator)
이터레이터(iterator)는 for문과 같이 순차적으로 사용할 수 있는 객체를 의미하며 한번 사용시 재사용할 수 없다.
iter()를 이용하여 반복 객체 생성
next()를 이용하여 객체에서 각각 다음값을 추출
{% highlight python %}
list1 = []
iterator = iter(list1)
next(iterator)
next(iterator)
…
{% endhighlight %}
제너레이터(generator)는 이터레이터를 생성하는 함수로 함수의 출력이 순차적으로 다른 값을 출력하기 원할때 사용한다.
{% highlight python %}
def generator():
yield ‘a’
yield ‘b’
yield ‘c’
gen = generator()
next(gen)
next(gen)
…
{% endhighlight %}
타입 어노테이션(type annotaion)
타입 어노테이션(type annotaion)은 각변수의 자료형을 적시하는 것으로 에러의 가능성을 감소시키고, 코드의 가독성과 협업의 효율성을 위하여 사용한다.
{% highlight python %}
def func(data1: , data2: ) ->
func__annotations__
#{data1: int, ‘data2’: int, ‘return’: int }
{% endhighlight %}
문자열 처리
문자열을 처리하는 방식으로는 str(), repr() 두가지가 있으며 아래의 특징을 가진다.
str() : 사용자 인터페이스 문자열
repr() : 프로그램 인터페이스 문자열
{% highlight python %}
data = repr(“hello world”)
eval(data) #프로그램에서 다시 사용가능한 형태로 변형
{% endhighlight %}
외부라이브러리 사용
pip 라이브러리 매니저
{% highlight shell %}
pip install
pip uninstall
pip install <pkg==version> 버전별 설치
pip install —upgrade 업그레이드
pip list
pip list —format=freeze > requirements.txt 리스트 파일로 저장
pip install -r requirements.txt 리스트 설치
{% endhighlight %}
PYTHON
/
Basic
· 2023-08-21
-
-
-
-
클래스
클래스
클래스(class)는 각각의 개념화된 사물들을 객체화(object) 할 수 있고 이러한 객체들이 속성을 공유하는 방식을 지칭한다. 클래스 또한 함수와 같이 재사용성에 있어서 효과적이고, 유지보수에 유용하다. 클래스는 아래의 특징을 가진다.
상속(inheritace) : 상위의 개념과 하위의 개념간에 개념을 상속해주고 계승하는것을 의미한다. 상위의 개념은 superclass, 하위의 개념은 subclass라고 칭한다. e.x. 포유류(superclass) 고양이, 삵(subclass)
다양성(polymorphism) : 하위의 개념들이 상위의 개념에서 받은 개념 이외에 다양성을 가지는 것을 의미한다. e.x. 상위 개념(짖는다) 하위개념 (왈왈, 짹짹)
추상화(abstraction) : 클래스의 내부를 보지 않아도 내부의 변수와 같은것들을 보지 않아도 알수 있는것을 의미한다.
은닉화(encapsulation) : 클래스 내부에 변수(class variable) 기능(class method)을 가지게 되는것을 의미한다.
클래스가 사용하는 메서드는 다음과 같이 나눠질 수 있다.
인스턴스 메서드 : 첫번째 파라미터로 self를 가진다.
클래스 메서드 : 클래스의 속성에 접근하는것으로 cls파라미터 사용
정적 메서드 : 메서드가 인스턴스와 독립적으로 사용될때 사용
매직 메서드 :
클래스는 생성자(constructor)(init)를 이용하여 기본형을 정의한다.
(str)은 문자열화를 하여 서로 다른 객체 간의 정보를 전달하는 데 사용된다.
(repr)은 인간이 이해할 수 있는 표현으로 나타내기 위한 것입니다.
우선 순위는 __str__이 __repr__보다 높다.
추상 메서드 : 자식 class에서 필수적으로 구현해야하는 것을 지정
각각의 매서드들은 아래와 같이 사용이된다.
{% highlight python %}
class ():
data0 = 0
def __init__(self, data1, data2):
self.data1 = data1
...
def instance_method1(self, data3, data4): # 인스턴스
action
return 0
@classmethod
def class_method1(cls): # 클래스
print(f”{cls.data0}”)
@staticmethod
def static_method1(): # 정적
return
def str(self) -> str: # 매직
return f””
def repr(self) -> str:
return f””
@abstractmethod
def abstract_method1(self): # 추상
pass
{% endhighlight %}
클래스의 속성은 다음과 같이 구분을 할 수 있다.
각 객체의 속성
{% highlight python %}
class ():
def __init__(self, data1):
self.data1 = data1 # 각 객체의 속성
{% endhighlight %}
모든 객체가 공유하는 속성
{% highlight python %}
class ():
data0 = 0
def __init__(self, data1):
self.data1 = data1
.data0 += 1 # 모든 객체가 공유하는 속성
{% endhighlight %}
클래스 내부에서만 접근 가능한 속성(네임 맹글링(name mangling) 을 이용하여 변경은 가능)
{% highlight python %}
class ():
def __init__(self, data1):
self.__data1 = data1 # 불변 속성
.___data1 = "x" # 네임 맹글링 하는법
{% endhighlight %}
docstring은 모듈, 함수, 클래스 또는 메소드 정의의 첫 번째에 오는 문자열으로 해당 객체의 doc 속성으로 사용됨.
{% highlight python %}
class ():
"""
문서화 자료 입력
"""
def __init__(self, data1):
{% endhighlight %}
PYTHON
/
Basic
· 2023-08-15
-
함수
함수
함수에는 입력과 출력이 존재하며, 입력을 받아서 함수가 가공후 출력을 하는것이 일반적인 형태이다. 어떠한 반복적인 활동(재생산성)이 필요할때 코드의 간편화를 위해 사용이된다. 코드를 함수화 하면 가독성이 증가하는 장점이 있음
{% highlight python %}
def name(input):
action1
action2
return output
var3 = name(var1, var2)
{% endhighlight %}
인수(arguments)는 함수 호출시 전달하는 입력값은 지칭한다.
매개변수(parameter) : 매개변수는 함수에서 input을 의미한다.
디폴트 매개변수 : 매개변수에 디폴트값(초기값)을 설정해 줄수 있다. 매개변수가 여러개일때 디폴트값을 뒤에서 부터 작성
{% highlight python %}
def name(var1, var2=’data2’):
action1
action2
return output
{% endhighlight %}
가변 매개변수 : 매개변수를 여러개 사용할때 (*)을 이용하여 튜플화 하여 불러올 수 있다. 가변 매개변수 뒤에는 일반 매개변수가 올수 없음
{% highlight python %}
def name(var1, *vars): # vars = [‘data2’,’data3’]
action1
return output
name(‘data1’, ‘data2’,’data3’)
{% endhighlight %}
키워드 매개변수 : 매개변수에 값을 넣을때 순서대로 입력을 받는데 키워드를 이용하면 순서와 상관없이 값을 넣을 수 있게된다.
{% highlight python %}
def name(var1, var2):
action1
return output
name(var1 = ‘data1’, var2 = ‘data2’)
{% endhighlight %}
키워드 가변 매개변수 : 키워드 매개변수를 여러개 사용할때 (**)을 이용하여 딕셔너리화 하여 불러올 수 있다.
{% highlight python %}
def name(**vars): # vars = {‘var1’:’data1’, ‘var2’:’data3’}
action1
return output
name(var1 = ‘data1’, var2 = ‘data2’)
{% endhighlight %}
지역변수(local variable)와 전역변수(global variable) : 함수를 사용하게 되면 주의해야하는 것중에 하나가 지역변수와 전역변수의 혼동을 막는것이다. 지역변수는 해당함수에서 사용이 되는 변수를 의미하고 전역변수는 함수의 내외 적으로 사용이 되는 변수를 의미한다.
{% highlight python %}
data2 = ‘value2’
data4 = ‘value4’
def func(data1, data2):
data3 = ‘value3’ # local variable
global data4 # global variable
print(data4) # value4
data2 = ‘value5’
data2는 인수를 받아서 지역변수화 된것을 활용하기에
전역변수인 data2는 변화없이 함수안에서만 value5로 작용
func(‘value1’,data2)
{% endhighlight %}
람다 함수(lambda function)
람다함수는 간단한 함수를 작성할때 사용이된다. 아래는 일반 함수를 람다 함수로 표현한 것이다.
{% highlight python %}
def add(a, b):
return a+b
add = lambda a, b : a + b
———————————– level up
lambda a : True if else False
{% endhighlight %}
map 함수
순서가 있는 자료형의 원소를 순차적으로 함수에서 활용하는 함수이다.
{% highlight python %}
list1 = [1,2]
def func1(data):
return data+1
data = map(func1 ,list1) # map object type
list(data) # type conversion
{% endhighlight %}
filter 함수
순서가 있는 자료형의 원소들에서 원하는 항목을 추출하는 함수이다.
{% highlight python %}
list1 = [1,2]
def func1(data):
return data > 1
data = filter(func1 ,list1) # filter object type
list(data) # type conversion
{% endhighlight %}
reduce 함수
순서가 있는 자료형의 원소들의 스택을 쌓는 함수이다.
{% highlight python %}
from functools import reduce
list1 = [1,2,3,4,5]
def func1(data1, data2):
return data1+ data2
data = reduce(func1 ,list1) # reduce object type
{% endhighlight %}
PYTHON
/
Basic
· 2023-08-14
-
입출력과 제어문
입출력
사용자 입력 및 출력
사용자 입력은 input() 함수를 이용하여 사용자로부터 문자열 자료형 데이터를 입력받는것이다. ()안에 작성하는 내용을 “프롬프트 문자열”이라고 한다.
사용자 출력은 print() 함수를 이용하여 자료형을 출력한다.
(+)를 이용하여 문자열을 더할 수 있다. (+)는 생략가능.
(,)를 이용하여 문자열을 띄워쓰기 가능하다.
파일 입력 및 출력
파일 입력은 open() 함수를 이용해서 파일을 열 수 있다.
{% highlight python %}
data = open(, )
{% endhighlight %}
mode의 종류는 아래와 같다.
write 모드는 파일을 작성하는 방법으로 아래와 같다.
{% highlight python %}
data = open(,"w") #path = D:/mydesk/a.txt or a.txt
data.write("Hello world")
data.close()
with open() as data:
# context manager(수행 방법을 기억하고 있는 방식)
# 기본적으로 사용하는 함수를 with문 안에 사용하면 되며
# with문을 나올 때 close를 자동으로 불러줍니다.
data.write("Hello world")
{% endhighlight %}
append 모드는 파일을 이어서 작성하는 방법으로 아래와 같다.
{% highlight python %}
data = open(,"a")
data.write("Hello world2")
data.close()
{% endhighlight %}
read 모드는 파일을 읽는 방법으로 아래와 같다.
readline() : 파일을 한줄씩 읽기(\n도 불려짐)
readlines() : 파일을 한번에 읽어서 리스트로 출력(\n도 불려짐)
strip() : 줄바꿈 문자(\n) 제거
{% highlight python %}
data = open(,"r")
for i in len(Data.readlines()):
text = data.readline().strip()
print(text)
list_data = []
with open(,"r") as data:
for text in list_data:
list_data.append(text.strip())
{% endhighlight %}
xb모드는 binay형식으로 사용할경우 wb, rb와 같이 사용한다.
제어문
if문
아래와 같은 형식이 가장 기본적인 형식이며 다양한 state에서 어떻게 action이 가해지는지에 대한 제어문이다.
{% highlight python %}
if state1:
action1
elif state2:
action2
else:
action3
{% endhighlight %}
in / not in 연산자는 데이터 안에 있는지 없는지를 구별하는 연산자로 아래와 같이 작용한다.
{% highlight python %}
if ‘a’ not in ‘state’:
action1
else:
action2
{% endhighlight %}
pass 키워드는 조건에 해당하지만 어떠한 액션도 없이 넘기고 싶을때 사용을 하며, 개발자들 사이에서는 추후에 작업을 하기위해 사용하기도 한다.
{% highlight python %}
if ‘a’ not in ‘state’:
pass
else:
action2
{% endhighlight %}
관계 & 논리 연산자
관계 연산자는 a, b의 관계를 알아보기 위한 연산자로 True / False로 값이 나오게 된다.
==(같음)
!=(다름)
<(오른쪽이 큼)
>(왼쪽이 큼)
<=(오른쪽이 크거나 같음)
>=(왼쪽이 크거나 같음)
논리 연산자는 논리적으로 참과 거짓을 나타내는 연산자로 True / False로 값이 나오게 된다.
not(부정)
and(논리 곱)
or(논리 합)
while & for문
loop case는 리스트 형과 같이 루프를 가질 수있는 형식들은 다음과 같다.
문자열 : 문자열은 리스트와 같이 각 문자들을 변수로 사용가능하다.
range() : 범위를 생성해주는 함수. (출력시 range()로 나오며 list()함수로 가시화 가능)
range(n)은 0~n-1의 정수 집합이다.
range(i,n)은 i~n-1의 정수 집합이다.
range(i,k,n)은 i~k-1까지 n의 차
for문은 아래와 같이 ~에서 반복이 될때 사용하는것으로 in에 해당하는 내용이 끝날때 까지 반복이된다. 특이점 중 하나는 딕셔너리형식을 반복할경우 변수로 key값이 도출된다.
{% highlight python %}
for var in list(‘or other loop case’):
action
{% endhighlight %}
while문 : 어떠한 조건이 있을때 조건에 해당하면 반복하는 반복문으로 아래와 같이 사용된다. 일명 무한 루프라고 하며 조건에서 탈출 할 수 없을경우 심각한 오류를 발생할 수 있음
{% highlight python %}
while state:
action1
action2
{% endhighlight %}
break 키워드는 반복문을 탈출 할때 사용이 되는 키워드로 무한 루프와 같은 에러발생이 의심되면 사용가능하다.
continue 키워드는 반복문에서 다음액션을 무시하고 처음부터 다시 시작하고 싶을때 사용이 가능하다.
PYTHON
/
Basic
· 2023-08-11
-
변수와 자료형
변수(variable)
어떠한 값을 담는 저장공간과 그것을 부르는 명칭으로 다음과 같은 규칙이 존재한다.
영문자, _로 시작을해야함
대소문자를 구분함
특수문자 사용불가능
공백이 존재할 수 없음
파이썬의 예약어(if else …) 사용불가능
변수에는 문자, 숫자, 데이터타입등을 선언할 수 있음. 변수를 선언하면 임의의 메모리와 주소를 할당함.
자료형(datatype)
사용자의 데이터를 프로그래밍 언어가 이해가능한 형식으로 정의 하는것을 일컬으며, 프로그램에서 저장하는 데이터의 타입으로 다음과 같은 형식들이 있다.
NoneType : 어디에도 속하지 않는 해석불가능 타입
숫자(numeric)
정수(integral)
정수(int) : -1,0,1,…
부울(bool) : 참과 거짓을 나타내는 자료형
실수(float) : 1.04
복소수(complex) : 1+5i
수열(sequence)
불변(immutable)
문자열(str) : 문자들의 집합
튜플(tuple) : 순서를 가지는 집합으로 ()으로 구성이됨
바이트(bytes) : 바이트 나열 타입 e.x. b’0’ == b’\x00’
변형(mutable)
리스트(list) : 순서를 가지는 집합으로 []으로 구성이됨
비트어레이(byte arrays) : 변형가능한 바이트 나열 타입
매칭(mapping)
딕셔너리 : 순서를 가지지 않은 집합으로 {}으로 구성되며 key와 value 쌍으로 구성이된다.
집합 : 중복이 없고 순서를 가지지 않는 객체의 모음
집합(set) : 중복이 없고 순서를 가지지 않는 객체의 모음
정적집합(frozen set) : 집합과 같지만 변형이 불가능
숫자형
숫자를 나타내는 형식으로 아래와 같다.
정수 : 소숫점이 없는 숫자
실수, 부동 소숫점 : 소숫점이 있는 숫자
숫자연산은 사칙연산, 나머지(%), 몫(//), 제곱(**)으로 구성된다.
숫자형변환은 문자형의 숫자, 형식이 다른 숫자형들 사이의 변환을 지원한다. $e.x., \;$ int(), float()
문자열 자료형
문자를 나타내는 형식으로 아래와 같은 방식을 따른다.
큰 따옴표, 작은 따옴표로 문자열 만들기
문자열 내부에 따옴표 넣기
이스케이프 문자를 사용해 문자열 만들기 e.x.) \n \t …
여러줄 문자열 만들기 e.x.)
줄바꿈 없이 문자열 만들기
문자열도 숫자열 처럼 연산이 가능해진다.
(+)연산자는 문자열을 더함
(*)연산자는 문자열을 반복함
문자열은 숫자열과 다르게 각각의 문자가 독립적으로 구성이 되는데 이에 따라서 인덱싱(열 내부의 값을 지정) 과 슬라이싱(문자열의 범위 선택)이 아래와 같이 가능하다.
([]) 문자 선택 연산자(넘버링을 통해서 순서대로 추출가능)
문자 선택 연산자를 이용하여 넘버링 하는것을 인덱스라고 한다.
순방향 인덱스는 0에서 부터 증가
역방향 인덱스는 -1에서 부터 감소
([:]) 문자 범위 선택 연산자
문자범위 선태가 전후에 인덱스를 이용하여 범위를 선택함
문자열에 다른 문자열과 숫자열을 넣으려고 할때 포멧에 맞춰서 넣어줘야 하며 포멧은 포멧팅은 여러 종류가 있다.
%포멧팅은 아래와 같다.
%d : 정수형 대입
%f : 실수형 대입
%s : 문자열 대입
%c : 문자 대입
%o : 8진수
%x : 16진수
{% highlight python %}
data = “hello %s world %d” %(“to this”, 10)
{% endhighlight %}
.format()포멧팅은 아래와 같다.
{% highlight python %}
data = “hello {0} world {1}”.format(“to this”, 10)
{% endhighlight %}
.f string 포멧팅은 아래와 같다.
{% highlight python %}
data = f”hello world "
{% endhighlight %}
---
문자열을 사용함에 있어서 주로 사용되는 함수는 아래와 같다.
.len() : 문자열 길이 출력
.split(’.’) : 문자열 나누기
.count() : 문자 갯수 세기
.replace(’a’,’b’) : 문자열 바꾸기
.find(’a’) : 문자열 인덱싱 찾기
.upper() : 문자열 대문자로 변경
.lower() : 문자열 소문자로 변경
‘a’.join(x) : 문자열 삽입 (x문자열의 문자사이에 a넣기)
리스트 자료형
([])의 내부에 요소들을 넣는 자료형을 지칭하며 ‘,’으로 구분되며 여러가지 자료형을 담을 수 있다.
리스트도 문자열과 같은 연산이 가능하다.
리스트형도 문자열 처럼 인덱싱과 슬라이싱이 가능하다.
리스트는 인덱싱 또는 슬라이싱을 기반으로 하여 내부의 요소들을 아래와 같이 변경 또는 삭제가 가능하다.
List[1] = ‘b’ : 리스트의 두번째 요소를 ‘b’로 변경
List[1:3] = [’a’,’b’] : 리스트의 두번째, 세번째 요소를 ‘a’,‘b’로 변경
del List[n] = 리스트 n+1번째 요소 삭제
리스트 자료형을 사용함에 있어서 주로 사용되는 함수는 아래와 같다.
len(List[]) : 리스트 길이 출력
.sort() : 리스트 정렬
.reverse() : 리스트 뒤집기
.append(x) : 리스트 뒤에 요소 추가
.extend([]) : 리스트 확장
.insert(n,’a’) : n+1번째에 ‘a’삽입
.remove(n) : 리스트 n+1번째 요소 제거
.pop(n) : 리스트 n+1번째 요소 꺼내기(꺼낸 요소는 삭제됨)
.count(x) : 리스트에 포함된 ‘x’의 갯수 확인
튜플 자료형
(())의 내부에 요소들을 넣는 자료형을 지칭하며 ‘,’으로 구분되며 여러가지 자료형을 담을 수 있다. 리스트와 다른점은 내부의 데이터가 수정 및 삭제가 안되는것이다.
특이점으로는 하나의 요소를 사용할때는 마지막에 (,)가 필요하고, (()) 없이도 튜플로 사용이 가능한것이다.
튜플도 리스트와 같은 연산이 가능하다.
튜플도 리스트형 처럼 인덱싱과 슬라이싱이 가능하다.
딕셔너리 자료형
({})의 내부에 요소들을 넣는 자료형을 지칭하며 key, value로 구분되며 여러가지 자료형을 담을 수 있다. 리스트와 비교해보면 인덱스 대신 key를 사용한다. 딕셔너리에서 value를 추출하기 위해서는 Dic[’key’]와 같이 사용한다.
딕셔너리는 내부의 value를 변경과 삭제가 가능하다.
딕셔너리 자료형을 사용함에 있어서 주로 사용되는 함수는 아래와 같다.
.keys() : key값을 리스트로 만듬
.values() : value값을 리스트로 만듬
.items() : key,value 쌍 얻기
.get(key) : key로 value 얻기
‘key’ in Dic : key가 존재하는지 확인
.clear() : 딕셔너리 내부 삭제
집합 자료형
set()을 사용하는 비중복성 자료형이다. 명제의 집합과 같은 형태를 가진다.
집합은 다음과 같은 연산이 가능하다.
| (합집합) : 집합간의 합집합을 구한다.
& (교집합) : 집합간의 교집합을 구한다.
- (차집합) : 집합간의 차집합을 구한다.
집합 자료형을 사용함에 있어서 주로 사용되는 함수는 아래와 같다.
.add(’a’) : 한개의 값(’a’)을 추가
.update([]) : 여러개의 값([])을 추가
.remove(’a’) : 특정값(’a’) 삭제
부울 자료형
참과 거짓을 나타내는 자료형으로 조건형으로 사용된다. $e.x., \;$ “a” == “a”, bool(’’)⇒False, bool(’d’)⇒True
PYTHON
/
Basic
· 2023-08-10
-
-
-
About Data Structure
시간복잡도
알고리즘 로직에서 입력값이 전체 연산의 시간에 미치는 영향을 알기 위한 방법
big-O
상한 점근법으로 최대 걸리는 시간을 알 수 있다. 아래는 대표적인 시간이다.
$O(1)$ - 단일 작업
$O(n)$ - 입력에 대한 모든 작업
$O(n^2)$ - 입력에 대한 모든 작업의 재반복
$O(log(n))$ - 입력에서 이진 탐색하는 방법
big-omega
하한 점근법으로 최선의 경우에서 시간을 알 수 있다.
big-theta
상*하한 점근법의 평균
list
LIFO(last in first out) 모델
static list
일반적인 정적 리스트 범위를 미리 지정하고 넘어가면 추가 할당함
linked list
리스트 요소마다 연결되는 형식 처럼 제작한 리스트
{% highlight python %}
from collections import deque
queue = deque()
{% endhighlight %}
stack
LIFO(last in first out) 모델
push()
데이터 입력
pop()
데이터 출력(+삭제)
top(), peek()
데이터 출력
Queue
FIFO(first in first out) 모델
push(), offer(), add()
데이터 입력
pop(), poll()
데이터 출력(+삭제)
peek()
데이터 출력
hash(Dictionary,Set in python)
데이터를 빠르게 저장하고 가져오는 기법으로 key를 연산을 통해 value를 알 수 있다
sorting
정렬을 하는방법으로 동일한 값이 기존서순대로 나열 되는 stable sort와 그렇지 않은 unstable sort로 나뉘어진다.
binary search
정렬된 값에서 중앙값을 찾고 중앙을 기준으로 나눠서 유사한값이 해당하는 집합에서 다시 중앙값을 찾아 나가는 방법
bubble sort(stable)
순서대로 다음값과의 순서를 비교하여 정렬하는법 $O(n^2)$
insert sort(stable)
순서대로 다음값을 포함하여 포함한 집합에서 순서를 비교하여 정렬하는법 $O(n^2)$
merge sort(stable)
각 개별로 분할하고 다시 짝찌어 돌아가면서 정렬하는법 $O(n log(n))$
quick sort(unstable)
임의의 pivot값을 정하고 pivot보다 크거나 작은 값을 재배치하는것을 반복함 $O(n log(n))$ ~ $O(n^2)$
재귀함수
자기 자신을 재호출하여 사용하는 함수의 방식, 시스템 자원의 효율이 조금 떨어짐
base case, recurrence relation으로 이루어지며 base case로 모든 문제가 해결이 되어야한다.
tree
데이터의 계층적 구조를 나타내며 하나의 노드가 여러 노드들을 가르킬 수있습니다.
binary tree
트리 구조에서 자식 노드를 최대 두개까지 가지는 구조
tree search
preorder 방식
루트를 방문 후 왼쪽 자식 노드, 오른쪽 자식 노드 순으로 진행되며 자식 노드를 루트 노드화 하며 심층적 탐색을 한다.
inorder 방식
왼쪽 자식 노드를 가고 루트를 방문한 후 오른쪽 자식 노드로 이동하는 방법으로 자식 노드를 루트 노드화 하며 심층적 탐색을 한다.
postorder 방식
왼쪽 자식 노드를 가고 오른쪽 자식 노드로 이동한 다음 루트를 방문하는 방법으로 자식 노드를 루트 노드화 하며 심층적 탐색을 한다.
binary tree search
중복된 값이 없이 루트의 왼쪽에는 루트보다 작은값 오른쪽에는 루트보다 큰값으로 구성이된다.(중위 탐색 기법으로 구성)
데이터 삭제시 왼쪽의 최대값 또는 오른쪽의 최소값과 교체한다.
heap
완전 이진트리의 구조를 가지며 데이터 찾기$O(1)$와 추가,삭제$O(log(n))$가 빠르다.
max heap
루트 노드가 자식 노드보다 크거나 같음
min heap
루트 노드가 자식 노드보다 작거나 같음
priority queue
들어온 순서와 상관없이 우선 순위가 높은 데이터 순으로 처리
heapify(O(n))
데이터가 추가(O(logn)) 및 삭제(O(logn))될때 힙 구조를 유지하기 위한 로직
{% highlight python %}
import heapq
min_heap=[1,4,6,3,7,8,2]
heapq.heapify(min_heap)
heapq.heappop(min_heap)
heapq.heappush(min_heap)
{% endhighlight %}
graph
vertex(노드)와 edge(연결선)으로 구성이되며 2차원 행렬 관계도 또는 인접 리스트 관계도로 표현이 가능하다.
방향 그래프
edge에 방향성을 추가한 그래프
가중치 그래프
edge에 가중치를 추가한 그래프
순환 그래프
vertex에서 edge를 거쳐 되돌아 올 수 있는 방향 그래프
adjacency matrix(인접 행렬)
연결된 vertex는 1 연결이 안된 vertex는 0으로 나타내는 행렬(메모리 비효율)
adjacency list(인접 리스트)
연결된 vertex를 나열한 리스트를 모은 dictinary
implicit graph(암시적 그래프)
그래프 탐색
DFS(depth-first-search)
깊이 우선 탐색법으로 stack을 이용하거나 preorder inorder postorder를 사용 가능하다.
BFS(breadth-first-search)
너비 우선 탐색법으로 queue사용가능, 가까운것을 먼저 검색한다고 볼 수 있다.(이미 방문한 노드는 재진입 하지 않는다.)
위상정렬
비순환 그래프를 순서대로 출력하는 방법
Queue(진입 차수) 활용
진입 차수는 노드에 들어오는 edge의 수를 의미하며 진입 차수가 0인 노드들을 queue에 넣고 순차적으로 빼면서 연결된 edge를 제거하며 해당 노드를 넣는것을 반복한다.
stack(DFS) 활용
깊이가 깊은 곳부터 순차적으로 stack을 쌓고 모든 데이터가 전부 쌓이고 나면 추출하는 방식.
그래프의 최단거리
다익스트라(Dijkstra)
노드에서 노드끼리 최단 경로를 찾는 방법으로 edge의 가중치는 양수로 이루어 진다.
DP
동적 계산법으로 재귀함수에서 하위의 함수가 중복될때 사용
피보나치의 경우 $O(2^n)$에서 $O(n)$으로 감소
구하려는것부터 시작하는 top-down, 아는것 부터 시작하는 bottom-up방식이 있다.
cache
데이터를 임시로 저장하는 저장소
LRU(Least Recently Used)
가장 예전에 사용한 데이터를 삭제하는 방법
LFU(Least Frequently Used)
가장 사용빈도가 작은 데이터를 삭제하는 방법
-
-
모집단과 샘플링
모집단(population) 샘플링(sampling)
어떠한 정보를 구하려고 할때 해당 대상의 전체 집합을 모집단(population)이라고 하며 이러한 모집단에서 임의의 집합을 추출하면 이것을 샘플링(sampling)한다고 할 수있다.
이러한 샘플링에는 복원추출과 비복원추출이 있으며, 복원추출은 추출한 데이터를 포함하여 다시 추출하는것을 이르고 비복원추출은 추출한 데이터를 포함하지 않고 추출하는것이다.
샘플링 기법으로는 단순(simaple random), 층화(stratified), 계통(systematic), 군집(cluster) 샘플링이 대표적이다. 단순 샘플링은 랜덤하게 추출한것, 층화 샘플링은 그룹화된 모집단에서 균일한 갯수의 요소들을 추출한것, 계통 샘플링은 매 k번째 요소를 추출하는것, 군집 샘플링은 군집화된 집단들에서 몇개를 선택하는것이다.
모집단에서 영향받은 독립 분포(iid)(independent & identically distributed)
샘플의 이상적인 상황을 의미하며 iid일 경우 랜덤샘플 $X_1,…,X_k$, 모집단 $f(x: \theta)$ 이면 $X_1,…,X_k \overset {iid}{\sim} f(x: \theta)$으로 나타낼 수 있다.
랜덤샘플 $X_1,…,X_k$일때 $u(X_1,…,X_k)$를 통계량(statistic)으로 표기할 수 있다.
표본 변수(sample variable)와 불편향성(unbiased estimator)
모집단 $X \sim Bernoulli(p)$에서 $iid$ 랜덤샘플 $X_1,…,X_k$일때,
표본비율(sample rate) $\hat{P}:={1 \over n}(X_1+ \cdots + X_n)$,
표본평균(sample mean) $\bar{X} := {1 \over n} \sum_{i=1}^n X_i$
표본분산(sample variance) $S^2:={1 \over {n-1}} \sum_{i=1}^n{(X_i-\bar{X})^2}$
이 된다.
$X \sim (\mu , \sigma ^2) \rightarrow E(\bar{X})=\mu , \; E(S^2)=\sigma ^2$ 일때 $\bar{X}, \; S^2$을 불편향성(unbiased estimator)을 가진다고 한다.
MATH
/
Statistic
· 2023-08-03
-
표본분포
카이제곱분포($X^2$ distribution)
$k \in \mathbb{N}$이고 $Z_{11}^2, \cdots ,Z_{1k}^2 \overset{iid}{\sim} N(0,1)$ 일때 $X \sim X^2(k) \overset{def}{\leftrightarrow} X \overset{d}{\equiv} Z_{11}^2+ \cdots +Z_{1k}^2$를 카이제곱분포($X^2$ distribution)라고 부르며 $k$를 자유도(degree of freedom)이라고 부른다.
$X \sim X^2(k) \rightarrow E(X) =k, Var(X)=2k$ ( $\therefore k$가 커질 수록 그래프가 오른쪽으로 이동하며 평평해진다.)
$X_1,…,X_n \overset{iid}{\sim} N(\mu, \sigma ^2)$ 일때,
$\bar{X} \sim N(\mu, \sigma ^2 / n)$
$S^2=\sum(X_i-\bar{X})^2/(n-1)$ $in$ $\bar{X}$ : independent
${(n-1)S^2 \over {\sigma ^2}} \sim X^2(n-1)$
카이제곱 분포는 모집단의 분산을 추정하기 위해 사용한다.
t분포(t-distribution)
$Z \sim N(0,1), \; V \sim X^2(r), \; Z,V$: 독립적 일때, $X \overset{d}{\equiv} {Z \over {\sqrt{V/r}}} \sim t(r)$ 이다.
$X_1,…,Xn \overset{iid}{\sim} N(\mu,\sigma ^2) \rightarrow {\bar{X}-\mu \over {S/\sqrt{n}}} \sim t(n-1)$ (모표준편차를 표본표준편차로 대체하는것)
t분포는 표본의 크기가 작거나 모분산을 알 수 없을때(위와 같이 표준편차를 대체하여) 모집단의 평균은 측정할때 사용된다.
f분포(f-distribution)
$V_1 \sim X^2(r_1), \; V_2 \sim X^2(r_2), \; V_1,V_2$: 독립
$F \overset{d}{\equiv}{V_1/r_1 \over {V_2/r_2}} \sim F(r_1-1,r_2-1)$
두개 이상의 모집단의 분산비를 추론하여 비교할때 사용된다.
MATH
/
Statistic
· 2023-08-02
-
-
중심극한정리와 큰수의 법칙
중심극한정리(CLT)(central limit theorem)
$X_1,…,X_n \overset{iid}{\sim}(\mu,\sigma^2)$ 이면서, $n$이 충분히 크다면 표준정규분포를 따르는데 이것을 중심극한정리(CLT)(central limit theorem)라고 한다.
큰수의 법칙(LLN)(law of large numbers)
$X_1,…,X_n \overset{iid}{\sim}(\mu,\sigma^2)$ 일때, $\forall \epsilon > 0, \; \underset{n \rightarrow \infty}{\lim}P(|\bar{x_n}-\mu| < \epsilon)=1$ 즉, 시행횟수가 늘어나면 통계적 확률이 수학적 확률에 수렴할 확률이 1에 가까워 진다는 것으로 큰수의 법칙(LLN)(law of large numbers)이라고 불린다.
MATH
/
Statistic
· 2023-07-31
-
-
확률
표본공간(sample space)과 사건(event)
전체 공간의 부분집합을 사건(event)이라고 정의하고 전체 공간에서 관측 가능한 모든 집합을 표본공간(sample space)이라고 한다.
확률(probability)
표본공간에서 다음의 규칙들을 만족하는 것을 확률(probability) $P$라고 한다.
$P(S)=1$
$\forall \; event \; A \; on \; S$, $0 \leq P(A) \leq 1$(positive measure)
$A_1,A_2,… : event \; with \; A_i \cup A_j=\phi$(=mutually disjoint)
→ $P(A_1 \cup \cdots ) = P(A_1) +\cdots$
확률변수(random variable)
$X:S \rightarrow R$인 함수가 모든 출력을 포함하고 있으면 확률변수(random variable)라고 한다.
이산확률변수(discrete random variable)
확률변수는 크게 두종류로 나뉘어지며 countable 할 경우는 이산확률변수(discrete random variable)로 불려지며 확률을 계산을 할때 사용하는 확률밀도함수(probability density function)는
$f:X(X) \rightarrow [0,1]$, $f(x):=P(X=x)$
$P(a \leq X \leq b)= \underset{a\leq x \leq b}{\sum}f(x)$
로 나타낼 수있다.
연속확률변수(continuous random variable)과 연속균등분포(uniformdistribution)
uncountable할때는 연속확률변수(continuous random variable)로 불려지며 확률밀도함수는 $\int_a^bf(x)dx=P(a \leq X \leq b)$로 나타내진다.
연속확률변수가 균등한값을 가지게 되는 특이케이스를 연속균등분포(uniformdistribution)라고 부르며 다음과 같이 표기하기도한다. $-\infty < a < b < + \infty$, $f(x):=\begin{cases}
{1 \over {b-a}} \; if x\in[a,b] \
0 \; otherwise
\end{cases}$
확률에서의 변수들(variables in probability)
확률에서는 통계및 분석을 위해서 다양한 변수들을 구한다.
이산확률분포에서
기댓값(expectation)은 $E(X) = \mu :=\sum_x x\cdot f(x)$
분산(variance)은 $Var(X) :=E((x-\mu)^2) = E(X^2)-E(X)^2$
표준편차(standard deviation)는 $\sigma(X) := \sqrt{Var(X)}$
연속확률분포에서
기댓값은 $E(X) = \mu :=\int_{-\infty}^{+\infty} x\cdot f(x)dx$
분산은 $Var(X) :=\int_{-\infty}^{+\infty}(x-\mu)^2f(x)dx = E(X^2)-E(X)^2$
표준편차는 $\sigma(X) := \sqrt{Var(X)}$
확률분포(distributions)
베르누이 실행(bernoulli trial)
동전을 던져서 앞뒤를 확인 하는것처럼 단 1회의 기회에 참과 거짓이 있는것을 베르누이 실행(bernoulli trial)이라고 부른다.
이항분포(binomial distribution)
베르누이 실행과 같이 참과 거짓만 있는 분포도를 베르누이 분포(bernoulli distribution)라고 한다. 참과 거짓이 아닌 임의의 $p$확률과 $1-p$ 확률이 있을때 다회의 실행에서 나타내는 분포를 이항분포(binomial distribution)라고 부른다. 이는 $P(X=k)=
\begin{pmatrix}
n\
k
\end{pmatrix} \cdot p^k(1-p)^{n-k} (0 \leq k \leq n, k \leq \mathbb {Z})$로 표현되며 $X \sim B(n,p)$이다.
다항분포(multinomial distribution)
이항분포의 경우 두개의 경우에서만의 확률이라면 더많은 경우에서의 확률을 가질때는 다항분포(multinomical distribution)라고 칭하며 $n$번의 시행횟수, $k$개의 경우, 각확률이 $p_1,…,p_k$라고 할때, $P(X=(x_1,…,x_k))=
\begin{pmatrix}
n\
x_1,…,x_k
\end{pmatrix} \cdot p_1^{x_1} \cdots p_k^{x_k} (0 \leq k \leq n, k \leq \mathbb {Z}, p_i \in [0,1])$
표준정규분포(standard normal distribution)
$\phi(z):={1 \over \sqrt{2\pi}}e^{-{1 \over 2}z^2}$를 $pdf$로 가지는 확률분포를 표준정규분포(standard normal distribution)라고 부르며 $pdf$를 다음과 같이 $P(a \leq z \leq b)=\int_a^b \phi(z)dz, Z \sim N(0,1)$ 나타낸다.
정규분포(normal distribution) z-score
$\mu \in \mathbb{R}, \sigma > 0$이면서 ${1 \over \sigma}\phi({x-\mu \over \sigma})={1 \over \sqrt{2\pi}\sigma}e^{-{1 \over 2}({x-\mu \over \sigma})^2}$로 구성된 확률분포를 정규분포(normal distribution)라고 부르며 $pdf$를 다음과 같이 $P(a \leq x \leq b)=\int_a^b {1 \over \sigma}\phi({x-\mu \over \sigma})dx, X \sim N(\mu,\sigma^2)$ 나타낸다. 표준편차 $\sigma$에 해당되는 수치 별로 전체 데이터가 해당하는 비율을 알 수 있고 그것을 z점수(z-score)라고 부르며 $\sigma$에 해당하는 값을 68%, $2\sigma$에 해당하는 값을 95%라고 한다. 이와 같은 비율들로 이상치를 확인하기 쉬워진다.
푸아송분포(poisson distribution)
이항분포에서 시행 횟수가 무한히 클경우 계산하기 힘들어진다, 이때는 근사치를 이용하여 계산을 하는것이 비교적 쉬워지는데 이것을 푸아송근사 라고 칭하며 푸아송분포(poisson distribution)을 가지게 된다. $n \gg 1 \; \& \; p \ll 1$ s.t. $np_n \rightarrow \lambda \; as \; n \rightarrow \infty$ 일때 $pdf_X(x) ={n \choose x}p_n^x{(1-p_n)}^{n-x} \rightarrow {e^{-\lambda} \lambda^x \over x!} \; as \; n\rightarrow \infty$로 나타내진다. $X \sim Poisson(\lambda) \rightarrow E(X) =\lambda, \; Var(X)=\lambda$
MATH
/
Statistic
· 2023-07-26
-
-
-
-
선형성과 선형대수
선형대수학(linear algebra)
선형대수학(linear algebra)은 문자 그대로 연산의 선형성을 다루는것이다. 선형성을 따지기 위해서는 선형연산이 적용되는것을 확인해야한다.
선형연산(linear operations) 이항연산(binary operation)과 스칼라곱(scalar multiplication)
선형연산(linear operations)에는 이항연산(binary operation)과 스칼라곱(scalar multiplication)이 있으며, $V$가 비어있지 않은 집합일때 $\ast : V \times V \rightarrow V$이와 같은 상황에서 $V$에 대한 이항연산이라 부른다.
$\cdot : R \times V \rightarrow V$에서는 $V/R$에 대한 스칼라곱이라 부른다.
백터공간(vertor space)
위와 같은 선형연산을 가지는 집합을 백터공간(vertor space)라고 부고 여기에는 다음과 같은 규칙들이 있다.
$(v,t):abelian \;group$
$(v,t):group$
결합법칙(associativity) : $(v+w)+u=v+(w+u)$ for $v,w,u \in V$
항등원(identity) : $\exists 0_0 \in V$ s.t. $v+0_0=0_0+v=v$ in $\forall v \in V$
역원(inverse) : $\forall v \in V, \exists v^` \in V s.t. v+v^` =v^`+v=0$
교환법칙(commutative property) : $v+w=w+v$ for $w,v \in V$
분배법칙(distributivity) $ in \; a,b\in R \; v,w\in V$
$(a+b)v = av+bv$
$(ab)v = a(bv)$
$A(v+w)=av+aw$
$1 \cdot v =v$, $\forall v \in V$
선형사상(linear map)
두개의 백터공간이 입력과 출력이 되는 함수가 선형성을 가질경우 선형사상(linear map)이라 한다.
선형대수학의 기본정리(Fundamental Theorem of Linear Algebra, FTLA)
선형대수학의 기본정리(Fundamental Theorem of Linear Algebra, FTLA)에 따르면 선형사상과 행렬은 같은것으로 취급할 수있다.
MATH
/
Basic
· 2023-07-21
-
이항정리
팩토리얼(factorial)
1에서 부터 $n$까지의 숫자를 전부 곱하는것을 $n!$라고 표기할 수 있으며 이를 팩토리얼(factorial)이라고 한다. 수식을 정리하면
$n! := \underset{1 \leq m \leq n}{\prod} m = n \times (n-1) \times \cdots \times 2 \times 1$ 와 같다.
이항정리(binomical theorem) 이항계수(binomical coefficient)
두개의 항을 가진 이항식을 거듭제곱을 하는경우를 단항식으로 나열하는것을 이항정리(binomical theorem)라고 하며 수식으로는 ${(a+b)}^n = \underset{r=0}{\overset{n}{\sum}}{n \choose r}a^rb^{n-r}$ 와 같이 표현을 한다.
이항정리에서 사용하는 계수를 이항계수(binomical coefficient)라고 하며 다음과 같이 정의한다 . ${n \choose r} := { n! \over r!(n-r)!}$
다항정리(multinomical theorem) 다항계수(multinomical coefficient)
이항정리와 이항계수를 차수를 높여서 포면 고차항에서도 사용이 가능하며 이를 다항정리(multinomical theorem)와 다항계수(multinomical coefficient)라고 한다. 다항정리는 다음과 같이 표현하며
${(a_1+ \cdots +a_n)}^n = \underset{\underset{r_i \in N \cup {{0}}}{r_1+ \dots +r_k=1}}{\overset{n}{\sum}}{n \choose r_1, \cdots, r_k}a_1^{r1} \cdots a_k^{r_k}$
다항계수는 다음과 같이 표현한다.
${n \choose r_1, \cdots, r_k} := { n! \over (r_1, \dots , r_k)!}$
$\quad n, r_1, \cdots, r_k \in N \cup {{0}}, \overset {k}{\underset {i=1}{\sum}}r_i=n$
MATH
/
Basic
· 2023-07-20
-
-
함수
이진관계와(binary relation) 순서쌍(ordered pair)
집합 $A, B$가 있을때 $a \in A, \; b \in B$일경우 $A$에서 $B$로의 이진관계(binary relation)($R$)는 순서쌍(ordered pair) (a,b)로 이루어진 집합이며 $A \times B$의 부분집합이다.
함수(function)
$f \subset A \times B$이면서 $a \in A$와 매칭되는 유일한 $b \in B$를 가질경우 $f$를 $A$에서 $B$로 향하는 함수(function)라고 칭한다.
정의역(domain) 공역(codomain) 치역(range / image) 그래프(graph)
$(a,b) \in f$에서 $x \in A$의 경우 $A$를 정의역(domain)이라고 하고 $y \in B$의 경우 $B$를 공역(codomain)이라고 한다. $A$에서 $B$로 향하는 $f(A) := {{f(x) \; : \; x \in A}}$는 치역(range / image)이라고 한다.
$f: A \rightarrow B$에서 $G(f) := {{(x,f(x) \; : \; x \in A }} \subset A \times B$ 인 경우 $G$를 $f$의 그래프(graph)라고 한다.
단사(injective / one-to-one) 전사(surjective/ onto) 일대일대응(bijective / an one-to-one correspondence)
함수에는 다양한 형태의 함수가 있으며 $A$에서 $B$로 향하는 함수가 있을 경우 $A$의 원소가 유일 할경우 이를 단사(injective / one-to-one)라고 칭하며 아래와 같이 나타낸다.
$f(x_1)=f(x_2) \rightarrow x_1=x_2$
$i.e., \;$ $\forall y \in f(A), \exists! x \in A \; s.t. \; y=f(x)$
$B$의 원소가 모두 사용될경우 이를 전사(surjective/ onto)라고 칭하며 아래와 같이 나타낸다.
$f(A)=B$ i.e. $f(A) \supset B$
$i.e., \; $ $\forall y \in B, \exists x \in A \; s.t. \; y=f(x)$
단사와 전사가 한번에 적용이 될경우를 일대일대응(bijective / an one-to-one correspondence)이라고 칭하며 아래와 같이 나타낸다.
$\forall y \in B, \exists !x \in A \; s.t. \; y=f(x)$
역함수(inverse function) preimage(역상)
$y=f(x)$가 있을때 $f^{-1}(y)=x$로 사용한 함수를 $f^{-1} : B \rightarrow A$인 상태의 역함수(inverse function)라고 지칭한다.
역함수와 서로 오해하기 쉬운것으로 오해하지 말아야 하는것이 있는데 그것을 역함수이면서 일대일대응 인것을 preimage(역상)이라 하며 $f^{-1}(Q) := {{x \in A :f(x) \in Q }}$를 $f$에 대한 $Q$의 역상이라 한다.
이동(translation)
$f:R \cdots> R$인 함수에서 함수 $y = f(x)$에서 $y+b=f(x-a)$로 변환된다면 이를 $x$축에서 $a$만큼 이동(translation), $y$축에서 $b$만큼 이동한다고 볼 수 있다. 또한 $y=f(ax)$은 $x$축에서 $1\over a$만큼 팽창(expansion)하고 $y = af(x)$은 $y$축에서 $a$만큼 팽창한다고 볼 수 있다.
볼록함수(convexity)
함수의 경우 다양한 형태의 모양을 가지게 되는데 $f: R \cdots > R$, $x,y \in Dom(f) \; with \; x<y \; and \; t \in [0,1]$에서 $f(tx+(1-t)y) \leq tf(x)+(1-t)f(y)$일경우는 볼록형(convex) $f(tx+(1-t)y) \geq tf(x)+(1-t)f(y)$일경우는 오목형(concave)이다.
$e.g., \; $로그 그래프와 같은 형태를 오목형이라고 한다.
MATH
/
Basic
· 2023-07-18
-
-
-
-
-
Django unit test
What is serializer
test
test_base
normal serializer
일반적인 seriallizer는 serializers.Serializer의 상속을 받아 아래와 같이 작성하게 됩니다.
{% highlight python %}
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(required=False, allow_blank=True, max_length=10)
def create(self, validated_data):
return models.User.objects.create(**validated_data) {% endhighlight %}
위와 같은 방식은 model과 상관없이 serializer를 설정하고 싶을때 사용할 수 있으며, model을 활용하여 사용하는 방법도 있습니다.
model serializer
model seriallizer는 serializers.ModelSerializer의 상속을 받아 아래와 같이 작성하게 됩니다. 아래의 방식은 model이 선언되어 있을때 사용하기 용이하며 코드를 간편하게 해줍니다.
{% highlight python %}
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = [‘id’, ‘name’]
{% endhighlight %}
method field
method field는 다른 field를 활용하여 재가공하여 사용하는 방식입니다. 대표적으로 id값이 있고 id의 길이를 확인하는 방법입니다.
{% highlight python %}
class UserSerializer(serializers.ModelSerializer):
is_long = serializers.SerializerMethodField()
class Meta:
model = models.User
fields = ['id', 'name']
def get_is_long(self, instance: CheckedCrn):
if len(instance.id) > 2:
return "long"
else:
return "short" {% endhighlight %}
dict -> json -> dict
때에 따라서는 데이터의 형태가 계속 변경이 되어야 할 수 있습니다. 그에따라 형변환을 하는 법을 나타냅니다.
{% highlight python %}
import io
from rest_framework.renderers import JSONRenderer
content = JSONRenderer().render(serializer.data) # json
stream = io.BytesIO(content)
data = JSONParser().parse(stream)
serializer = UserSerializer(data=data)
serializer.is_valid()
serializer.validated_data # check data
serializer.save()
serializer.data # dict
{% endhighlight %}
nested serializer
N in (1:N)
1:N 의 형식에서 N의 입장은 다음과 같이 바로 활용이 가능합니다.
seriallizer
{% highlight python %}
class GroupOnlySerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserWithGroupSerializer(serializers.ModelSerializer):
product = GroupOnlySerializer(read_only=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserWithGroupSerializer
{% endhighlight %}
1 in (1:N)
1:N 의 형식에서 1의 입장은 역참조를 해야 하기 때문에 조금은 복잡합니다.
Read case
seriallizer
{% highlight python %}
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserSerializer(serializers.ModelSerializer):
product = GroupSerializer(read_only=True, many=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserSerializer
{% endhighlight %}
Write case
write case에서는 원래 read만 가능하기 때문에 create를 override하여 새로이 구성해줘야 합니다.
seriallizer
{% highlight python %}
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = “all”
class UserSerializer(serializers.ModelSerializer):
product = GroupSerializer(read_only=True, many=True)
class Meta:
model = User
fields = "__all__" {% endhighlight %}
view
{% highlight python %}
class UserListAPIView(generics.ListAPIView):
“””
User GET ALL API
“””
queryset = User.objects.all().order_by(“-id”)
serializer_class = UserSerializer
def create(self, validated_data):
groups = validated_data.pop(‘group’)
user = User.objects.create(**validated_data)
for group in groups:
Group.objects.create(user=user, **group)
return user
{% endhighlight %}
Next step
models
serializers
views
Prev(how to start)
Prev
-
Touch background to close