<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>chane_ha_da.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sun, 03 Aug 2025 14:16:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>chane_ha_da.log</title>
            <url>https://velog.velcdn.com/images/chane_ha_da/profile/aa30e696-1c6d-4dac-8848-a5376e8d0985/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. chane_ha_da.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/chane_ha_da" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Spring] JPA 연관관계에서 직렬화 ]]></title>
            <link>https://velog.io/@chane_ha_da/Spring-JPA-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84%EC%97%90%EC%84%9C-%EC%A7%81%EB%A0%AC%ED%99%94</link>
            <guid>https://velog.io/@chane_ha_da/Spring-JPA-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84%EC%97%90%EC%84%9C-%EC%A7%81%EB%A0%AC%ED%99%94</guid>
            <pubDate>Sun, 03 Aug 2025 14:16:16 GMT</pubDate>
            <description><![CDATA[<h1 id="서론">서론</h1>
<p>Spring에서 REST API를 구현할 때, Spring JPA와 Jackson을 많이 사용한다. 이 환경에서 양방향 연관관계를 매핑할 때 무슨 문제가 있을까?</p>
<h3 id="순환-참조">순환 참조??</h3>
<p>두 객체가 서로를 참조하면서 <strong>참조의 참조를 하는</strong>상황</p>
<pre><code class="language-java">@Entity
public class User {
    @OneToMany(mappedBy = &quot;user&quot;)
    private List&lt;Post&gt; posts;
}

@Entity
public class Post {
    @ManyToOne
    private User user;
}
</code></pre>
<p>이 구조에서 User는 Post 리스트를 가지고 있고, Post는 다시 User를 참조
<strong>참조가 끝없이 반복</strong>되며, 결국 StackOverflowError 또는 API 무한 응답 대기 문제가 발생
<img src="https://velog.velcdn.com/images/chane_ha_da/post/c9379804-9593-4bbd-9d70-a2421c490030/image.png" alt=""></p>
<h3 id="중요한-이유">중요한 이유</h3>
<ul>
<li>프론트엔드로 JSON 데이터를 보낼 때 응답이 끝나지 않음</li>
<li>로깅이나 디버깅 시 콘솔 출력조차 안 됨</li>
<li>Jackson이 객체 그래프를 순회하면서 순환 루프에 빠지기 때문<br>

</li>
</ul>
<h1 id="해결-방법">해결 방법</h1>
<h2 id="1-jsonignore">1. @JsonIgnore</h2>
<p>해당 필드를 직렬화 대상에서 완전히 제외하는 방법</p>
<pre><code class="language-java">@Entity
public class Post {
    @Id @GeneratedValue
    private Long id;
    private String title;

    @ManyToOne
    @JoinColumn(name = &quot;user_id&quot;)
    @JsonIgnore
    private User user;
}
</code></pre>
<h3 id="장점">장점</h3>
<ul>
<li>구현이 간단하고, 순환 참조 문제가 즉각 해결됨</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>무조건 직렬화에서 제외되므로, 클라이언트가 Post 객체 안의 user 정보가 필요할 경우 별도 처리 필요</li>
<li>양방향 정보 제공이 불가능해, 필요하다면 DTO 변환 로직이 복잡해질 수 있음</li>
</ul>
<h2 id="2-jsonmanagedreference--jsonbackreference">2. @JsonManagedReference / @JsonBackReference</h2>
<p>Jackson이 부모‒자식 관계를 인식하도록 표시</p>
<pre><code class="language-java">@Entity
public class User {
    @Id @GeneratedValue
    private Long id;
    private String name;

    @OneToMany(mappedBy = &quot;user&quot;)
    @JsonManagedReference
    private List&lt;Post&gt; posts;
}

@Entity
public class Post {
    @Id @GeneratedValue
    private Long id;
    private String title;

    @ManyToOne
    @JoinColumn(name = &quot;user_id&quot;)
    @JsonBackReference
    private User user;
}
</code></pre>
<ul>
<li>@JsonManagedReference가 붙은 쪽(User.posts)은 직렬화(serialize) 시 포함</li>
<li>@JsonBackReference가 붙은 쪽(Post.user)은 역직렬화(deserialize) 시 포함, 직렬화 시엔 무시<h3 id="장점-1">장점</h3>
</li>
<li>부모 → 자식 방향은 JSON에 노출, 자식 → 부모 방향 순환은 차단</li>
<li>양방향 데이터가 일부 필요한 경우 활용 가능</li>
</ul>
<h3 id="주의사항">주의사항</h3>
<ul>
<li>관계가 둘 이상이면 각각에 대해 value 속성으로 식별자 지정 필요</li>
<li>JPA 매핑과 Jackson 매핑이 분리되어 관리 포인트가 늘어남</li>
</ul>
<h2 id="3-jsonidentityinfo">3. @JsonIdentityInfo</h2>
<p>같은 객체가 반복될 경우 중복 출력하지 않고 참조만 남기는 방식</p>
<pre><code class="language-java">@Entity
@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = &quot;id&quot;
)
public class User {
    @Id
    private Long id;
    private String name;

    @OneToMany(mappedBy = &quot;user&quot;)
    private List&lt;Post&gt; posts;
}

@Entity
@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = &quot;id&quot;
)
public class Post {
    @Id
    private Long id;
    private String title;

    @ManyToOne
    private User user;
}
</code></pre>
<h3 id="장점-2">장점</h3>
<ul>
<li>순환 참조를 안전하게 처리할 수 있음</li>
<li>복잡한 객체 그래프에서도 유지보수 부담 없이 순환 해결 가능</li>
</ul>
<h3 id="단점-1">단점</h3>
<ul>
<li>프론트엔드에서 ID로 다시 객체를 매핑해야 하므로 가독성이 떨어질 수 있음</li>
<li>객체 전체가 아닌 참조 ID만 노출되기 때문에 추가 요청 없이 데이터를 바로 사용할 수 없음</li>
</ul>
<h3 id="언제-사용하는가">언제 사용하는가?</h3>
<ul>
<li>관계가 깊고 엮인 구조가 많아 @JsonIgnore 또는 @JsonManagedReference로는 감당이 어려울 때</li>
<li>복잡한 객체 그래프를 객체 ID 중심으로 표현하는 게 적절한 시스템 (예: 그래프 DB, 트리 구조 등)</li>
<li>빠르게 순환 참조를 막고 싶은 경우</li>
</ul>
<h2 id="4-dto">4. DTO</h2>
<p>DTO(Data Transfer Object)는 엔티티(Entity)의 데이터를 클라이언트에 전달하거나 요청받기 위한 전용 객체</p>
<pre><code class="language-java">public class TagPlainDto {
    private Long id;
    private String name;

    public static TagPlainDto fromEntity(TagPlain tag) {
        return new TagPlainDto(tag.getId(), tag.getName());
    }

    // Constructor, Getter
}
</code></pre>
<h3 id="장점-3">장점</h3>
<ul>
<li>순환 참조 문제 해결</li>
<li>보안성 향상</li>
<li>도메인 모델과 분리된 API 구조</li>
</ul>
<h3 id="단점-2">단점</h3>
<ul>
<li>코드가 늘어남</li>
<li>변환 로직 필요</li>
<li>성능 고려 필요<br>

</li>
</ul>
<h1 id="결론">결론</h1>
<table>
<thead>
<tr>
<th>방식</th>
<th>장점</th>
<th>단점</th>
<th>추천 상황</th>
</tr>
</thead>
<tbody><tr>
<td><strong>@JsonIgnore</strong></td>
<td>- 구현이 간단<br/>- 즉시 순환 차단</td>
<td>- 해당 필드가 JSON에서 빠짐<br/>- 필요한 데이터는 별도 처리 필요</td>
<td>간단히 순환만 끊고 싶을 때</td>
</tr>
<tr>
<td><strong>@JsonManagedReference / @JsonBackReference</strong></td>
<td>- 부모→자식만 노출하며 순환 방지<br/>- 일부 양방향 유지 가능</td>
<td>- 관계가 많아지면 <code>value</code> 관리 복잡<br/>- 매핑 설정 포인트 증가</td>
<td>명확한 부모-자식 구조에서 순환만 제어할 때</td>
</tr>
<tr>
<td><strong>@JsonIdentityInfo</strong></td>
<td>- ID 기반 참조로 복잡한 순환 그래프도 안전 처리</td>
<td>- JSON 가독성↓ (ID만 노출)<br/>- 추가 데이터 요청 필요</td>
<td>깊게 얽힌 연관 구조를 ID 중심으로 표현할 때</td>
</tr>
<tr>
<td><strong>DTO 분리</strong></td>
<td>- 순환 참조 완전 제거<br/>- 보안성·유연성·문서화 강점</td>
<td>- DTO 클래스·매핑 로직 작성량 증가<br/>- 유지보수 시 동기화 필요</td>
<td>실무 대형 프로젝트에서 안정적 API 설계가 필요할 때</td>
</tr>
<tr>
<td><br></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] RestController에서 객체 반환]]></title>
            <link>https://velog.io/@chane_ha_da/Spring-RestController%EC%97%90%EC%84%9C-%EA%B0%9D%EC%B2%B4-%EB%B0%98%ED%99%98</link>
            <guid>https://velog.io/@chane_ha_da/Spring-RestController%EC%97%90%EC%84%9C-%EA%B0%9D%EC%B2%B4-%EB%B0%98%ED%99%98</guid>
            <pubDate>Fri, 16 May 2025 05:07:38 GMT</pubDate>
            <description><![CDATA[<h2 id="서론">서론</h2>
<p>스프링을 통해 REST API를 구축하다보면 객체(DTO)를 반환하는 일은 매우 자주있다.</p>
<pre><code class="language-java">// UserResponse.java
public class UserResponse {
    private String name;
    private int age;

    public UserResponse() {
        name = &quot;Chan&quot;;
        age = 27;
    }
}


// MainController.java
@RestController
public class MainController {

    @GetMapping(&quot;/api/v1/users&quot;)
    public UserResponse getUsers() {
        UserResponse response = new UserResponse();
        return response;
    }
}
</code></pre>
<p><strong>다음의 코드를 보고 잘못된 부분을 찾아 보자.</strong>
분명 틀린 부분이 없어보이지만, 심지어 실행에도 문제가 없지만 실행을 하면, <strong>다음과 같은 문제가 발생한다.</strong>
<img src="https://velog.velcdn.com/images/chane_ha_da/post/85b10cbd-be00-411a-b815-49d1bcc156b6/image.png" alt=""></p>
<h3 id="🔴-http-status-406---not-acceptable-">🔴 HTTP Status 406 - Not Acceptable ??</h3>
<p>이 상태 코드는 클라이언트가 요청할 때 지정한 Accept 헤더에 서버가 응답 가능한 타입이 없다는 뜻입니다.
<strong>즉, 서버가 JSON을 제공하지 못했다는 것!</strong>
무엇이 문제일까? 좀 더 알아보자.
<br/></p>
<h2 id="단계별로-알아보기">단계별로 알아보기</h2>
<h3 id="restcontroller-">@RestController ??</h3>
<blockquote>
<p>@Controller + @ResponseBody</p>
</blockquote>
<p>해당 클래스의 모든 메서드는 반환값을 View가 아닌 <strong>HTTP 응답 본문(body)</strong>에 직접 쓴다.
즉, 객체를 반환에 직접 사용!</p>
<h3 id="객체반환---어떻게">객체반환? - 어떻게??</h3>
<p>기본적으로 Spring은 반환 시 HttpMessageConverter를 사용.
객체를 반환하면 Spring은 자동으로 객체를 JSON으로 변환한다.
이때, MappingJackson2HttpMessageConverter를 사용!
<strong>객체를 JSON으로 변환을 한다!</strong></p>
<h3 id="json-변환은-누가">JSON 변환은 누가??</h3>
<p>MappingJackson2HttpMessageConverter은 <strong>Jackson</strong> 라이브러리를 사용한다.
<strong>Jackson은 객체를 JSON으로 직렬화함!</strong></p>
<h3 id="왜-문제가-발생하는가">왜 문제가 발생하는가?</h3>
<p><strong>Jackson의 직렬화에 대한 문제</strong></p>
<blockquote>
<p>Jackson은 직렬화 시, 다음 중 하나를 필요로 함</p>
</blockquote>
<ul>
<li>public 필드</li>
<li>getter 메서드</li>
</ul>
<p><strong>결국 private 필드인데 getter가 없으면 JSON 직렬화 실패</strong></p>
<h3 id="올바른-코드">올바른 코드</h3>
<pre><code class="language-java">// UserResponse.java
public class UserResponse {
    private String name;
    private int age;

    public UserResponse() {
        name = &quot;Chan&quot;;
        age = 27;
    }

    public String getName() {
        return &quot;HaeChan&quot;;
    }
}
</code></pre>
<p>다음과 같이 getter가 있어야 작동한다.
<img src="https://velog.velcdn.com/images/chane_ha_da/post/c4b9bf7a-5cca-4453-9eb9-5ce5f18e29c2/image.png" alt="">
다음을 통해 Spring에서 RestController에서 객체 반환 시, Getter의 내용을 사용한다는 것을 알 수 있다.
<br/></p>
<h2 id="심화학습">심화학습</h2>
<h3 id="jackson을-이용하기-때문에">Jackson을 이용하기 때문에</h3>
<pre><code class="language-java">@JsonIgnore
@JsonProperty
@JsonManagedReference
@JsonBackReference</code></pre>
<p>다음과 같은 어노테이션을 사용할 수 있음</p>
<ul>
<li><p>@JsonIgnore: 해당 필드를 JSON 직렬화/역직렬화에서 제외</p>
</li>
<li><p>@JsonProperty: JSON의 필드 이름을 Java 필드와 다르게 지정</p>
</li>
<li><p>@JsonManagedReference &amp; @JsonBackReference: 두 어노테이션은 양방향 관계에서 순환 참조로 인해 StackOverflow가 발생하는 것을 방지
  @JsonManagedReference → 직렬화에 포함됨 (보통 부모 → 자식 방향)
  @JsonBackReference → 직렬화에서 제외됨 (보통 자식 → 부모 방향)</p>
</li>
<li><p>@JsonIdentityInfo: Jackson이 객체의 ID 기반으로 참조를 추적하게 하여, 순환 참조 구조에서도 무한 루프 없이 직렬화가 가능</p>
</li>
</ul>
<h3 id="objectmapper를-사용하기">ObjectMapper를 사용하기</h3>
<p><strong>ObjectMapper는 Jackson 라이브러리의 핵심 클래스</strong></p>
<h4 id="직접-사용하기">직접 사용하기</h4>
<pre><code class="language-java">ObjectMapper objectMapper = new ObjectMapper();

// 직렬화: Java 객체 → JSON
User user = new User(&quot;haechan&quot;, 25);
String json = objectMapper.writeValueAsString(user);

// 역직렬화: JSON → Java 객체
String jsonString = &quot;{\&quot;name\&quot;:\&quot;haechan\&quot;,\&quot;age\&quot;:25}&quot;;
User user2 = objectMapper.readValue(jsonString, User.class);</code></pre>
<h4 id="커스텀-마이징">커스텀 마이징</h4>
<pre><code class="language-java">@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();

        // 예: snake_case → camelCase 자동 매핑
        mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);

        // null 값 무시
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        return mapper;
    }
}</code></pre>
<p>다음과 같이 커스텀해서 사용할 수 있다.
<br/></p>
<h2 id="정리">정리</h2>
<ul>
<li>Spring은 객체 반환 시, Jackson을 사용한다.</li>
<li><strong>따라서, public 혹은 getter가 반드시 필요하다.</strong><br/></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AIVLE AI 6기] 미니 프로젝트는 무엇인가요?]]></title>
            <link>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AF%B8%EB%8B%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</link>
            <guid>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AF%B8%EB%8B%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</guid>
            <pubDate>Tue, 31 Dec 2024 05:02:40 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is-미니-프로젝트">What is 미니 프로젝트?</h1>
<blockquote>
<p><strong>실습 후 배운 것을 적용해보는 시간</strong>
AIVLE SCHOOL에서는 7번의 미니 프로젝트를 진행</p>
</blockquote>
<h4 id="주어지는-것">주어지는 것</h4>
<ul>
<li>미션, 데이터, 도메인 정보, 가이드</li>
</ul>
<h4 id="해야하는-것">해야하는 것</h4>
<ul>
<li>데이터 분석, 배운 것을 적용하여 문제를 해결하기<br>

</li>
</ul>
<h1 id="진행-방식">진행 방식</h1>
<ol>
<li>해결해야 할 미션, 데이터, 도메인 정보, 가이드가 제공</li>
<li>개별실습을 통해 주어진 시간 내미션을스스로해결</li>
<li>조별실습을 통해 부족한부분을서로배우고공동과제를수행</li>
<li>전체발표 시간에는 조별 솔루션을 공유하고인사이트를습득</li>
<li>프로젝트에 따라 개인/조별 과제 제출 및 Self-Test로 마무리</li>
</ol>
<ul>
<li>다음과 같은 목표가 주어진다!!
<img src="https://velog.velcdn.com/images/chane_ha_da/post/d49a48d4-337b-4223-af1b-a20727365e08/image.png" alt=""><br>

</li>
</ul>
<h1 id="미니-프로젝트-정리">미니 프로젝트 정리</h1>
<h3 id="주제">주제</h3>
<ul>
<li>1차: 데이터 분석 및 의미찾기</li>
<li>2차: 머신러닝</li>
<li>3차: 딥러닝</li>
<li>4차: 시각지능 딥러닝</li>
<li>5차: 언어지능 딥러닝</li>
<li>6차: 에이스(AICE) 자격증 준비 + 데이터 분석 정리</li>
<li>7차: AI 웹 서비스</li>
</ul>
<h3 id="강의장">강의장</h3>
<ul>
<li><strong>수도권은 2개의 강의장이 있음!</strong></li>
</ul>
<ol>
<li>전농 교육장</li>
<li>분당 교육장</li>
</ol>
<h3 id="미니프로젝트-팁">미니프로젝트 팁</h3>
<ul>
<li>못해도 최선을 다하기!</li>
<li>팀원이랑 의사소통 최대한 많이 하기</li>
<li><strong>강의장을 무조건 활용하기</strong></li>
<li>오프라인 소통이 제일 중요함<br>

</li>
</ul>
<h1 id="미니-프로젝트-맛보기">미니 프로젝트 맛보기</h1>
<h3 id="주제-1">주제</h3>
<ul>
<li>어느 구에 버스정류장을 추가하는 것이 좋은가?</li>
</ul>
<h3 id="제공-데이터">제공 데이터</h3>
<ul>
<li>버스 이용객, 교통 수요, 현 상황 등등</li>
</ul>
<h3 id="목표">목표</h3>
<ul>
<li>데이터 분석을 통해 적합한 지역을 찾자!</li>
</ul>
<h3 id="가이드">가이드</h3>
<ul>
<li>버스 이용객, 교통 수요 데이터 분석</li>
<li>머신러닝을 이용한 교통 수요 예상</li>
<li>여러 도구를 사용하여 인사이트 도출</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AIVLE AI 6기] 무엇을 배우나요? 4주차-머신러닝2]]></title>
            <link>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-4%EC%A3%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D2</link>
            <guid>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-4%EC%A3%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D2</guid>
            <pubDate>Tue, 26 Nov 2024 02:44:10 GMT</pubDate>
            <description><![CDATA[<h1 id="모델-정리">모델 정리</h1>
<ul>
<li>Linear Regression</li>
<li>K-Nearest Neighbor</li>
<li>Decision Tree</li>
<li>Logistic Regression</li>
<li>Random Forest</li>
<li>XGBoost</li>
<li>Light GBM<br>

</li>
</ul>
<h1 id="linear-regression">Linear Regression</h1>
<ul>
<li>이름과 같이 회귀만 가능!</li>
<li>선형 직선을 이용하여 값을 예측하는 방식<h2 id="단순-회귀">단순 회귀</h2>
</li>
<li>독립변수 개수로 회귀분석을 단순 회귀와 다중 회귀로 분류</li>
<li>독립변수 하나가 종속변수에 영향을 미치는 선형 회귀</li>
<li>𝑥 값 하나만으로 𝑦값을 설명할 수 있는 경우</li>
<li>독립변수의 최선의 가중치와(w1)와 편향(w0)을 찾음</li>
</ul>
<h2 id="다중-회귀">다중 회귀</h2>
<ul>
<li>여러 독립변수가 종속변수에 영향을 미치는 선형 회귀</li>
<li>𝑦 값을 설명하기 위해서는 여러 개의 𝑥 값이 필요한 경우</li>
<li>각 독립변수의 최선의 가중치와(w1, w2, w3, w4…)와 편향(w0)을 찾음</li>
</ul>
<h2 id="code">code</h2>
<pre><code class="language-python">from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score</code></pre>
<br>

<h1 id="k-nearest-neighbor">K-Nearest Neighbor</h1>
<ul>
<li>k-Nearest Neighbor: k 최근접 이웃(가장 가까운 이웃 k개)</li>
<li>학습용 데이터에서 k개의 최근접 이웃의 값을 찾아 그 값들로 새로운 값을 예측하는 알고리즘</li>
<li>회귀와 분류에 사용되는 매우 간단한 지도학습 알고리즘</li>
<li>다른 알고리즘에 비해 이해하기 쉽지만, 연산 속도가 느림<h2 id="k값의-중요성">k값의 중요성</h2>
</li>
<li>k(탐색하는 이웃 개수)에 따라 데이터를 다르게 예측할 수도 있음</li>
<li>k 값에 따라 예측 값이 달라지므로 적절한 k 값을 찾는 것이 중요(기본값=5)</li>
<li>검증 데이터로 가장 정확도가 높은 k를 찾아 KNN 알고리즘의 k로 사용</li>
</ul>
<h2 id="scaling">Scaling</h2>
<ul>
<li>거리를 사용하기 때문에 정규화가 성능에 영향을 미침<pre><code class="language-python"># 함수 불러오기
from sklearn.preprocessing import MinMaxScaler
# 정규화
scaler = MinMaxScaler()
# scaler.fit(x_train)
x_train = scaler.fit_transform(x_train)
x_test = scaler.transform(x_test)</code></pre>
</li>
</ul>
<h2 id="code-1">code</h2>
<pre><code class="language-python"># 회귀모델
from sklearn.neighbors import KNeighborsRegressor
from sklearn.metrics import mean_absolute_error, r2_score
# 분류모델
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix, classification_report
# 선언하기
model = KNeighborsRegressor(n_neighbors=5)</code></pre>
<br>

<h1 id="decision-tree">Decision Tree</h1>
<ul>
<li>특정 변수에 대한 의사결정 규칙을 나무 가지가 뻗는 형태로 분류해 나감</li>
<li>분류와 회귀 모두에 사용되는 지도학습 알고리즘</li>
<li>분석 과정이 직관적이며, 이해와 설명하기가 쉬움</li>
<li>스케일링 등의 전처리 영향도가 크지 않음</li>
<li><strong>과적합으로 모델 성능이 떨어지기 쉬움</strong></li>
<li><strong>트리 깊이를 제한하는(=가지치기) 튜닝이 필요</strong></li>
</ul>
<h2 id="가지치기">가지치기</h2>
<ul>
<li>가지치기를 하지 않으면 모델이 학습 데이터에는 매우 잘 맞지만, 평가 데이터에는 잘 맞지 않음</li>
<li>여러 하이퍼파라미터 값을 조정해 가지치기 할 수 있음<ul>
<li>max_depth, min_samples_leaf, min_samples_split 등</li>
</ul>
</li>
<li>학습 데이터에 대한 성능은 낮아지나, 평가 데이터에 대한 성능을 높일 수 있음</li>
<li>가장 적절한 하이퍼파라미터 값을 찾도록 노력해야 함</li>
</ul>
<h2 id="code-2">code</h2>
<pre><code class="language-python"># 회귀모델
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_absolute_error, r2_score
# 분류모델
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import confusion_matrix, classification_report

# 선언하기
model = DecisionTreeRegressor(max_depth=5)</code></pre>
<br>

<h1 id="logistic-regression">Logistic Regression</h1>
<ul>
<li>Sigmoid를 활용하여 <strong>분류</strong>만 가능한 모델!</li>
</ul>
<h2 id="로지스틱-함수">로지스틱 함수</h2>
<ul>
<li>시그모이드(sigmoid) 함수라고도 부름</li>
<li>확률 값 𝑝 는 선형 판별식 값이 커지면 1, 작아지면 0에 가까운 값이 됨</li>
<li>(-∞, ∞) 범위를 갖는 선형 판별식 결과로 (0, 1) 범위의 확률 값을 얻게 됨</li>
<li>기본적으로 확률 값 0.5를 임계값(Threshold)로 하여 이보다 크면 1, 아니면 0으로 분류함</li>
<li>𝑥 데이터가 주어졌을 때 확률을 예측하는 로지스틱 회귀분석은 학습 데이터를 잘 설명하는 선형 판별식의 기울기(𝑎)와 절편(𝑏)을 찾는 문제</li>
</ul>
<h2 id="code-3">code</h2>
<pre><code class="language-python">from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, classification_report
# 선언하기
model = LogisticRegression()</code></pre>
<br>

<h1 id="앙상블ensemble">앙상블(Ensemble)</h1>
<ul>
<li>통합은 힘이다(Unity is strength)</li>
<li>약한 모델이 올바르게 결합하면 더 정확하고 견고한 모델을 얻을 수 있다!</li>
<li>여러 개의 모델을 결합하여 훨씬 강력한 모델을 생성하는 기법</li>
</ul>
<h2 id="배깅bagging">배깅(Bagging)</h2>
<ul>
<li>Bootstrap Aggregating의 약자</li>
<li>데이터로부터 부트스트랩 한 데이터로 모델들을 학습시킨 후, 모델들의 예측 결과를 집계해 최종 결과를 얻는 방법</li>
<li>같은 유형의 알고리즘 기반 모델들을 사용</li>
<li>데이터 분할 시 중복을 허용(복원 랜덤 샘플링 방식이라고 함)</li>
<li>범주형 데이터(Categorical Data)는 투표 방식(Voting)으로 결과를 집계</li>
<li>연속형 데이터(Continuous Data)는 평균으로 결과를 집계</li>
<li>대표적인 배깅 알고리즘: Random Forest</li>
</ul>
<h2 id="부스팅boosting">부스팅(Boosting)</h2>
<ul>
<li>같은 유형의 알고리즘 기반 모델 여러 개에 대해 순차적으로 학습을 수행</li>
<li>이전 모델이 제대로 예측하지 못한 데이터에 대해서 가중치를 부여하여 다음 모델이 학습과 예측을 진행하는 방법</li>
<li>계속하여 모델에게 가중치를 부스팅하며 학습을 진행해 부스팅 방식이라 함</li>
<li>예측 성능이 뛰어나 앙상블 학습을 주도함</li>
<li>배깅에 비해 성능이 좋지만, 속도가 느리고 과적합 발생 가능성이 있음</li>
<li>대표적인 부스팅 알고리즘: XGBoost, LightGBM</li>
</ul>
<h2 id="code-4">code</h2>
<pre><code class="language-python"># 회귀모델
from sklearn.ensemble import RandomForestRegressor
from xgboost import XGBRegressor
from sklearn.metrics import mean_absolute_error, r2_score

# 분류모델
from sklearn.ensemble import RandomForestClassifier
from xgboost import XGBClassifier
from sklearn.metrics import confusion_matrix, classification_report


# 선언하기
model = RandomForestRegressor(max_depth=5, n_estimators=100, random_state=1)
model = XGBRegressor(max_depth=5, n_estimators=100, random_state=1)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AIVLE AI 6기] 무엇을 배우나요? 4주차-머신러닝1]]></title>
            <link>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-4%EC%A3%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D1</link>
            <guid>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-4%EC%A3%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D1</guid>
            <pubDate>Tue, 26 Nov 2024 02:04:44 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is">What is?</h1>
<ul>
<li>데이터를 기반으로 학습하여 특정 작업을 수행하는 것</li>
<li>인간의 경험 = 머신의 데이터</li>
<li>데이터를 통해 학습을 하는 것<br>
# 머신러닝 종류 분류
## 학습 방법에 따른 분류
>#### 지도학습</li>
<li>학습 대상이 되는 데이터에 정답을 주어 규칙성, 즉 데이터의 패턴을 배우게 하는 학습 방법<h4 id="비지도-학습">비지도 학습</h4>
</li>
<li>정답이 없는 데이터 만으로 배우게 하는 학습 방법<h4 id="강화-학습">강화 학습</h4>
</li>
<li>선택한 결과에 대해 보상을 받아 행동을 개선하면서 배우게 하는 학습 방법</li>
</ul>
<h2 id="과제에-따른-분류">과제에 따른 분류</h2>
<blockquote>
<h4 id="분류문제">분류문제</h4>
</blockquote>
<ul>
<li>이미 적절히 분류된 데이터를 학습하여 분류 규칙을 찾고, 그 규칙을 기반으로 새롭게 주어진 데이터를 적절히 분류하는 것을 목적으로 함(지도 학습)<h4 id="회귀문제">회귀문제</h4>
</li>
<li>이미 결과값이 있는 데이터를 학습하여 입력 값과 결과 값의 연관성을 찾고, 그 연관성을 기반으로 새롭게 주어진 데이터에 대한 값을 예측하는 것을 목적으로 함(지도 학습)<h4 id="클러스터링">클러스터링</h4>
</li>
<li>주어진 데이터를 학습하여 적절한 분류 규칙을 찾아 데이터를 분류함을 목적으로 함, 정답이 없어 성능 평가가 어려움(비지도 학습)</li>
</ul>
<h3 id="분류-vs-회귀">분류 vs 회귀</h3>
<ul>
<li><strong>분류와 회귀에 따라 사용할 알고리즘과 평가 함수가 달라짐</strong></li>
<li><strong>예측 값에 연속성이 있으면 회귀</strong><br>

</li>
</ul>
<h1 id="용어-정리">용어 정리</h1>
<blockquote>
<h3 id="모델model">모델(Model)</h3>
</blockquote>
<ul>
<li>데이터로부터 패턴을 찾아</li>
<li>수학식으로 정리해 놓은 것</li>
<li>모델링(Modeling): 오차가 적은 모델을 만드는 과정<h3 id="모델의-목적">모델의 목적</h3>
</li>
<li>샘플을 가지고 전체를 추정<ul>
<li>샘플: 표본, 부분집합, 일부, 과거의 데이터</li>
<li>전체: 모집단, 전체집합, 현재와 미래의 데이터</li>
<li>추정: 예측, 추론<h3 id="행column">행(Column)</h3>
</li>
</ul>
</li>
<li>특성, 속성, 변수, 필드<h3 id="열row">열(Row)</h3>
</li>
<li>개체, 관측치, 기록, 사례, 경우<h3 id="독립변수-종속변수">독립변수, 종속변수</h3>
</li>
<li>독립변수를 𝑥 로, 종속변수를 𝑦로 표시함</li>
<li>독립변수(원인)</li>
<li>종속변수(결과)<h3 id="오차">오차</h3>
</li>
<li>통계학에서 사용되는 가장 단순한 모델 중 하나가 평균</li>
<li>관측값(=실젯값)과 모델 예측값의 차이: 이탈도(Deviance) → 오차<h3 id="데이터-분리">데이터 분리</h3>
</li>
<li>데이터 셋을 학습용, 검증용, 평가용 데이터로 분리 함</li>
<li>평가용 데이터는 별도로 제공되는 데이터일 경우가 많음</li>
<li>검증용 데이터로 평가 전에 모델 성능을 검증해 볼 수 있음(튜닝 시 사용)<h3 id="과대적합overfitting">과대적합(Overfitting)</h3>
</li>
<li>학습 데이터에 대해서는 성능이 매우 좋은데, 평가 데이터에 대해서는 성능이 매우 좋지 않은 경우</li>
<li>학습 데이터에 대해서만 잘 맞는 모델 → 실전에서 예측 성능이 좋지 않음<h3 id="과소적합underfitting">과소적합(Underfitting)</h3>
</li>
<li>학습 데이터보다 평가 데이터에 대한 성능이 매우 좋거나, 모든 데이터에 대한 성능이 매우 안 좋은 경우</li>
<li>모델이 너무 단순하여 학습 데이터에 대해 적절히 훈련되지 않은 경우<br>

</li>
</ul>
<h1 id="모델링-코드">모델링 코드</h1>
<h2 id="구조">구조</h2>
<ol>
<li>불러오기</li>
<li>선언하기</li>
<li>학습하기</li>
<li>예측하기</li>
<li>평가하기<pre><code class="language-python">#1
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
</code></pre>
</li>
</ol>
<p>#2
model = LinearRegression()</p>
<p>#3
model.fit(x_train, y_train)</p>
<p>#4
y_pred = model.predict(x_test)</p>
<p>#5
mean_absolute_error(y_test, y_pred)</p>
<pre><code>&lt;br&gt;

# 성능평가
## 회귀 모델 성능 평가
![](https://velog.velcdn.com/images/chane_ha_da/post/68370984-411f-4eb9-a964-27555772fb15/image.png)
### 결정 계수 R^2(R-Squared)
- Coefficient of Determination
- MSE로 여전히 설명이 부족한 부분이 있음(성능이 확실히 와 닿지 않음)
- 모델 성능을 잘 해석하기 위해서 만든 MSE의 표준화된 버전이 결정 계수임
- 전체 오차 중에서 회귀식이 잡아낸 오차 비율(일반적으로 0 ~ 1 사이)
- 오차의 비 또는 설명력이라고도 부름
- 𝑅^2 = 1이면 𝑀𝑆𝐸 = 0이고 모델이 데이터를 완벽하게 학습한 것
![](https://velog.velcdn.com/images/chane_ha_da/post/ab773623-35df-455e-a9c1-8467b9d64f2e/image.png)

### code
```python
# 함수 불러오기
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_absolute_percentage_error
from sklearn.metrics import r2_score

# 평가하기
# mean_absolute_error(실젯값, 예측값)
print(mean_absolute_error(y_test, y_pred))</code></pre><h2 id="분류-모델-성능-평가">분류 모델 성능 평가</h2>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/7ae49f9a-222f-4c68-8971-6c07ba07fb22/image.png" alt=""></p>
<h3 id="accuracy정확도">Accuracy(정확도)</h3>
<ul>
<li>정분류율 이라고 부르기도 함</li>
<li>전체 중에서 Positive와 Negative 로 정확히 예측한(TN + TP) 비율</li>
<li>Negative를 Negative로 예측한 경우도 옳은 예측임을 고려하는 평가지표</li>
<li>가장 직관적으로 모델 성능을 확인할 수 있는 평가지표</li>
</ul>
<h3 id="precision정밀도--예측-관점">Precision(정밀도) / 예측 관점</h3>
<ul>
<li>Positive로 예측한 것(FP + TP) 중에서 실제 Positive(TP)인 비율</li>
<li>비가 내릴 것으로 예측한 날 중에서 실제 비가 내린 날의 비율</li>
</ul>
<h3 id="recall재현율--실제-관점">Recall(재현율) / 실제 관점</h3>
<ul>
<li>실제 Positive(FN + TP) 중에서 Positive로 예측한(TP) 비율</li>
<li>민감도(Sensitivity)라고 부르는 경우가 많음</li>
<li>실제 비가 내린 날 중에서 비가 내릴 것으로 예측한 날의 비율</li>
</ul>
<h3 id="specificity특이도">Specificity(특이도)</h3>
<ul>
<li>실제 Negative(TN + FP) 중에서 Negative로 예측한(TN) 비율</li>
<li>실제 비가 내리지 않은 날 중에서 비가 내리지 않을 것으로 예측한 날의 비율</li>
</ul>
<h3 id="f1-score">F1-Score</h3>
<ul>
<li>정밀도와 재현율의 조화 평균</li>
<li>분자가 같지만 분모가 다를 경우, 즉 관점이 다른 경우 조화 평균이 큰 의미를 가짐</li>
<li>정밀도와 재현율이 적절하게 요구 될 때 사용</li>
</ul>
<h3 id="code">code</h3>
<pre><code class="language-python"># 함수 불러오기
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report

# 평가하기
# accuracy_score(실젯값, 예측값)
print(accuracy_score(y_test, y_pred))
print(precision_score(y_test, y_pred, average=None))</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring Boot] 사용자 요청 Valid 심화 과정]]></title>
            <link>https://velog.io/@chane_ha_da/Spring-Boot-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%9A%94%EC%B2%AD-Valid-%EC%8B%AC%ED%99%94-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@chane_ha_da/Spring-Boot-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%9A%94%EC%B2%AD-Valid-%EC%8B%AC%ED%99%94-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Fri, 22 Nov 2024 11:11:31 GMT</pubDate>
            <description><![CDATA[<h1 id="intro">Intro?</h1>
<blockquote>
<p>@Valid 어노테이션을 사용하면 사용자의 요청을 검증할 수 있다. 
간단하게 검증에 대해서 알아보고 좀 더 복잡한 검증을 처리해보자!</p>
</blockquote>
<h1 id="valid">Valid?</h1>
<h2 id="dependencies">dependencies</h2>
<pre><code class="language-gradel">implementation &#39;org.springframework.boot:spring-boot-starter-validation&#39;</code></pre>
<h2 id="annotations">Annotations</h2>
<pre><code class="language-java">@Size

@NotNull

@NotEmpty

@NotBlank

@Past

@Future

@FutureOrPresent

@Max

@Min

@Pattern

@Valid

@Email</code></pre>
<h2 id="code">code</h2>
<pre><code class="language-java">public class PortfolioInputItemDTO {
    @NotNull(message = &quot;Stock name must not be null&quot;)
    private String stockName;

    @Min(value = 0, message = &quot;Weight must be at least 0&quot;)
    @Max(value = 1, message = &quot;Weight must be at most 1&quot;)
    @NotNull(message = &quot;weight must not be null&quot;)
    private float weight;
}
</code></pre>
<ul>
<li>다음과 같이 사용하고, 여러 개를 한번에 사용할 수 있음</li>
<li>message의 경우 예외처리시 전달할 내용을 지정!</li>
</ul>
<h2 id="예외-발생-처리-과정">예외 발생 처리 과정</h2>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/e5407097-bf36-43fd-9c7a-ae2b44f6c935/image.png" alt=""></p>
<blockquote>
<p>다음의 과정에서 Handler Mapping 단계에서 @Valid 또는 @Validated가 붙은 파라미터가 있는 경우 유효성 검사</p>
</blockquote>
<ul>
<li>검증 실패 시 <strong>MethodArgumentNotValidException</strong>가 발생함</li>
<li>@ControllerAdvice 어노테이션을 사용하여 정의된 전역 예외 처리기가 있는 경우, 그 메서드가 호출<br>

</li>
</ul>
<h1 id="사용자-정의-검증하기">사용자 정의 검증하기!</h1>
<h2 id="what">What?</h2>
<pre><code class="language-java">public class PortfolioInputItemDTO {
    private List&lt;Stock&gt; stocks;
    //Stock(String name, float weight)
}
</code></pre>
<ul>
<li>다음 DTO에서 List의 Stock의 weight의 합이 1인지 검증을 하고 싶다.</li>
<li>기존의 Annotations만을 이용해서는 불가능하다!</li>
</ul>
<h2 id="process">Process</h2>
<blockquote>
<ol>
<li>Annotation을 정의한다.</li>
<li>검증식을 만든다.</li>
<li>사용하기</li>
</ol>
</blockquote>
<h2 id="in-use">In use</h2>
<pre><code class="language-java">public class PortfolionputDTO {
    private LocalDate startDate;
    private LocalDate endDate;
    private List&lt;PortfolioInputItemDTO&gt; portfolioInputItemDTOList;
}
</code></pre>
<ol>
<li>startDate &lt; endDate인지 검증</li>
<li>List의 weight의 합이 1이 되도록 검증</li>
</ol>
<h3 id="1-annotation-정의하기">1. Annotation 정의하기</h3>
<pre><code class="language-java">import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = PortfolioInputValidator.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidPortfolioInput {
    String message() default &quot;Valid Error&quot;;

    Class&lt;?&gt;[] groups() default {};

    Class&lt;? extends Payload&gt;[] payload() default {};
}
</code></pre>
<ul>
<li>@Constraint(validatedBy = PortfolioInputValidator.class): 유효성 검사를 수행할 클래스를 지정</li>
<li>@Target({ElementType.TYPE}): 적용 범위를 클래스로 설정</li>
<li>@Retention(RetentionPolicy.RUNTIME): 런타임 동안 유지</li>
<li>message: 검사 실패시 전달할 기본 메시지</li>
</ul>
<h3 id="검증-클래스-만들기">검증 클래스 만들기</h3>
<pre><code class="language-java">import com.chan.stock_portfolio_backtest_api.dto.PortfolioInputItemDTO;
import com.chan.stock_portfolio_backtest_api.dto.PortfolionputDTO;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.time.LocalDate;
import java.util.List;

public class PortfolioInputValidator implements ConstraintValidator&lt;ValidPortfolioInput, PortfolionputDTO&gt; {
    @Override
    public boolean isValid(PortfolionputDTO portfolionputDTO, ConstraintValidatorContext constraintValidatorContext) {
        constraintValidatorContext.disableDefaultConstraintViolation();

        if (portfolionputDTO == null) {
            return true;
        }

        //startDate &lt; endDate valid
        LocalDate startDate = portfolionputDTO.getStartDate();
        LocalDate endDate = portfolionputDTO.getEndDate();
        if (startDate != null &amp;&amp; endDate != null) {
            if (!startDate.isBefore(endDate)) {
                constraintValidatorContext
                        .buildConstraintViolationWithTemplate(&quot;endDate must be after the startDate&quot;)
                        .addPropertyNode(&quot;endDate&quot;)
                        .addConstraintViolation();
                return false;
            }
        }

        //weight sum == 1 valid
        List&lt;PortfolioInputItemDTO&gt; portfolioInputItemDTOList = portfolionputDTO.getPortfolioInputItemDTOList();
        float weightSum = 0;
        for (PortfolioInputItemDTO i : portfolioInputItemDTOList) {
            weightSum += i.getWeight();
        }

        if (weightSum != 1) {
            constraintValidatorContext
                    .buildConstraintViolationWithTemplate(&quot;weight sum is might be 1&quot;)
                    .addPropertyNode(&quot;portfolioInputItemDTOList&quot;)
                    .addConstraintViolation();
            return false;
        }

        return true;
    }
}
</code></pre>
<ul>
<li>ConstraintValidator&lt;어노테이션, 적용할 클래스&gt;을 상속받아서 구현해야함</li>
<li>public boolean isValid(): 다음을 오버라이딩 하여 구현해야함</li>
<li>constraintValidatorContext.disableDefaultConstraintViolation(): 기본 메세지를 제거하는 부분<pre><code class="language-java">  if (!startDate.isBefore(endDate)) {
      constraintValidatorContext
              .buildConstraintViolationWithTemplate(&quot;endDate must be after the startDate&quot;)
              .addPropertyNode(&quot;endDate&quot;)
              .addConstraintViolation();
      return false;
  }</code></pre>
</li>
<li>다음과 같이 false를 반환하면 유효성 검사를 실패로 설정</li>
<li>constraintValidatorContext을 사용해 메세지와 Property를 추가할 수 있음</li>
</ul>
<h3 id="사용하기">사용하기</h3>
<pre><code class="language-java">@ValidPortfolioInput
public class PortfolionputDTO {
    @DateTimeFormat(pattern = &quot;yyyy-MM-dd&quot;)
    @NotNull(message = &quot;Start date must not be null&quot;)
    private LocalDate startDate;

    @DateTimeFormat(pattern = &quot;yyyy-MM-dd&quot;)
    @NotNull(message = &quot;End date must not be null&quot;)
    private LocalDate endDate;

    @Valid
    private List&lt;PortfolioInputItemDTO&gt; portfolioInputItemDTOList;
}
</code></pre>
<ul>
<li>다음과 같이 만든 어노테이션을 클래스에 추가하여 사용할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AIVLE AI 6기] 무엇을 배우나요? 3주차-웹 크롤링]]></title>
            <link>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-3%EC%A3%BC%EC%B0%A8-%EC%9B%B9-%ED%81%AC%EB%A1%A4%EB%A7%81</link>
            <guid>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-3%EC%A3%BC%EC%B0%A8-%EC%9B%B9-%ED%81%AC%EB%A1%A4%EB%A7%81</guid>
            <pubDate>Wed, 06 Nov 2024 05:41:36 GMT</pubDate>
            <description><![CDATA[<h1 id="web-crawling">Web Crawling</h1>
<ul>
<li>웹서비스의 여러 페이지를 이동하며 데이터를 수집하는 작업</li>
</ul>
<h2 id="웹크롤링-방법">웹크롤링 방법</h2>
<h3 id="웹페이지의-종류">웹페이지의 종류</h3>
<ul>
<li>정적인 페이지 : 웹 브라우져에 화면이 한번 뜨면 이벤트에 의한 화면의 변경이 없는 페이지</li>
<li>동적인 페이지 : 웹 브라우져에 화면이 뜨고 이벤트가 발생하면 서버에서 데이터를 가져와 화면을 변경하는 페이지</li>
</ul>
<h3 id="requests-이용">requests 이용</h3>
<ol>
<li>json 문자열로 받아서 파싱하는 방법 : 주로 동적 페이지 크롤링할때 사용</li>
<li>html 문자열로 받아서 파싱하는 방법 : 주로 정적 페이지 크롤링할때 사용</li>
</ol>
<h3 id="selenium-이용">selenium 이용</h3>
<ul>
<li>브라우져를 직접 열어서 데이터를 받는 방법</li>
</ul>
<blockquote>
<p>속도 비교
requests json &gt; requests html &gt; selenium</p>
</blockquote>
<br>

<h1 id="requests-방식-크롤링">requests 방식 크롤링</h1>
<h2 id="import">import</h2>
<pre><code class="language-python">import requests
import pandas as pd # 데이터 처리를 위한
</code></pre>
<h2 id="url-구성하기">URL 구성하기</h2>
<ul>
<li>개발자 모드 -&gt; 네트워크 상 URL을 가져옴<pre><code class="language-python">page, page_size = 1, 60
url = f&#39;https://m.stock.naver.com/api/index/KOSPI/price?\pageSize={page_size}&amp;page={page}&#39;
</code></pre>
</li>
</ul>
<pre><code>
## 요청하고 응답받기
```python
response = requests.get(url)
response
</code></pre><p><img src="https://velog.velcdn.com/images/chane_ha_da/post/925f491d-5dab-47f5-9a75-757035ca2d96/image.png" alt="">
다음과 같이 200을 출력한다면 정상적으로 응답을 받아온 것이다.</p>
<h2 id="df-구성하기">df 구성하기</h2>
<pre><code class="language-python">columns = [&quot;localTradedAt&quot;, &quot;closePrice&quot;]
data = response.json()
kospi_df = pd.DataFrame(data)[columns]
kospi_df
</code></pre>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/e9495fd4-4f00-41c2-a6d4-8c2b3c590d54/image.png" alt="">
<br></p>
<h1 id="requestsrest-api-공공데이터-포탈">requests(REST API-공공데이터 포탈)</h1>
<h2 id="import-1">import</h2>
<pre><code class="language-python">import requests, json
import pandas as pd # 데이터 처리를 위한
</code></pre>
<h2 id="url-구성하기-1">URL 구성하기</h2>
<h3 id="api-키-및-파라미터-설정">API 키 및 파라미터 설정</h3>
<pre><code class="language-python">REST_API_KEY = &quot;your-key&quot;
resultType = &#39;json&#39;
basDt = &#39;20241105&#39;
</code></pre>
<h3 id="url">URL</h3>
<pre><code class="language-python">url = f&#39;http://apis.data.go.kr/1160100/service/GetStockSecuritiesInfoService/getStockPriceInfo?serviceKey={REST_API_KEY}&amp;resultType={resultType}&amp;basDt={basDt}&#39;
</code></pre>
<h2 id="요청하고-응답받기">요청하고 응답받기</h2>
<pre><code class="language-python">response = requests.get(url)
response
</code></pre>
<h2 id="응답-분석하고-데이터로-json-형식-변경하기">응답 분석하고 데이터로 json 형식 변경하기</h2>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/b1161309-db6c-435e-ba93-cd867e48506e/image.png" alt=""></p>
<ul>
<li>다음과 같은 구조를 가진다.</li>
<li>item들을 불러오기 위해서 response&gt;body&gt;items&gt;item을 찾아야 한다.</li>
</ul>
<pre><code class="language-python">data = repsonse.json()[&#39;response&#39;][&#39;body&#39;][&#39;items&#39;][&#39;item&#39;]
</code></pre>
<h2 id="df-구성하기-1">df 구성하기</h2>
<pre><code class="language-python">df = pd.DataFrame(data)
df
</code></pre>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/2821f23c-4854-4a74-9de8-29b502e7d817/image.png" alt="">
<br></p>
<h1 id="정정페이지-데이터-수집">정정페이지 데이터 수집</h1>
<h2 id="import-2">import</h2>
<pre><code class="language-python">import pandas as pd
import requests
from bs4 import BeautifulSoup
</code></pre>
<h2 id="url-정의-및-호출">url 정의 및 호출</h2>
<pre><code class="language-python">query = &quot;삼성전자&quot;
url = f&quot;https://search.naver.com/search.naver?query={query}&quot;

dom = BeautifulSoup(response.text, &quot;html.parser&quot;)
</code></pre>
<h2 id="정보가져오기">정보가져오기</h2>
<pre><code class="language-python">elements = dom.select(&quot;.fds-refine-query-grid a&quot;)
elements[0].text

element = elements[0]
link = element.get(&quot;href&quot;)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AIVLE AI 6기] 무엇을 배우나요? 2주차-데이터 분석]]></title>
            <link>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9DAIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D</link>
            <guid>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9DAIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D</guid>
            <pubDate>Tue, 29 Oct 2024 01:30:57 GMT</pubDate>
            <description><![CDATA[<h1 id="가설검정이란">가설검정이란?</h1>
<h2 id="모집단과-표본">모집단과 표본</h2>
<blockquote>
<p>모집단: 우리가 알고 싶은 대상 전체
표본: 그 대상의 일부 영역
-&gt; <strong>표본을 가지고 모집단을 알고 싶은것!</strong></p>
</blockquote>
<ul>
<li>우리는 표본을 통해 모집단을 추정한다!</li>
</ul>
<h2 id="귀무가설-vs-대립가설">귀무가설 vs 대립가설</h2>
<ul>
<li>귀무가설: 기존에 알고있는 가설, 버릴 가설</li>
<li>대립가설: 귀무가설에 대립하는 명제<blockquote>
<p>바이러스 치료제인 A는 효과가 있을까?
귀무가설: A는 효과가 없다.
대립가설: A는 효과가 있다.</p>
</blockquote>
</li>
</ul>
<h2 id="그래서-가설-검정이란">그래서 가설 검정이란?</h2>
<ol>
<li>가설을 설립한다.</li>
<li>표본을 통해 P-value를 구한다.</li>
<li>P-value의 값이 기준보다 작다면 가설을 수립한다.</li>
</ol>
<p>-&gt; 이러한 절차를 가설 검정이라 부름
<br/></p>
<h1 id="이변량-분석">이변량 분석</h1>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/463269a9-2023-4233-90b8-c8e864fb14bf/image.png" alt=""></p>
<h2 id="case1-연속---연속">Case1: 연속 -&gt; 연속</h2>
<h3 id="시각화산점도">시각화(산점도)</h3>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/6165e92d-c7e2-496f-af3f-3bc6db78f431/image.png" alt=""></p>
<ul>
<li>두 숫자형 변수의 관계를 나타내는 그래프</li>
<li>중요한 관점은 <strong>직선</strong>인가?<pre><code class="language-python">plt.scatter( x축 값, y축 값 )
plt.scatter( ‘x변수’, ‘y변수’, data = df) 
</code></pre>
</li>
</ul>
<p>sns.scatterplot( ‘x변수’, ‘y변수’, data = df)
sns.pairplot(dataframe) # 산점도 한번에 그리기</p>
<pre><code>
### 수치비교
* 상관계수: 관계를 수치화한것
* 상관분석: 상관계수가 유의미한 지를 검정(test)
```python
import scipy.stats as spst
spst.pearsonr(air[&#39;Temp&#39;], air[&#39;Ozone&#39;])
# 결과: (상관계수, p-value)

df.corr() # 한번에 상관계수 구하기</code></pre><p>-&gt; P-value &lt; 0.05 이면, 두 변수 간에 관계가 있다!</p>
<h2 id="case2-범주---연속">Case2: 범주 -&gt; 연속</h2>
<h3 id="시각화">시각화</h3>
<pre><code class="language-python">sns.barplot(x=&quot;Survived&quot;, y=&quot;Age&quot;, data=titanic)
plt.grid()
plt.show()
</code></pre>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/f6103124-7ada-4f13-a67e-6be0ff718744/image.png" alt=""></p>
<ul>
<li>두 평균에 차이가 크고, 신뢰구간이 겹치지 않을 때</li>
<li><blockquote>
<p>대립가설이 맞다!</p>
</blockquote>
</li>
</ul>
<h2 id="수치화t-test-anova분산분석">수치화(t-test, anova(분산분석))</h2>
<ul>
<li>범주가 2개 -&gt; t-test</li>
<li>범주가 3개 이상 -&gt; anova(분산분석)</li>
</ul>
<pre><code class="language-python"># t-test
# 1) t-test를 위한 데이터 준비
# NaN 행 제외
temp = titanic.loc[titanic[&#39;Age&#39;].notnull()]
# 두 그룹으로 데이터 저장
died = temp.loc[temp[&#39;Survived&#39;]==0, &#39;Age&#39;]
survived = temp.loc[temp[&#39;Survived&#39;]==1, &#39;Age&#39;]
# 2) t-test
spst.ttest_ind(died, survived)


# anova
# 1) 분산 분석을 위한 데이터 만들기
# NaN 행 제외
temp = titanic.loc[titanic[&#39;Age&#39;].notnull()]
# 그룹별 저장
P_1 = temp.loc[temp.Pclass == 1, &#39;Age&#39;]
P_2 = temp.loc[temp.Pclass == 2, &#39;Age&#39;]
P_3 = temp.loc[temp.Pclass == 3, &#39;Age&#39;]
# 2) 분산분석
spst.f_oneway(P_1, P_2, P_3)
</code></pre>
<ul>
<li>p-value가 0.05보다 작으면 차이가 있다.</li>
<li>t 통계량이 -2보다 작거나, 2보다 크면, 차이가 있다.</li>
</ul>
<h2 id="case3-범주---범주">Case3: 범주 -&gt; 범주</h2>
<h3 id="교차표-사용">교차표 사용</h3>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/b6833f9b-c92a-40d0-9e5a-4b43a9de483c/image.png" alt=""></p>
<pre><code class="language-python"># option: columns, index, all
pd.crosstab(행, 열, normalize = option)
</code></pre>
<h3 id="시각화mosaic-plot">시각화(mosaic plot)</h3>
<pre><code class="language-python">mosaic(titanic, [ &#39;Pclass&#39;,&#39;Survived&#39;])
plt.axhline(1- titanic[&#39;Survived&#39;].mean(),
color = &#39;r&#39;)
plt.show()
</code></pre>
<h3 id="수치화카이제곱검정">수치화(카이제곱검정)</h3>
<ul>
<li>기대빈도와 실제의 차이를 값으로 나타낸것<pre><code class="language-python"># 1) 먼저 교차표 집계
table = pd.crosstab(titanic[&#39;Survived’],
titanic[&#39;Pclass&#39;])
print(table)
print(&#39;-&#39; * 50)
# 2) 카이제곱검정
spst.chi2_contingency(table)
</code></pre>
</li>
</ul>
<h1 id="결과">결과</h1>
<h1 id="카이제곱-통계랑-p-value-자유도-기대빈도">카이제곱 통계랑, p-value, 자유도, 기대빈도</h1>
<pre><code>
## Case4: 연속 -&gt; 범주
### 시각화
```python
sns.kdeplot( )</code></pre><p><img src="blob:https://velog.io/73f63bdd-e048-4539-aac5-8f3c72be84be" alt="업로드중..">
<br/></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AIVLE AI 6기] 무엇을 배우나요? 2주차-데이터 처리]]></title>
            <link>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B2%98%EB%A6%ACAIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B2%98%EB%A6%ACAIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Thu, 24 Oct 2024 02:58:54 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터-처리란">데이터 처리란?</h1>
<ul>
<li>주어진 데이터의 구조를 이해하고 분석을 위해 변경하는 과정</li>
<li><strong>데이터 분석 절차를 이해하여 데이터를 변경하는 것</strong></li>
<li>pandas를 활용한다!<br>

</li>
</ul>
<h1 id="데이터프레임-변경">데이터프레임 변경</h1>
<h2 id="열-이름-변경">열 이름 변경</h2>
<ul>
<li>모든 열 이름을 변경하는 방식, 지정한 열 이름을 변경하는 방식이 있음<blockquote>
<p>df.columns: 모든 열 이름 변경
df.rename(): 지정한 열 이름 변경</p>
</blockquote>
</li>
</ul>
<pre><code class="language-python">tip.columns = [&#39;total_bill&#39;, &#39;tip&#39;, &#39;sex&#39;, &#39;smoker&#39;, &#39;day&#39;, &#39;time&#39;, &#39;size&#39;]
tip.rename(columns={&#39;total_bill_amount&#39;: &#39;total_bill&#39;,
 &#39;male_female&#39;: &#39;sex&#39;,
 &#39;smoke_yes_no&#39;: &#39;smoker&#39;,
 &#39;week_name&#39;: &#39;day&#39;,
 &#39;dinner_lunch&#39;: &#39;time&#39;}, inplace=True)</code></pre>
<h2 id="열-추가">열 추가</h2>
<ul>
<li>데이터 분석 시 열의 순서가 중요한 경우가 있음! -&gt; 오류발생 가능성이 있음<blockquote>
<p>없는 열을 변경시 df[&#39;new] = []: 맨 뒤에 열 추가
insert(): 지정한 위치에 추가</p>
</blockquote>
</li>
</ul>
<pre><code class="language-python"># final_amt 열 추가
tip[&#39;final_amt&#39;] = tip[&#39;total_bill&#39;] + tip[&#39;tip&#39;] 

# tip 열 앞에 div_tb 열 추가
tip.insert(1, &#39;div_tb&#39;, tip[&#39;total_bill&#39;] / tip[&#39;size&#39;])</code></pre>
<h2 id="열-삭제">열 삭제</h2>
<ul>
<li>inplace를 False로 사용 시, 해당 값을 새로운 변수에 저장해야함<blockquote>
<p>df.drop()
axis=0: 행 삭제(기본 값), axis=1: 열 삭제
inplace = False : 삭제한 것처럼 보여줘, True : 원본 데이터 변경</p>
</blockquote>
</li>
</ul>
<pre><code class="language-python"># 열 하나 삭제
tip.drop(&#39;final_amt&#39;, axis=1, inplace=True)

# 열 두 개 삭제
tip.drop([&#39;div_tb&#39;, &#39;day&#39;], axis=1, inplace=True)</code></pre>
<h2 id="값-변경">값 변경</h2>
<ul>
<li>기본적으로 []을 활용하여 값을 변경할 수 있음<blockquote>
<p>[]: 조건문 사용가능
map: 값에 따라 변경 가능</p>
</blockquote>
<pre><code class="language-python"># tip[‘tip’] 의 모든 값을 0으로 바꾸기
tip[‘tip’] = 0
</code></pre>
</li>
</ul>
<h1 id="tiptip-의-값이-10보다-작을-경우-0으로-바꾸기">tip[‘tip’] 의 값이 10보다 작을 경우, 0으로 바꾸기</h1>
<p>tip.loc[tip[‘tip’] &lt; 10, ‘tip’] = 0</p>
<h1 id="tiptip-의-값이-10보다-작을-경우-0-아니면-1로-바꾸기">tip[‘tip’] 의 값이 10보다 작을 경우 0, 아니면 1로 바꾸기</h1>
<p>tip[‘tip’] = np.where(tip[‘tip’] &lt; 10, 0, 1)</p>
<h1 id="male---1-female---0">Male -&gt; 1, Female -&gt; 0</h1>
<p>tip[&#39;sex&#39;] = tip[&#39;sex&#39;].map({&#39;Male&#39;: 1, &#39;Female&#39;: 0})</p>
<pre><code>### pd.cut
* 숫자형 -&gt; 범주형 변수로 변환하는 함수
```python
# 크기로 3등분해서 등급 구하기
tip[&#39;tip_grp&#39;] = pd.cut(tip[&#39;tip&#39;], 3, labels=[&#39;c&#39;, &#39;d&#39;, &#39;e&#39;] )

# 나이를 다음 구간으로 분할합니다.
# &#39;young&#39;  : =&lt; 40 
# &#39;junior&#39; : 40 &lt;   =&lt; 50
# &#39;senior&#39; : 50 &lt; np.inf
# 값의 범위 중 오른쪽(큰값)이 아닌 왼쪽(작은값)이 포함되도록 하려면 pd.cut 함수 옵션에 right = False 라고 지정해야 합니다.
age_group = pd.cut(data2[&#39;Age&#39;], bins =[0, 40, 50, 100], labels = [&#39;young&#39;,&#39;junior&#39;,&#39;senior&#39;])
age_group.value_counts()</code></pre><br>

<h1 id="데이터프레임-결합">데이터프레임 결합</h1>
<h2 id="pdconcat">pd.concat()</h2>
<ul>
<li>단순히 합치는 방식</li>
<li><strong>행, 열 두 방향 모두 가능!</strong><blockquote>
<p>axis: 0(세로, 행), 1(가로, 열) 방향으로 합친다
join: outer(모든 행과 열 합치기), inner(같은 행만 합치기)</p>
</blockquote>
</li>
</ul>
<pre><code class="language-python"># 세로로 합치기
pd.concat([df1, df2], axis = 0, join = &#39;inner&#39;)
pd.concat([df1, df2], axis = 0, join = &#39;outer&#39;)

# 가로로 합치기
pd.concat([df1, df2], axis = 1, join = &#39;inner&#39;)
pd.concat([df1, df2], axis = 1, join = &#39;outer&#39;)</code></pre>
<h3 id="inner-outer의-차이">inner, outer의 차이</h3>
<ul>
<li>기본 데이터 
<img src="https://velog.velcdn.com/images/chane_ha_da/post/ce8dd85b-194a-4582-95f6-0ba2e2286a3d/image.png" alt=""></li>
<li>inner 결과
<img src="https://velog.velcdn.com/images/chane_ha_da/post/f7f73514-b3c5-41a9-bcc7-1d7f60ea9d40/image.png" alt=""></li>
<li>outer 결과
<img src="https://velog.velcdn.com/images/chane_ha_da/post/2fb2a5ec-f867-44ba-a6a8-e791c42b352e/image.png" alt=""></li>
</ul>
<h2 id="pdmerge">pd.merge()</h2>
<ul>
<li>지정한 칼럼의 값을 기준으로 병합 / 옆으로만 병합</li>
<li>테이블의 조인과 같음!!<blockquote>
<p>join: outer(모두 합치기), inner(같은 값만 합치기)
left : 왼쪽 df는 모두, 오른쪽 df는 같은 값만
right : 오른쪽 df는 모두, 왼쪽 df는 같은 값만
on: 기준 설정</p>
</blockquote>
</li>
</ul>
<pre><code class="language-python">pd.merge(df1, df2, how = &#39;inner&#39;, on = &#39;A&#39;)
pd.merge(df1, df2, how = &#39;left&#39;)
pd.merge(df1, df2, how = &#39;right&#39;)</code></pre>
<h2 id="pdpivot">pd.pivot()</h2>
<ul>
<li>집계된(group by) 데이터를 재구성<pre><code class="language-python">temp = pd.merge(sales1, products)
temp2 = temp.groupby([&#39;Date&#39;, &#39;Category&#39;], as_index = False)[&#39;Qty&#39;].sum()
temp3 = temp2.pivot(index = &#39;Category&#39;, columns = &#39;Date&#39; , values = &#39;Qty&#39;)</code></pre>
<br>

</li>
</ul>
<h1 id="단변량-분석">단변량 분석</h1>
<ul>
<li>하나의 변수만을 대상으로 수행하는 데이터 분석 기법</li>
<li>데이터를 요약하고 그 변수의 분포나 특성을 이해하는 데 초점</li>
<li>숫자형과 범주형에 따라 방식이 다름!</li>
</ul>
<h2 id="숫자형-단변량-분석">숫자형 단변량 분석</h2>
<ol>
<li>숫자로 요약하기 : 정보의 대푯값</li>
<li>구간을 나누고 빈도수(frequency) 계산 -&gt; 도수 분포표</li>
</ol>
<h3 id="숫자로-요약하기">숫자로 요약하기</h3>
<pre><code class="language-python">np.mean(t[&#39;Fare&#39;])
t[&#39;Fare&#39;].mean()

np.median(t[&#39;Fare&#39;])
t[&#39;Fare&#39;].median()

titanic[&#39;Pclass&#39;].mode()

# 기초 통계량
df.describe() </code></pre>
<h3 id="시각화-하기">시각화 하기</h3>
<h4 id="histogram">Histogram</h4>
<ul>
<li>도수 분포를 정보 그림으로 나타낸 것</li>
<li>bins는 구간의 수로 적절히 조절하는 것이 중요<pre><code class="language-python">plt.hist(titanic.Fare, bins = 30, edgecolor = &#39;gray&#39;)
plt.xlabel(&#39;Fare&#39;)
plt.ylabel(&#39;Frequency&#39;)
plt.show()</code></pre>
<img src="https://velog.velcdn.com/images/chane_ha_da/post/8304dbfa-15df-4712-a1fe-1bebf829fb38/image.png" alt=""></li>
</ul>
<h4 id="density-plot">Density Plot</h4>
<ul>
<li>밀도함수 그래프</li>
<li>그래프의 아래 면적의 합은 1<pre><code class="language-python">sns.kdeplot(titanic[&#39;Fare&#39;])
plt.show()</code></pre>
<img src="https://velog.velcdn.com/images/chane_ha_da/post/ed41b65e-6b1a-4048-b600-459ee1b126dc/image.png" alt=""></li>
</ul>
<h4 id="box-plot">Box Plot</h4>
<ul>
<li>사전에 반드시 NaN을 제외(sns.boxplot 은 NaN을 알아서 제거해 줌)</li>
<li>vert 옵션 : 횡(False), 종(True, 기본값)<pre><code class="language-python">plt.boxplot(temp[&#39;Age&#39;] , vert = False)
plt.grid()
plt.show()</code></pre>
<img src="https://velog.velcdn.com/images/chane_ha_da/post/50d66c3c-8f56-4f92-8213-333702f8f76b/image.png" alt=""></li>
</ul>
<h2 id="범주형-단변량-분석">범주형 단변량 분석</h2>
<h3 id="숫자로-요약하기-1">숫자로 요약하기</h3>
<pre><code class="language-python">titanic[&#39;Embarked&#39;].value_counts()
titanic[&#39;Embarked&#39;].value_counts(normalize = True)</code></pre>
<h3 id="시각화-하기-1">시각화 하기</h3>
<h4 id="bar-plot">Bar Plot</h4>
<pre><code class="language-python">sns.countplot(titanic[&#39;Pclass&#39;])
plt.grid()
plt.show()</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AIVLE AI 6기] 무엇을 배우나요? 1주차-Python 프로그래밍, 라이브러리]]></title>
            <link>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-1%EC%A3%BC%EC%B0%A8-Python-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</link>
            <guid>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-1%EC%A3%BC%EC%B0%A8-Python-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</guid>
            <pubDate>Tue, 15 Oct 2024 02:00:23 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is-numpy">What is Numpy?</h1>
<ul>
<li>빠른 수치 계산을 위해서 C언어로 만들어진 파이썬 라이브러리</li>
<li>벡터와 행렬 연산에 편리한 기능들을 제공</li>
<li>데이터분석용 라이브러리인 Pandas와 Matplotlib의 기반으로 사용됨</li>
<li>Array(벡터, 행렬) 단위로 데이터 관리</li>
</ul>
<h2 id="용어정리">용어정리</h2>
<ul>
<li>Axis: 배열의 각 축(0: 행, 1: 열)</li>
<li>Rank: 축의 개수(차원)</li>
<li>Shape: 축의 길이</li>
</ul>
<h2 id="codes">codes</h2>
<h3 id="import">import</h3>
<pre><code class="language-python">import numpy
import numpy as np
from numpy import array</code></pre>
<h3 id="기본사용">기본사용</h3>
<pre><code class="language-python">a = np.array()
a.ndim # 차원 출력
a.shape # -&gt; (행, 열)
a.dtype # 데이터 타입 출력</code></pre>
<h3 id="배열-만들기">배열 만들기</h3>
<pre><code class="language-python">a = np.array()
a = np.array([1, 2, 3, 4]) # list로 선언
np.zeros((2, 2)) # 0으로 채워진 배열
np.ones((1, 2)) # 1로 채워진 배열
np.full((2, 2), 7.) # 특정 값으로 채워진 배열
np.eye(2) # 단위 행렬(대각만 1)
np.random.random((2, 2))</code></pre>
<h3 id="reshape">Reshape</h3>
<ul>
<li>기존 배열을 새로운 형태의 배열로 다시 구성하는 함수</li>
<li>(1, 6) -&gt; (6, 1) 이렇게 변경 가능<pre><code class="language-python">np.reshape(li, (6, 1))
li.reshape(6, 1)
li.reshape(6, -1) # -1은 알아서 변환</code></pre>
</li>
</ul>
<h3 id="기본-연산들">기본 연산들</h3>
<pre><code class="language-python">a, b

a+b
np.add(a, b)

a-b
np.subtract(a, b)

a*b
np.multiply(a, b)

a/b
np.divide(a, b)

a**b
np.power(a, b)

# 제곱근
np.sqrt(a)</code></pre>
<h3 id="집계-함수들">집계 함수들</h3>
<pre><code class="language-python">np.mean(), np.sum(), np.std()
# 전체 집계
print(np.sum(a))

# 열기준 집계
print(np.sum(a, axis = 0))

# 행기준 집계
print(np.sum(a, axis = 1))

# 가장 큰(작은) 값의 인덱스 반환
np.argmax(array, axis=0)
np.argmin(array, axis=0)</code></pre>
<h3 id="배열-데이터-조회-인덱싱-슬라이싱">배열 데이터 조회: 인덱싱, 슬라이싱</h3>
<pre><code class="language-python">arr1[1, 3]
arr1[1][3]

arr1[1,:] # arr[1]
arr[[행1, 행2]]
arr[[행1, 행2],:] 

arr1[시작:끝]
arr1[행, 시작:끝]
arr1[시작:끝, 시작:끝]</code></pre>
<h3 id="조건에-따른-값-설정">조건에 따른 값 설정</h3>
<pre><code class="language-python"> np.where(조건문, 참일 때 값, 거짓일 때 값)
 np.where(a&gt;2, 1, 0)</code></pre>
<br>

<h1 id="what-is-pandas">What is Pandas?</h1>
<h2 id="데이터프레임과-시리즈">데이터프레임과 시리즈</h2>
<h3 id="데이터프레임dataframe">데이터프레임(Dataframe)?</h3>
<ul>
<li>데이터 분석에서 가장 중요한 데이터 구조</li>
<li>관계형 데이터베이스의 테이블 또는 엑셀 시트와 같은 형태 (2차원 구조)</li>
<li>변수들의 집합 → 각 열을 변수라고 부름</li>
<li>행(분석 단위), 열(정보)</li>
</ul>
<h3 id="시리즈series">시리즈(Series)?</h3>
<ul>
<li>하나의 정보에 대한 데이터들의 집합</li>
<li>데이터 프레임에서 하나의 열을 떼어낸 것(1차원)</li>
</ul>
<h2 id="codes-1">codes</h2>
<h3 id="csv파일에서-데이터-읽어-오기">CSV파일에서 데이터 읽어 오기</h3>
<ul>
<li>pandas는 여러가지 파일을 읽어오는 것이 가능<pre><code class="language-python">path = &#39;./data.csv&#39;
data = pd.read_csv(path)</code></pre>
</li>
</ul>
<h3 id="데이터프레임-정보-확인">데이터프레임 정보 확인</h3>
<pre><code class="language-python">df.head(10) # 상위 10개
df.tail(10) # 하위위 10개

# 열 자료형
data.dtypes

# 모양 확인(행, 열)
df.shape
# 정보 확인
df.info()
# 기초 통계 정보 확인
df.describe()</code></pre>
<h3 id="데이터-정렬">데이터 정렬</h3>
<pre><code class="language-python"># ascending: False(내림차순), True(오름차순-기본값)
# 인덱스 기준으로 정렬
data.sort_index(ascending=False)
# 정해서 정렬
data.sort_values(by=&#39;aaa&#39;)
data.sort_values(by=[&#39;aaa&#39;, &#39;bbbb&#39;], ascending=[True, True])
temp.reset_index(drop = True)</code></pre>
<h3 id="고유-값-확인">고유 값 확인</h3>
<pre><code class="language-python">data[&#39;MaritalStatus&#39;].unique()
data[&#39;MaritalStatus&#39;].value_counts()</code></pre>
<h3 id="기본-집계-메소드">기본 집계 메소드</h3>
<pre><code class="language-python">data[&#39;MonthlyIncome&#39;].sum()
data[&#39;MonthlyIncome&#39;].max()
data[[&#39;Age&#39;, &#39;MonthlyIncome&#39;]].mean()
data[[&#39;Age&#39;, &#39;MonthlyIncome&#39;]].median()</code></pre>
<h3 id="데이터조회">데이터조회</h3>
<ul>
<li><strong>시리즈와 데이터프레임으로 조회가 가능</strong><pre><code class="language-python"># 1차원(시리즈)로 조회
data[&#39;col&#39;]
data.col
</code></pre>
</li>
</ul>
<h1 id="2차원데이터프레임으로-조회">2차원(데이터프레임)으로 조회</h1>
<p>data[[&#39;col&#39;]]
data[[&#39;col1&#39;, &#39;col2&#39;]]</p>
<pre><code>
### 조건으로 데이터 조회
```python
# 기본 loc[행 조건, 열 이름]
data.loc[data[&#39;tip&#39;] &gt; 6.0]

# 여러 조건 and, or -&gt; &amp;, |
data.loc[(data[&#39;tip&#39;] &gt; 6.0) | (data[&#39;ar&#39;] &lt; 6.0)]]

# 열 이름 지정해서 가져오기
data.loc[:, [&#39;tip&#39;, &#39;size&#39;]]

# isin([값1, 값2]): 값이 리스트안에 있어야 조회
tip.loc[tip[&#39;day&#39;].isin([&#39;Sat&#39;, &#39;Sun&#39;])]

# between: 사이에 있는 값
# &#39;left&#39;, &#39;right&#39;, &#39;neither&#39;, &#39;both&#39;: 포함 여부
tip.loc[tip[&#39;size&#39;].between(1, 3)]
tip.loc[tip[&#39;size&#39;].between(1, 3, &#39;left&#39;)]</code></pre><h3 id="집계-함수">집계 함수</h3>
<pre><code class="language-python"># MonthlyIncome 합계
data[&#39;MonthlyIncome&#39;].sum()

# MonthlyIncome, TotalWorkingYears 각각의 평균
data[[&#39;MonthlyIncome&#39;, &#39;TotalWorkingYears&#39;]].mean()

max()
min()
count()</code></pre>
<h3 id="groupby">groupby()</h3>
<blockquote>
</blockquote>
<p>dataframe.groupby( ‘집계기준변수’, as_index = )[‘집계대상변수’].집계함수</p>
<ul>
<li>집계기준 변수 : ~~별 에 해당되는 변수 혹은 리스트. 범주형 변수 (예: 월 별, 지역 별 등)</li>
<li>집계대상 변수 : 집계함수로 집계할 변수 혹은 리스트. (예 : 매출액 합계 )</li>
<li>as_index = True → 집계기준변수를 인덱스로 사용</li>
<li>[[tip&#39;]].sum() → 결과가 데이터프레임이 됨</li>
</ul>
<pre><code class="language-python"># 집계 대상 열을 리스트로 지정
# day별 total_bill, tip 합계 조회
tip.groupby(&#39;day&#39;, as_index=False)[[&#39;total_bill&#39;, &#39;tip&#39;]].sum()

# 집계 기준 열을 여럿 설정 가능
# day + smoker별 total_bill, tip 합계 조회
tip.groupby([&#39;day&#39;, &#39;smoker&#39;], as_index=False)[[&#39;total_bill&#39;, &#39;tip&#39;]].sum()

# agg()
# day별 tip 합계, 평균, 최댓값, 최솟값
tip.groupby(&#39;day&#39;)[&#39;tip&#39;].agg([&#39;sum&#39;, &#39;mean&#39;, &#39;max&#39;, &#39;min&#39;])
# day별 total_bill 평균, tip 합계
tip.groupby(&#39;day&#39;, as_index=False).agg({&#39;total_bill&#39;:&#39;mean&#39;, &#39;tip&#39;:&#39;sum&#39;})</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AIVLE AI 6기] 무엇을 배우나요? 1주차-Git]]></title>
            <link>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-1%EC%A3%BC%EC%B0%A8-Git</link>
            <guid>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EB%AC%B4%EC%97%87%EC%9D%84-%EB%B0%B0%EC%9A%B0%EB%82%98%EC%9A%94-1%EC%A3%BC%EC%B0%A8-Git</guid>
            <pubDate>Mon, 30 Sep 2024 04:33:53 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is-git">What is Git?</h1>
<ul>
<li>가장 처음 배우는 만큼 개발자에게 Git은 중요하다.</li>
<li><strong>Git은 분산 버전관리 시스템</strong></li>
<li>프로젝트를 관리하고 협업 시 매우 유용함!!<br/>

</li>
</ul>
<h1 id="용어정리">용어정리</h1>
<h2 id="기본-개념">기본 개념</h2>
<h3 id="repository저장소">Repository(저장소)</h3>
<ul>
<li>코드와 관련된 모든 파일과 변경 내역을 저장하는 공간</li>
<li>프로젝트의 모든 데이터와 기록이 저장됨<h3 id="commit">Commit</h3>
</li>
<li><strong>변경 사항을 저장하는 단위</strong></li>
<li>커밋을 통해 파일의 상태를 저장</li>
<li>각 커밋은 고유한 해시 값을 가진다.
<img src="https://velog.velcdn.com/images/chane_ha_da/post/a3ba0b56-7b70-457d-8f01-0c12205117aa/image.png" alt=""><h3 id="branch">Branch</h3>
</li>
<li>독립적으로 작업할 수 있는 가지</li>
<li>메인 브랜치와는 별개로 개발하거나 새로운 기능을 추가할 때 사용</li>
<li>최종적으로 병합<h3 id="head">HEAD</h3>
</li>
<li>현재 작업 중인 브랜치의 최신 커밋을 가리키는 포인터</li>
<li><strong>작업하는 위치를 의미</strong></li>
</ul>
<h2 id="브랜치-관리-및-협업">브랜치 관리 및 협업</h2>
<h3 id="remote원격-저장소">Remote(원격 저장소)</h3>
<ul>
<li>온라인이나 네트워크 상에 있는 저장소</li>
<li><strong>GitHub등등</strong><h3 id="merge">Merge</h3>
</li>
<li>두 개의 브랜치를 하나로 합치는 작업</li>
<li>주로 기능 개발이 완료된 브랜치를 메인 브랜치에 병합<h3 id="clone">Clone</h3>
</li>
<li>원격 저장소의 모든 데이터를 로컬로 복사하는 작업<h3 id="pull">Pull</h3>
</li>
<li>원격 저장소의 변경 사항을 로컬 저장소로 가져오는 작업</li>
<li><strong>fetch + merge</strong><h3 id="push">Push</h3>
</li>
<li>로컬에서 작업한 내용을 원격 저장소에 업로드하는 작업</li>
</ul>
<h3 id="conflict충돌">Conflict(충돌)</h3>
<ul>
<li>두 브랜치나 커밋을 병합할 때 동일한 파일의 동일한 부분이 다르게 수정된 경우 발생하는 문제</li>
<li>수동으로 해결해야함!<h3 id="checkout">Checkout</h3>
</li>
<li>다른 브랜치로 전환하거나 특정 커밋으로 이동하는 작업</li>
<li>특정 브랜치나 커밋으로 작업 디렉토리를 변경</li>
</ul>
<h2 id="파일-및-변경사항-관리">파일 및 변경사항 관리</h2>
<h3 id="stash임시-저장">Stash(임시 저장)</h3>
<ul>
<li>현재 작업 중인 변경 사항을 임시로 저장하고, 작업 디렉토리를 깨끗한 상태로 만드는 기능</li>
</ul>
<h3 id="fetch">Fetch</h3>
<ul>
<li>원격 저장소에서 변경된 사항을 가져오지만, 자동으로 병합하지는 않음<br/>

</li>
</ul>
<h1 id="깃-사용-순서">깃 사용 순서</h1>
<h2 id="로컬-및-개인-사용시">로컬 및 개인 사용시</h2>
<ol>
<li>깃 저장소 생성 / 레포 생성</li>
<li>브랜치 생성</li>
<li>파일 생성</li>
<li>커밋</li>
<li>메인 브랜치에 병합</li>
</ol>
<h2 id="원격저장소-사용시">원격저장소 사용시</h2>
<ol>
<li>GitHub등에서 원격저장소 생성</li>
<li>로컬에서 원격저장소 등록</li>
<li>pull(fetch+merge)</li>
<li>파일 생성</li>
<li>커밋</li>
<li>push</li>
</ol>
<p><strong>반드시 작업전에 pull을 해야한다!</strong>
<br/></p>
<h1 id="추가학습git-명령어">(추가학습)Git 명령어</h1>
<h2 id="기본-설정">기본 설정</h2>
<h3 id="저장소-생성-및-파일-추가-커밋">저장소 생성 및 파일 추가, 커밋</h3>
<pre><code class="language-bash">git init
# 특정 파일 추가
git add user.js
# 현재 폴더를 대상으로 추가
git add .
# add 취소
git reset user.js
# 커밋
git commit -m &quot;Initial commit&quot;</code></pre>
<h3 id="브랜치">브랜치</h3>
<pre><code class="language-bash"># 현재 branch 확인
git branch
# branch 생성
git branch like_feature
# branch 전환
git checkout like_feature</code></pre>
<h3 id="merge-1">merge</h3>
<pre><code class="language-bash"># 원하는 branch로 이동
git checkout master
git merge like_feature

# merge한 branch 확인 후 삭제
git branch --merged
git branch -d like_feature</code></pre>
<h3 id="사용자-정보-설정">사용자 정보 설정</h3>
<pre><code class="language-bash">lobal user.name &quot;xoo0608&quot;
git config --global user.email xoo0608@gmail.com

# 프로젝트마다 다르도록
git config user.name &quot;ChaneHaDa&quot;
git config user.email chane.ha.da@gmail.com</code></pre>
<h2 id="원격저장소-사용">원격저장소 사용</h2>
<h3 id="기본">기본</h3>
<pre><code class="language-bash"># 원격 저장소 보기
git remote -v
# 원격 저장소 연결
git remote add origin https://gitlab.com/group/project
# 원격 저장소 확인
git remote</code></pre>
<h3 id="가져오기">가져오기</h3>
<pre><code class="language-bash"># 원격 저장소 복제
git clone https://gitlab.com/alwys/myproject.git
# Pull: 원격 저장소에서 데이터 가져오기 + 병합(Merge)
git pull origin &lt;branch name&gt;
git checkout -t origin/dev # 원격 브런치 가져오기
git checkout -f -t origin/dev
git checkout -b -t origin/dev # 이름바꾸어서 가져오기
# Fetch: 원격 저장소에서 데이터 가져오기 / 작업 후 병합
git fetch</code></pre>
<h3 id="push-1">push</h3>
<pre><code class="language-bash"># 저장소 발행 / Merge부터 해야함
git push origin master</code></pre>
<br/>

]]></description>
        </item>
        <item>
            <title><![CDATA[[AIVLE AI 6기] 왜 에이블 스쿨인가?]]></title>
            <link>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EC%99%9C-%EC%97%90%EC%9D%B4%EB%B8%94%EC%8A%A4%EC%BF%A8%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@chane_ha_da/AIVLE-AI-6%EA%B8%B0-%EC%99%9C-%EC%97%90%EC%9D%B4%EB%B8%94%EC%8A%A4%EC%BF%A8%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Sun, 29 Sep 2024 13:16:58 GMT</pubDate>
            <description><![CDATA[<h1 id="ai-부트캠프란">AI 부트캠프란?</h1>
<h2 id="부트캠프란">부트캠프란?</h2>
<ul>
<li>개발자를 양성하는 교육 프로그램을 의미함</li>
<li>팀 협업을 통한 프로젝트를 수행하며 개발자로 성장하는 교육 <h2 id="ai-부트캠프-종류">AI 부트캠프 종류</h2>
</li>
<li>대표적으로 3개 정도가 있다.<h3 id="카카오테크-부트캠프인공지능">카카오테크 부트캠프(인공지능)</h3>
<img src="https://velog.velcdn.com/images/chane_ha_da/post/bab9c4ae-6f13-42f8-aa9e-c9bb4ec5fc56/image.png" alt=""></li>
<li><strong>코딩테스트 및 면접 진행</strong></li>
<li>약 6개월 진행</li>
<li>실시간 온라인 학습</li>
<li>오프라인 팀 프로젝트(자체 해커톤)</li>
<li>현직자 특강 및 이력서, 포트폴리오 컨설팅</li>
</ul>
<h3 id="boostcampai-tech">Boostcamp(AI Tech)</h3>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/850a1b0b-e567-41e7-b9cb-881398369584/image.png" alt=""></p>
<ul>
<li><strong>코딩테스트 및 문제해결력 테스트 진행</strong></li>
<li>CV(Computer Vision), NLP(Natural Language Processing), RecSys(Recommender System)의 세개의 분야로 나누어서 모집</li>
<li>약 7개월 진행</li>
<li>도메인 별 학습 후 기업 해커톤 진행</li>
<li><strong>취업 간접 지원</strong></li>
</ul>
<h3 id="kt-aivle-school">KT AIVLE School</h3>
<p><img src="https://velog.velcdn.com/images/chane_ha_da/post/1bd9f9a9-2674-459f-bfd6-ecf088f64ddc/image.png" alt=""></p>
<ul>
<li><strong>코딩테스트 및 인적성 검사 진행</strong></li>
<li>약 6개월 진행</li>
<li>실시간 온라인 학습</li>
<li>한 과목마다 미니 프로젝트 이후 빅 프로젝트 진행</li>
<li>실제 현업에서 사용하는 방식으로 프로젝트 진행</li>
<li>AICE 자격증 지원</li>
<li>코딩마스터즈 등 역량 강화 프로그램 지원</li>
<li><strong>잡페어 및 채용 연계</strong><br/>

</li>
</ul>
<h1 id="why-aivle">Why AIVLE?</h1>
<h2 id="합격-후기">합격 후기</h2>
<ul>
<li>사실 위에서 작성한 3개의 부트캠프를 모두 합격하였고 기간이 달라 선택하는 것에 어려움이 있었다.
<img src="https://velog.velcdn.com/images/chane_ha_da/post/142500ae-784d-4313-9d72-e64611dfc81c/image.png" alt="">
<img src="https://velog.velcdn.com/images/chane_ha_da/post/54b95721-2e21-4f6d-83dc-86da5b7c8261/image.png" alt="">
<img src="https://velog.velcdn.com/images/chane_ha_da/post/2ccd1e04-476d-4a8f-a599-d86fdda88bf6/image.png" alt=""></li>
<li>3개의 부트캠프 모두 코딩테스트를 진행하였는데 <strong>기초적인 문제를 반드시 해결할 수 있을 것(DFS, BFS 등)</strong>이 제일 중요하다고 생각한다.</li>
<li>에이블 스쿨의 경우 인적성 검사를 진행한다. 수 많은 기업에서 진행하는 인적성 검사를 경험해 볼 수 있다는 장점이 있다.</li>
</ul>
<h2 id="aivle을-선택한-이유">AIVLE을 선택한 이유</h2>
<ul>
<li>사실 가장 큰 이유는 <strong>KT의 채용연계</strong> 이 부분이다. 잡페어 및 기타 채용 지원 부분에서 AIVLE만한 곳이 없었다.</li>
<li>또한, 백엔드 개발자를 희망하기도 하여서 AI 모델링 및 웹서비스 개발을 모두 경험할 수 있다는 점에서 크게 장점이 있었다.</li>
</ul>
<h2 id="aivle-합류-과정">AIVLE 합류 과정</h2>
<ol>
<li>내일 배움 카드 발급 및 수령</li>
<li>HRD-Net 온라인 수강 신청</li>
<li>AIVLE 아이디 발급</li>
<li>파이썬 및 시각화 사전교육(선택사항)</li>
<li>노트북 수령(분당 kt 본사)</li>
<li>교육 시작<br/>

</li>
</ol>
<h1 id="끝마치면서">끝마치면서</h1>
<p>백엔드 개발자로 꾸준히 학습을 진행하고 있었지만 AI에 대한 이해는 필수적으로 필요하다고 생각한다. 혼자서 공부하기 힘든 부분이 있기 때문에 KT AIVLE School을 통해서 학습해보고자 한다. 다음에는 배운 것을 토대로 글을 작성하겠다~!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] Entity, Repository]]></title>
            <link>https://velog.io/@chane_ha_da/JPA-Entity-Repository</link>
            <guid>https://velog.io/@chane_ha_da/JPA-Entity-Repository</guid>
            <pubDate>Tue, 13 Aug 2024 12:38:03 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is-entity">What is Entity?</h1>
<ul>
<li>데이터 모델링에서 사용되는 객체 </li>
<li>데이터 베이스 테이블<br/>

</li>
</ul>
<h1 id="what-is-repository">What is Repository</h1>
<ul>
<li>데이터 베이스 테이블에 접근하기 위해 사용하는 인터페이스</li>
<li>실제로 DB에 접근하는 객체<br/>

</li>
</ul>
<h1 id="entity">Entity</h1>
<h3 id="기본-코드">기본 코드</h3>
<pre><code class="language-java">@Entity
@Table(name = &quot;PERSON&quot;, uniqueConstraints = {
        @UniqueConstraint(name = &quot;NAME_AGE_UNIQUE&quot;, columnNames = {&quot;NAME&quot;, &quot;AGE&quot;})
}) //제약조건 설정
@Access(AccessType.FIELD) // 직적 접근 -&gt; if @Id 가 있으면
@Access(AccessType.PROPERTY) //getter 사용 
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO) 
    //IDENTITY, SEQUENCE, TABLE, AUTO(자동으로 선택)
    private Long id;
    private String name

    @Enumerated(EnumType.STRING) //Enum의 이름값 저장
    //@Enumerated(EnumType.ORDINAL) //Enum의 순서 저장
    private String role;

    @Transient // 매핑을 하지 않음
    private String description;

    @Temporal(TemporalType.DATE) //날짜
    @Temporal(TemporalType.TIME) //시간
    @Temporal(TemporalType.TIMESTAMP) //날짜 + 시간
      private Date regDate;

      @Column(unique = true)
      @Column(columnDefinition = &quot;varchar(100) default &#39;EMPTY&#39;&quot;)
      @Column(nullable = false)
      @Column(length = 400)
      @Column(precision = 10, scale = 2) //precision, 자릿수 / scale, 소수점 
}</code></pre>
<ul>
<li>기본 생성자는 필수이다.</li>
</ul>
<h3 id="클래스-어노테이션-정리">클래스 어노테이션 정리</h3>
<ul>
<li><p>@Entity: 엔티티임을 선언</p>
</li>
<li><p>@Table: 테이블의 이름과 제약조건을 설정할 수 있음</p>
</li>
<li><blockquote>
<p>@UniqueConstraint: 제약 조건을 설정</p>
</blockquote>
</li>
<li><p>@Access: 접근 방식 설정</p>
</li>
<li><blockquote>
<p>AccessType.FIELD: 직접 접근</p>
</blockquote>
</li>
<li><blockquote>
<p>AccessType.PROPERTY: getter 사용해서 접근</p>
</blockquote>
<h4 id="accesstypeproperty">AccessType.PROPERTY</h4>
<pre><code class="language-java">@Entity
@Access(AccessType.FIELD) // 직적 접근 -&gt; if @Id 가 있으면
@Access(AccessType.PROPERTY) //getter 사용 
public class Person {
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO) 
   private Long id;

   @Transient
   private String firstName;

   @Transient
   private String lastName;

     @Access(AccessType.PROPERTY)
     public String getFullName() {
         return firstName + lastName;
     }
</code></pre>
</li>
</ul>
<p>}</p>
<pre><code>* 다음과 같은 방식으로 Getter를 이용하여 접근

### 변수 어노테이션 정리
* @Id: 기본키(Primary key)를 설정
* @GeneratedValue(strategy = GenerationType.AUTO): 기본키를 조건에 따라 자동으로 생성함
* @Enumerated: Enum 사용을 위한 것
-&gt; EnumType.STRING: 이름값 저장
-&gt; EnumType.ORDINAL: 순서 저장
* @Transient: 매핑을 하지 않음, 테이블에 저장 X
* @Temporal:날짜 타입 지정
* @Column: 컬럼 지정
&lt;br/&gt;

# Repository
```java
public interface PersonRepository extends JpaRepository&lt;Person, Long&gt; {
}
</code></pre><ul>
<li>다음과 같이 선언이 가능하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] JPA 시작하기]]></title>
            <link>https://velog.io/@chane_ha_da/JPA-JPA-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@chane_ha_da/JPA-JPA-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 12 Aug 2024 12:35:54 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is">What is?</h1>
<ul>
<li>JPA는 Java Persistence API의 약자로 자바 진영에서 ORM 기술 표준으로 사용 되는 인터페이스의 모음</li>
</ul>
<h3 id="orm">ORM?</h3>
<ul>
<li>Object-Relational Mapping의 약자로 Class와 테이블을 매핑하는 기술</li>
<li>객체를 RDB의 테이블에 연결해주는 기술</li>
<li>SQL을 작성하지 않고 DB를 조작하여 비즈니스 로직에 집중 할 수 있음</li>
</ul>
<h1 id="jpa와-hibernate-jdbc">JPA와 Hibernate, JDBC</h1>
<h3 id="jdbc">JDBC</h3>
<ul>
<li>Java Database Connectivity의 약자</li>
<li>Java에서 DB에 접근할 수 있도록 제공하는 API</li>
<li>영속성 레이어를 만들기 위한 것</li>
<li><blockquote>
<p>데이터를 생성한 프로그램이 종료되어도 존재하기 위함</p>
</blockquote>
</li>
</ul>
<h3 id="hibernate">Hibernate</h3>
<ul>
<li>JPA는 인터페이스를 구현하여 사용해야함</li>
<li>Hibernate는 JPA의 구현체 중 하나
<img src="https://velog.velcdn.com/images/chane_ha_da/post/72183c55-be4b-4b1c-bd36-0c2c9d21d696/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MSA Prepare] Zipkin을 활용한 Distributed Tracing]]></title>
            <link>https://velog.io/@chane_ha_da/MSA-Prepare-Zipkin%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-Distributed-Tracing</link>
            <guid>https://velog.io/@chane_ha_da/MSA-Prepare-Zipkin%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-Distributed-Tracing</guid>
            <pubDate>Tue, 25 Jun 2024 13:34:09 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is">What is?</h1>
<ul>
<li>분산된 메시지를 추적하는 방식</li>
<li>여러개의 서비스들의 호출등을 추적하는 방식<br/>

</li>
</ul>
<h1 id="zipkin-사용하기">Zipkin 사용하기</h1>
<ul>
<li>docker을 사용해서 실행하였다.<pre><code class="language-bash">  docker run -p 9411:9411 --rm openzipkin/zipkin</code></pre>
<br/>

</li>
</ul>
<h1 id="client-설정하기">Client 설정하기</h1>
<h3 id="dependencies">dependencies</h3>
<pre><code>dependencies {
    implementation &#39;io.micrometer:micrometer-observation&#39;
    implementation &#39;io.micrometer:micrometer-tracing-bridge-otel&#39;
    implementation &#39;io.opentelemetry:opentelemetry-exporter-zipkin&#39;

    //Brave as Bridge
    implementation &#39;io.micrometer:micrometer-tracing-bridge-brave&#39;
    implementation &#39;io.zipkin.reporter2:zipkin-reporter-brave&#39;

    //Uses Feign
    implementation &#39;io.github.openfeign:feign-micrometer&#39;
}</code></pre><h3 id="설정하기">설정하기</h3>
<pre><code>management.tracing.sampling.probability=1.0
logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]</code></pre><ul>
<li>샘필링할 확률을 설정 1.0은 모두 출력함</li>
<li>logging.pattern.level 로그의 패턴을 설정<br/></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MSA Prepare] resilience4j을 활용한 Circuit Breaker]]></title>
            <link>https://velog.io/@chane_ha_da/MSA-Prepare-resilience4j%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-Circuit-Breaker</link>
            <guid>https://velog.io/@chane_ha_da/MSA-Prepare-resilience4j%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-Circuit-Breaker</guid>
            <pubDate>Sat, 22 Jun 2024 06:50:02 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is">What is?</h1>
<ul>
<li>서비스 호출에서 장애가 발생하면 다른 서비스로 장애가 전파된다.</li>
<li>요청이 계속 쌓이다 보면 복구가 어렵다.</li>
<li>장애가 발생한 서비스를 탐지하고, 요청을 보내지 않도록 차단하는 디자인 패턴이 Circuit Breaker이다.<br/>

</li>
</ul>
<h1 id="use">Use</h1>
<h3 id="dependencies">dependencies</h3>
<pre><code>dependencies {
    implementation &#39;org.springframework.boot:spring-boot-starter-actuator&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-aop&#39;
    implementation &#39;io.github.resilience4j:resilience4j-spring-boot3&#39;
}</code></pre><ul>
<li>쉬운 적용을 위해서 aop를 추가적으로 사용하는 것이 좋다.</li>
</ul>
<h3 id="설정하기">설정하기</h3>
<ul>
<li>application.properties<pre><code>resilience4j.retry.instances.sample-api.maxAttempts=5
resilience4j.retry.instances.sample-api.waitDuration=1s
resilience4j.retry.instances.sample-api.enableExponentialBackoff=true
</code></pre></li>
</ul>
<p>#resilience4j.circuitbreaker.instances.default.failureRateThreshold=90</p>
<p>resilience4j.ratelimiter.instances.default.limitForPeriod=2
resilience4j.ratelimiter.instances.default.limitRefreshPeriod=10s</p>
<p>resilience4j.bulkhead.instances.default.maxConcurrentCalls=10
resilience4j.bulkhead.instances.sample-api.maxConcurrentCalls=10</p>
<pre><code>* maxAttempts: 재시도 방식의 최대 시도횟수를 정한다.
* waitDuration: 기다리는 시간 설정
* enableExponentialBackoff: 재요청 시간 간격 점차 증가

### Code
* Controller.java
```java
@RestController
public class CircuitBreakerController {

    private Logger logger =
            LoggerFactory.getLogger(CircuitBreakerController.class);

    @GetMapping(&quot;/sample-api&quot;)
    //@Retry(name = &quot;sample-api&quot;, fallbackMethod = &quot;hardcodedResponse&quot;)
    //@CircuitBreaker(name = &quot;default&quot;, fallbackMethod = &quot;hardcodedResponse&quot;)
    //@RateLimiter(name=&quot;default&quot;)
    @Bulkhead(name=&quot;sample-api&quot;)
    //10s =&gt; 10000 calls to the sample api
    public String sampleApi() {
        logger.info(&quot;Sample api call received&quot;);
//        ResponseEntity&lt;String&gt; forEntity = new RestTemplate().getForEntity(&quot;http://localhost:8080/some-dummy-url&quot;,
//                    String.class);
//        return forEntity.getBody();
        return &quot;sample-api&quot;;
    }

    public String hardcodedResponse(Exception ex) {
        return &quot;fallback-response&quot;;
    }
}</code></pre><ul>
<li>@Retry: 오류 발생시 재시작</li>
<li>@CircuitBreaker: 지정한 실패률 초과시 차단</li>
<li>@RateLimiter: 초당 허용하는 건수 설정</li>
<li>@Bulkhead: 동시 호출을 수를 제한하는 방식</li>
<li>fallbackMethod: 예비로 실행할 함수, 기본 함수와 리턴 값이 같아야한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MSA Prepare] Spring Cloud Gateway를 이용한 Swagger API 통합 문서 적용하기]]></title>
            <link>https://velog.io/@chane_ha_da/MSA-Prepare-Spring-Cloud-Gateway%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Swagger-API-%ED%86%B5%ED%95%A9-%EB%AC%B8%EC%84%9C-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@chane_ha_da/MSA-Prepare-Spring-Cloud-Gateway%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Swagger-API-%ED%86%B5%ED%95%A9-%EB%AC%B8%EC%84%9C-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 22 Jun 2024 06:49:01 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is">What is?</h1>
<ul>
<li>API들은 REST 방식을 이용하여 호출한다.</li>
<li>각 서비스별로 Swagger를 적용하여서 문서화 하였다.</li>
<li>Gateway를 활용해서 통합 문서를 사용하자<br/>

</li>
</ul>
<h1 id="in-gateway">In Gateway</h1>
<h3 id="dependencies">dependencies</h3>
<pre><code>dependencies {
    implementation &#39;org.springframework.boot:spring-boot-starter-webflux&#39;
    implementation &#39;org.springdoc:springdoc-openapi-starter-webflux-ui:2.4.0&#39;
}</code></pre><ul>
<li>Gateway는 webflux 방식이기 때문에 위와 같이 추가해야한다.</li>
</ul>
<h3 id="설정하기">설정하기</h3>
<ul>
<li>application.properties<pre><code>springdoc.swagger-ui.use-root-path=true
</code></pre></li>
</ul>
<p>springdoc.swagger-ui.urls[0].name=securities-service
springdoc.swagger-ui.urls[0].url=<a href="http://localhost:8765/api/securities-service/v3/api-docs">http://localhost:8765/api/securities-service/v3/api-docs</a></p>
<pre><code>* springdoc.swagger-ui.use-root-path: 루트 접근 시 swagger 페이지로 이동한다.
* springdoc.swagger-ui.urls[0].name: 서비스 이름 지정
* springdoc.swagger-ui.urls[0].url: 서비스의 정보 URL

### Gateway 설정
* ApiGateWayConfig.java
```java
@Configuration
public class ApiGateWayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeBuilder) {
        return routeBuilder.routes()
                .route(&quot;securities-service-openapi&quot;, r -&gt; {
                    return r.path(&quot;/api/securities-service/v3/api-docs/**&quot;)
                            .filters(f -&gt; f.rewritePath(
                                    &quot;/api/securities-service/(?&lt;path&gt;.*)&quot;, &quot;/${path}&quot;))
                            .uri(&quot;lb://SECURITIES-SERVICE&quot;);
                })
                .route(&quot;securities-service&quot;, r -&gt; {
                    return r.path(&quot;/stockprice/**&quot;, &quot;/stockinfo/**&quot;)
                            .uri(&quot;lb://SECURITIES-SERVICE&quot;);
                })
                .build();
    }
}
</code></pre><ul>
<li>위의 라우터는 사용자의 요청을 문서에 접근하게 하기 위해서</li>
<li>밑의 라우터는 사용자의 API 호출을 처리하기 위해서<br/>

</li>
</ul>
<h1 id="client">Client</h1>
<h3 id="swagger-config">Swagger config</h3>
<ul>
<li><p>SwaggerConfig.java</p>
<pre><code class="language-java">@Configuration
public class SwaggerConfig {
  @Bean
  public OpenAPI openAPI() {
      return new OpenAPI()
              .components(new Components())
              .addServersItem(new Server().url(&quot;/&quot;))
              .info(apiInfo());
  }

  private Info apiInfo() {
      return new Info()
              .title(&quot;Securities service&quot;)
              .description(&quot;Stock information service&quot;)
              .version(&quot;1.0.0&quot;);
  }
}
</code></pre>
</li>
</ul>
<p>```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MSA Prepare] Spring Cloud Gateway]]></title>
            <link>https://velog.io/@chane_ha_da/MSA-Prepare-Spring-Cloud-Gateway</link>
            <guid>https://velog.io/@chane_ha_da/MSA-Prepare-Spring-Cloud-Gateway</guid>
            <pubDate>Wed, 19 Jun 2024 13:35:59 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is">What is?</h1>
<ul>
<li>Spring Cloud Gateway는 API Gateway를 제공</li>
<li>API들의 단일지점을 제공</li>
<li>API들에 공통된 작업을 수행할 수 있음(Filter)</li>
<li>로깅, 모니터링 가능<br/>

</li>
</ul>
<h1 id="use">USE</h1>
<ul>
<li>Eureka 서버를 같이 사용함<h3 id="dependencies">dependencies</h3>
<pre><code class="language-gradle">dependencies {
  implementation &#39;org.springframework.cloud:spring-cloud-starter-gateway&#39;
  implementation &#39;org.springframework.cloud:spring-cloud-starter-netflix-eureka-client&#39;
}</code></pre>
<h3 id="설정하기">설정하기</h3>
</li>
<li>application.properties<pre><code>spring.application.name=api-gateway
server.port=8765
</code></pre></li>
</ul>
<p>eureka.client.serviceUrl.defaultZone=<a href="http://localhost:8761/eureka">http://localhost:8761/eureka</a></p>
<p>spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.discovery.locator.lower-case-service-id=true</p>
<pre><code>* 이제 다음과 같이 localhost:8765/SERVICE-NAME을 통해서 접근이 가능하다.
* spring.cloud.gateway.discovery.locator.lower-case-service-id 다음 설정을 통해 소문자의 경우도 접근이 가능하다.

### 좀 더 설정하기
* ApiGatewayConfiguration.java
```java
@Configuration
public class ApiGatewayConfiguration {

    @Bean
    public RouteLocator gatewayRouter(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(p -&gt; p
                        .path(&quot;/get&quot;)
                        .filters(f -&gt; f
                                .addRequestHeader(&quot;MyHeader&quot;, &quot;MyURI&quot;)
                                .addRequestParameter(&quot;Param&quot;, &quot;MyValue&quot;))
                        .uri(&quot;http://httpbin.org:80&quot;))
                .route(p -&gt; p.path(&quot;/currency-exchange/**&quot;)
                        .uri(&quot;lb://currency-exchange&quot;))
                .route(p -&gt; p.path(&quot;/currency-conversion/**&quot;)
                        .uri(&quot;lb://currency-conversion&quot;))
                .route(p -&gt; p.path(&quot;/currency-conversion-feign/**&quot;)
                        .uri(&quot;lb://currency-conversion&quot;))
                .route(p -&gt; p.path(&quot;/currency-conversion-new/**&quot;)
                        .filters(f -&gt; f.rewritePath(
                                &quot;/currency-conversion-new/(?&lt;segment&gt;.*)&quot;,
                                &quot;/currency-conversion-feign/${segment}&quot;))
                        .uri(&quot;lb://currency-conversion&quot;))
                .build();
    }
}
</code></pre><ul>
<li>다음과 같은 route를 통해 사용자의 요청을 라우팅 할 수있다.</li>
<li>filter를 적용하여 작업을 수행할 수 있다.</li>
<li>rewritePathsms 사용자의 요청을 변환한다.<br/>

</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MSA Prepare] Eureka Server을 활용한 Service Discovery]]></title>
            <link>https://velog.io/@chane_ha_da/MSA-Prepare-Eureka-Server%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-Service-Discovery</link>
            <guid>https://velog.io/@chane_ha_da/MSA-Prepare-Eureka-Server%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-Service-Discovery</guid>
            <pubDate>Mon, 17 Jun 2024 13:55:52 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is-eureka-server">What is Eureka Server</h1>
<ul>
<li>MSA에서 서비스간 호출이 필요한 경우가 많다.</li>
<li>서비스간 호출을 위해서는 IP등의 정보를 가지고 있어야 한다.</li>
<li><strong>서비스 호출에 필요한 정보를 저장하고 도움을 주는 것이 Eureka Server</strong></li>
<li>로드밸런싱의 기능도 지원한다.<br/>

</li>
</ul>
<h1 id="server-사용하기">Server 사용하기</h1>
<h3 id="dependencies">dependencies</h3>
<pre><code class="language-gradle">implementation &#39;org.springframework.cloud:spring-cloud-starter-netflix-eureka-server&#39;</code></pre>
<h3 id="applicationjava">Application.java</h3>
<pre><code class="language-java">@EnableEurekaServer
@SpringBootApplication
class NamingServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(NamingServerApplication.class, args);
    }

}</code></pre>
<ul>
<li>@EnableEurekaServer 다음의 어노테이션을 추가해야한다.</li>
</ul>
<h3 id="설정">설정</h3>
<ul>
<li>application.properties<pre><code>spring.application.name=naming-server
server.port=8761
</code></pre></li>
</ul>
<p>eureka.client.register-with-eureka=false # 자신을 등록할지
eureka.client.fetch-registry=false # 레지스트리에 정보를 가져올지</p>
<h1 id="디버깅에-유용함">디버깅에 유용함</h1>
<p>eureka.instance.prefer-ip-address=true
eureka.instance.hostname=localhost</p>
<pre><code>&lt;br/&gt;

# Client 사용하기
### dependencies
```gradle
implementation &#39;org.springframework.cloud:spring-cloud-starter-netflix-eureka-client&#39;</code></pre><h3 id="설정-1">설정</h3>
<ul>
<li>application.properties<pre><code>eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka</code></pre></li>
<li>기본적으로 알아서 등록한다.</li>
</ul>
<h3 id="feign-사용시">Feign 사용시</h3>
<pre><code class="language-java">@FeignClient(name=&quot;my-service&quot;)</code></pre>
<ul>
<li>다음과 같이 서비스명으로 접근이 가능하다.<br/></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MSA Prepare] OpenFeign을 사용한 서비스간 호출]]></title>
            <link>https://velog.io/@chane_ha_da/MSA-Prepare-OpenFeign%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%84%9C%EB%B9%84%EC%8A%A4%EA%B0%84-%ED%98%B8%EC%B6%9C</link>
            <guid>https://velog.io/@chane_ha_da/MSA-Prepare-OpenFeign%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%84%9C%EB%B9%84%EC%8A%A4%EA%B0%84-%ED%98%B8%EC%B6%9C</guid>
            <pubDate>Thu, 13 Jun 2024 10:32:01 GMT</pubDate>
            <description><![CDATA[<h1 id="what-is-feign">What is Feign?</h1>
<ul>
<li>인터페이스와 어노테이션 기반으로 REST 호출이 가능</li>
<li>Eureka등의 다른 기술들과 통합 가능</li>
<li>서비스간 호출을 위해서 사용<h3 id="단점-및-한계">단점 및 한계</h3>
</li>
<li>Http2를 지원하지 않음</li>
<li>공식적으로 Reactive 모델을 지원하지 않음<br/>

</li>
</ul>
<h1 id="사용하기">사용하기</h1>
<h3 id="dependencies">dependencies</h3>
<pre><code class="language-gradle">implementation &#39;org.springframework.cloud:spring-cloud-starter-openfeign&#39;</code></pre>
<h3 id="applicationjava">Application.java</h3>
<pre><code class="language-java">@SpringBootApplication
@EnableFeignClients
public class ServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }

}</code></pre>
<ul>
<li>@EnableFeignClients 다음의 어노테이션의 추가가 필요하다.</li>
</ul>
<h3 id="proxy-interface">Proxy interface</h3>
<pre><code class="language-java">@FeignClient(name=&quot;restservice&quot;, url=&quot;localhost:8000&quot;)
public interface RestProxy {
    @GetMapping(&quot;/team&quot;)
    public NewTeam hello();
}</code></pre>
<ul>
<li>다음과 같이 restservice의 서비스를 가져와서 사용할 수 있다.</li>
<li>Eureka를 적용하면 url을 사용하지 않아도 호출이 가능하다.</li>
</ul>
<h3 id="use">Use</h3>
<pre><code class="language-java">@RestController
public class Controller {
    @Autowired
    private RestProxy restProxy;

    @GetMapping(&quot;/myteam&quot;)
    public NewTeam retrieveMyTeam() {
        NewTeam team = restProxy.hello();
        return team;
    }
}</code></pre>
<br/>]]></description>
        </item>
    </channel>
</rss>