<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>waterglasses_k.log</title>
        <link>https://velog.io/</link>
        <description>잘 하고 있는겨?</description>
        <lastBuildDate>Tue, 16 Apr 2024 10:59:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>waterglasses_k.log</title>
            <url>https://velog.velcdn.com/images/waterglasses_k/profile/7a40355d-8430-4531-be89-6fd3f92a8811/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. waterglasses_k.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/waterglasses_k" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[python_법정동 충전소 데이터 시각화(folium, 최단거리)]]></title>
            <link>https://velog.io/@waterglasses_k/python%EB%B2%95%EC%A0%95%EB%8F%99-%EC%B6%A9%EC%A0%84%EC%86%8C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%8B%9C%EA%B0%81%ED%99%94folium-%EC%B5%9C%EB%8B%A8%EA%B1%B0%EB%A6%AC</link>
            <guid>https://velog.io/@waterglasses_k/python%EB%B2%95%EC%A0%95%EB%8F%99-%EC%B6%A9%EC%A0%84%EC%86%8C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%8B%9C%EA%B0%81%ED%99%94folium-%EC%B5%9C%EB%8B%A8%EA%B1%B0%EB%A6%AC</guid>
            <pubDate>Tue, 16 Apr 2024 10:59:45 GMT</pubDate>
            <description><![CDATA[<p>동별 충전접근성을 확인해보기로한다.</p>
<ol>
<li>법정동별 인근 충전소 평균 거리 순위</li>
<li>인근 급속 충전소 거리가 500m가 넘는 충전소 개수</li>
</ol>
<h3 id="충전소간-거리-구하기">충전소간 거리 구하기</h3>
<p>우선 급속충전소 데이터만 뺀다</p>
<pre><code class="language-python">charger_fast_df = charger_dong_df[charger_dong_df[&#39;기종(대)&#39;] == &#39;급속&#39;].reset_index(drop = True)
charger_fast_df.head(3)</code></pre>
<p>좌표 데이터에서 자기 자신과 같은 좌표는 제외하고 가장 가까운 좌표를 찾는다.</p>
<pre><code class="language-python"># 충전소 좌표에 대한 중복값을 제거하여 charger_point 생성
charger_point2 = charger_fast_df[[&#39;위도&#39;, &#39;경도&#39;]].drop_duplicates().reset_index(drop=True)

# 인근충전소위도, 인근충전소경도 컬럼을 charger_point에 추가하고 초기화
charger_point2[&#39;인근충전소위도&#39;] = None
charger_point2[&#39;인근충전소경도&#39;] = None

# NearestNeighbors 모델을 사용하여 가장 가까운 인근 충전소 찾기
X = charger_point2[[&#39;위도&#39;, &#39;경도&#39;]]
nbrs = NearestNeighbors(n_neighbors=2, algorithm=&#39;ball_tree&#39;).fit(X)

# 가장 가까운 인근 충전소 찾아서 인근충전소위도, 인근충전소경도 컬럼에 할당
def find_nearest_neighbor(row):
    # 현재 충전소의 좌표를 제외한 가장 가까운 이웃의 인덱스 찾기
    distances, indices = nbrs.kneighbors([row[[&#39;위도&#39;, &#39;경도&#39;]]])
    nearest_index = indices[0][1]  # 자기 자신을 제외한 가장 가까운 이웃의 인덱스
    nearest_row = charger_point2.iloc[nearest_index]
    # 자기 자신과 동일한 좌표를 가진 행이 있으면 두 번째로 가까운 이웃 선택
    while (nearest_row[&#39;위도&#39;] == row[&#39;위도&#39;]) and (nearest_row[&#39;경도&#39;] == row[&#39;경도&#39;]):
        nearest_index = (nearest_index + 1) % len(charger_point2)  # 인덱스를 순환하도록 수정
        nearest_row = charger_point2.iloc[nearest_index]
    row[&#39;인근충전소위도&#39;] = nearest_row[&#39;위도&#39;]
    row[&#39;인근충전소경도&#39;] = nearest_row[&#39;경도&#39;]
    return row

# 충전소 좌표별로 가장 가까운 인근 충전소를 찾아서 인근충전소위도, 인근충전소경도 컬럼에 할당
charger_fast_df[[&#39;인근충전소위도(급속)&#39;, &#39;인근충전소경도(급속)&#39;]] = charger_fast_df[[&#39;위도&#39;, &#39;경도&#39;]].apply(find_nearest_neighbor, axis=1)[[&#39;인근충전소위도&#39;, &#39;인근충전소경도&#39;]]</code></pre>
<p>찾은 좌표로 최단거리를 계산한다</p>
<pre><code class="language-python">#인근 충전소와의 거리 계산

# 위도와 경도 간의 직선 거리를 계산하는 함수
def haversine(lat1, lon1, lat2, lon2):
    R = 6371  # 지구의 반지름 (단위: km)
    dlat = np.radians(lat2 - lat1)
    dlon = np.radians(lon2 - lon1)
    a = np.sin(dlat / 2) * np.sin(dlat / 2) + np.cos(np.radians(lat1)) * np.cos(np.radians(lat2)) * np.sin(dlon / 2) * np.sin(dlon / 2)
    c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a))
    distance = R * c * 1000  # 미터 단위로 변환
    return distance

# 위도와 경도 간의 직선 거리를 계산하여 인근충전소거리 컬럼에 추가
charger_fast_df[&#39;인근충전소거리(급속)&#39;] = charger_fast_df.apply(lambda row: haversine(row[&#39;위도&#39;], row[&#39;경도&#39;], row[&#39;인근충전소위도(급속)&#39;], row[&#39;인근충전소경도(급속)&#39;]), axis=1)</code></pre>
<p>언제쯤 코드를 스스로 쓸 수 있을가...</p>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/eda66c91-b73f-46bb-aabe-a85b81301833/image.png" alt="">
시각화 해보면 대충 이런 모습
그래도 대부분의 충전소가 반경 500m이내에는 위치해있다.</p>
<h3 id="법정동별-인근-충전소-평균-거리-순위">법정동별 인근 충전소 평균 거리 순위</h3>
<pre><code class="language-python">bdong_nearly_charger_df = pd.DataFrame(charger_fast_df.groupby([&#39;군구&#39;,&#39;법정동코드&#39;, &#39;법정동명&#39;,&#39;법정동중심위도&#39;,&#39;법정동중심경도&#39;])[&#39;인근충전소거리(급속)&#39;].mean()).sort_values(by = &#39;인근충전소거리(급속)&#39;, ascending=False)
bdong_nearly_charger_df.reset_index(inplace = True)
bdong_nearly_charger_df</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/00626ad4-0ace-4f5d-b47e-5ba9b5c32993/image.png" alt=""></p>
<h3 id="지도시각화">지도시각화</h3>
<p>시각화를 하려면 우선 법정동 구역을 지도에 표시해야한다.
folium은 json파일을 쓰는데 법정동 경계 좌표 데이터가 json형식이 아무리 찾아도 없다.(행정동만 보임)
결국 수기로 변환해주었다.</p>
<ul>
<li><a href="http://www.gisdeveloper.co.kr/?p=2332">http://www.gisdeveloper.co.kr/?p=2332</a>
이곳에서 읍면동 데이터를 받은 후 아래 사이트를 참고해서 json파일로 변환했다.</li>
<li><a href="https://park9eon.com/how-to-convert-to-korea-shp-geojson/">https://park9eon.com/how-to-convert-to-korea-shp-geojson/</a></li>
</ul>
<p>아래 코드부터 다시 시작,
깨지는 글자로 encoding 추가.
지도 경계데이터라 좌표가 무지 많다. 그래서 서울시 코드(11)만 불러와서 변수에 저장한다.</p>
<pre><code class="language-python">#법정동 경계 좌표 json파일 불러오기
# JSON 파일 경로
json_file_path = &#39;/Users/sookyeong/Documents/내배캠/팀프로젝트/project5_final/emd (2).json&#39;

# JSON 파일 열기
with open(json_file_path, &#39;r&#39;, encoding=&#39;utf-8&#39;) as f:
    geo_data = json.load(f)

# EMD_CD가 앞 두글자가 &#39;11&#39;인 데이터만 필터링
filtered_features = [feature for feature in geo_data[&#39;features&#39;] if feature[&#39;properties&#39;][&#39;EMD_CD&#39;][:2] == &#39;11&#39;]

# 필터링된 데이터로 새로운 GeoJSON 생성
filtered_geo_data = {
    &#39;type&#39;: &#39;FeatureCollection&#39;,
    &#39;features&#39;: filtered_features
}</code></pre>
<p>웬걸 아무 생각없이 시각화하려고 해도 지도가 제대로 안뜬다.
좌표계가 wgs84가 아니었던 것.
27.xxx, 135.xxx이런식으로 변환해주기 위해 다시 작업</p>
<pre><code class="language-python">#wgs84 좌표계로 변환
import geopandas as gpd
import json

# GeoJSON 데이터를 GeoDataFrame으로 변환
gdf = gpd.GeoDataFrame.from_features(filtered_geo_data)

# 좌표계를 WGS84로 변환
gdf.crs = &quot;EPSG:5179&quot;

# 좌표계가 설정된 상태에서 다시 변환
gdf_wgs84 = gdf.to_crs(epsg=4326)

# GeoDataFrame을 GeoJSON 형식으로 변환
wgs84_geojson = gdf_wgs84.to_json()

# 필요한 경우 딕셔너리로 다시 변환
wgs84_geojson_dict = json.loads(wgs84_geojson)

wgs84_geojson_dict</code></pre>
<p>변환해준 좌표를 사용해서 folium 시각화</p>
<pre><code class="language-python">import folium

# Folium 지도 객체 생성
m = folium.Map(location=[37.55, 126.98], zoom_start=11, tiles=&#39;cartodbpositron&#39;)

folium.Choropleth(
    geo_data=wgs84_geojson_dict,
    data=bdong_nearly_charger_df,
    columns=[&#39;법정동코드&#39;, &#39;인근충전소거리(급속)&#39;],
    fill_color=&#39;PuBu&#39;,
    key_on=&#39;feature.properties.EMD_CD&#39;,  # GeoJSON 데이터에서 특정 속성 값의 키를 지정합니다.
    highlight=True,
    fill_opacity=0.5,
    line_opacity=0.5,
    legend_name=&#39;급속충전소&#39;,
    nan_fill_color=&#39;none&#39;
).add_to(m)

# Folium 지도 객체 출력
m</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/540ec786-9e9d-4a38-a515-ac9bfa233d11/image.png" alt="">
차충비, 인구밀도, 교통량등에도 지도를 사용할 수 있을 것 같다.
뭐하나 쉬운게 없는 ㅠ^ㅠ..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[python_법정동 중심점 좌표 구하기]]></title>
            <link>https://velog.io/@waterglasses_k/python%EB%B2%95%EC%A0%95%EB%8F%99-%EC%A4%91%EC%8B%AC%EC%A0%90-%EC%A2%8C%ED%91%9C-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@waterglasses_k/python%EB%B2%95%EC%A0%95%EB%8F%99-%EC%A4%91%EC%8B%AC%EC%A0%90-%EC%A2%8C%ED%91%9C-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 15 Apr 2024 06:46:47 GMT</pubDate>
            <description><![CDATA[<p>급속 충전소 최적 입지 선정 프로젝트 중 현재의 충전소간 거리를 확인해보고자 한다.
현재의 충전소간 거리가 멀면 충전소 입지가 더 필요할 것이고 거리가 짧으면 그렇지 않을 것이다.</p>
<h3 id="1-법정동-중심점-좌표-구하기">1. 법정동 중심점 좌표 구하기</h3>
<p>이는 geopandas를 사용하는데, 우선 우리나라 최신 행정구역 shp파일을 받아둔다. 
읍면동  데이터의 최신 버전을 다운로드 받았다.
<a href="http://www.gisdeveloper.co.kr/?p=2332">http://www.gisdeveloper.co.kr/?p=2332</a>
<img src="https://velog.velcdn.com/images/waterglasses_k/post/bd85c47d-e3e8-4acd-a6e1-dca991700dd5/image.png" alt=""></p>
<h3 id="2-중심좌표-구하기">2. 중심좌표 구하기</h3>
<pre><code class="language-python"># 라이브러리 호출
import geopandas as gpd

# 서울시 법정동 경계 데이터 불러오기
dong_boundary = gpd.read_file(&#39;/Users/sookyeong/Documents/내배캠/팀프로젝트/project5_final/emd.shp&#39;, encoding=&#39;cp949&#39;)</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/66f6ef96-5b1a-4f2f-aceb-64fa5af10831/image.png" alt="">
파일을 불러오면 평소 사용하는 WGS84 좌표가 아니다.
우선 CSR로 EPSG:5179으로 변환해주어야 한다.</p>
<pre><code class="language-python"># CRS 설정
dong_boundary.crs = &#39;EPSG:5179&#39;  </code></pre>
<p>&#39;EPSG:5179&#39;는 GeoDataFrame의 좌표 참조 시스템(CRS)을 &#39;EPSG:5179&#39;로 설정하는 것을 의미한다.EPSG(European Petroleum Survey Group)는 좌표 참조 시스템에 대한 표준 데이터 세트를 관리하는 국제적인 조직입니다. &#39;EPSG:5179&#39;는 대한민국 내에서 주로 사용되는 좌표 참조 시스템 중 하나라고 한다. </p>
<pre><code class="language-python"># 중심점 좌표 계산
dong_boundary[&#39;center_point&#39;] = dong_boundary[&#39;geometry&#39;].centroid

# 좌표를 WGS 84 좌표계로 변환
dong_boundary[&#39;geometry&#39;] = dong_boundary[&#39;geometry&#39;].to_crs(epsg=4326)
dong_boundary[&#39;center_point&#39;] = dong_boundary[&#39;center_point&#39;].to_crs(epsg=4326)</code></pre>
<p>그 다음은 간단하다.
중심점을 찾고 그 지점을 WGS 84좌표로 변환해준다.
<img src="https://velog.velcdn.com/images/waterglasses_k/post/828614f0-4116-4c15-9422-b7521a41542c/image.png" alt="">
center_point의 좌표를 위도, 경도 컬럼으로 분리하여주면 끝</p>
<hr>
<h3 id="전체코드">전체코드</h3>
<pre><code class="language-python">import geopandas as gpd
# 서울시 법정동 경계 데이터 불러오기
dong_boundary = gpd.read_file(&#39;/Users/sookyeong/Documents/내배캠/팀프로젝트/project5_final/emd.shp&#39;, encoding=&#39;cp949&#39;)

# CRS 설정
dong_boundary.crs = &#39;EPSG:5179&#39;  

# 중심점 좌표 계산
dong_boundary[&#39;center_point&#39;] = dong_boundary[&#39;geometry&#39;].centroid

# 좌표를 WGS 84 좌표계로 변환
dong_boundary[&#39;geometry&#39;] = dong_boundary[&#39;geometry&#39;].to_crs(epsg=4326)
dong_boundary[&#39;center_point&#39;] = dong_boundary[&#39;center_point&#39;].to_crs(epsg=4326)

#위도, 경도 컬럼 생성
dong_boundary[&#39;위도&#39;] = dong_boundary[&#39;center_point&#39;].y
dong_boundary[&#39;경도&#39;] = dong_boundary[&#39;center_point&#39;].x

#필요한 컬럼 남기기
dong_boundary = dong_boundary.drop(columns = [&#39;geometry&#39;, &#39;center_point&#39;])</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/7571cb16-7915-4bd8-97eb-85f13da1b4bf/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[python_코드카타(2023.03.28)]]></title>
            <link>https://velog.io/@waterglasses_k/python%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802023.03.28</link>
            <guid>https://velog.io/@waterglasses_k/python%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802023.03.28</guid>
            <pubDate>Thu, 28 Mar 2024 00:52:22 GMT</pubDate>
            <description><![CDATA[<h2 id="29-제일-작은-수-제거하기">29. <a href="https://school.programmers.co.kr/learn/courses/30/lessons/12935">제일 작은 수 제거하기</a></h2>
<blockquote>
</blockquote>
<h3 id="문제">문제</h3>
<p>정수를 저장한 배열, arr 에서 가장 작은 수를 제거한 배열을 리턴하는 함수, solution을 완성해주세요. 단, 리턴하려는 배열이 빈 배열인 경우엔 배열에 -1을 채워 리턴하세요. 예를들어 arr이 [4,3,2,1]인 경우는 [4,3,2]를 리턴 하고, [10]면 [-1]을 리턴 합니다.</p>
<h3 id="👩🏻💻-my-coding">👩🏻‍💻 my coding</h3>
<ul>
<li>리스트의 sort(), remove()</li>
<li>리스트의 메소드를 적용해 변수에 저장이 안된다.<pre><code class="language-python">def solution(x) : 
  if len(x) &gt; 1 : 
      x.sort(reverse = True)
      x.remove(x[-1])
      return x 
  elif len(x) &lt;= 1 : 
      result = [-1]
      return result </code></pre>
테스트는 통과했는데 제출하니 오답이다.
min을 쓰면 된다.<pre><code class="language-python">def solution(arr):
  if len(arr) &lt;= 1:
      return [-1]
  else:
      min_val = min(arr)
      arr.remove(min_val)
      return arr</code></pre>
크기순으로 나열해서 remove하는것과 왜 다른지 잘 모르겠다.
해답을 찾아보니 정렬로 배열 순서를 바꾸면 안된다고 한다.
문제 조건에 들어가있으면 좋았을텐데 !</li>
</ul>
<hr>
<h2 id="30-가운데-글자-가져오기">30. <a href="https://school.programmers.co.kr/learn/courses/30/lessons/12903">가운데 글자 가져오기</a></h2>
<blockquote>
</blockquote>
<h3 id="문제-1">문제</h3>
<p>단어 s의 가운데 글자를 반환하는 함수, solution을 만들어 보세요. 단어의 길이가 짝수라면 가운데 두글자를 반환하면 됩니다.</p>
<h3 id="👩🏻💻-my-coding-1">👩🏻‍💻 my coding</h3>
<ul>
<li>나머지로 글자수 짝/홀 구하기</li>
<li>2로 나누어 가운데 글자 위치 뽑아내기<pre><code class="language-python">def solution(x) : 
  a = int(len(x) / 2 - 0.5)
  if len(x) %2 == 0 : 
      return x[a:a+2]
  else : 
      return x[a]
</code></pre>
</li>
</ul>
<p>````</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[pandas 전처리 (결측치, 이상치처리) ]]></title>
            <link>https://velog.io/@waterglasses_k/pandas-%EC%A0%84%EC%B2%98%EB%A6%AC-%EA%B2%B0%EC%B8%A1%EC%B9%98-%EC%9D%B4%EC%83%81%EC%B9%98%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@waterglasses_k/pandas-%EC%A0%84%EC%B2%98%EB%A6%AC-%EA%B2%B0%EC%B8%A1%EC%B9%98-%EC%9D%B4%EC%83%81%EC%B9%98%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Wed, 27 Mar 2024 09:45:10 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-python">import seaborn as sns
df = sns.load_dataset(&quot;titanic&quot;)</code></pre>
<h2 id="1-결측치-처리">1. 결측치 처리</h2>
<h3 id="결측치-삭제">결측치 삭제</h3>
<p>✅ <strong>dropna</strong></p>
<pre><code class="language-python">df.info() #결측치 확인
df.isna().sum() #결측치 확인

#결측치 그래프로 보기
import missingno as msno
msno.bar(df)

# 결측치 있는 행 삭제
df.dropna(axis=0)

#결측치 있는 열 학제
df.dropna(axis=0)

df.dropna(axis=0, how=&#39;any&#39;)  # 해당 행이나 열에 결측치가 하나라도 있다면 제거. (default)

df.dropna(axis=0, how=&#39;all&#39;)  # 해당 행이나 열의 &#39;모든 값&#39;이 결측치라면 제거.

df.dropna(axis=1, thresh=800)  # 결측치가 아닌 값이 thresh보다 적게 있을 때 제거. how와 함께 사용 불가.

df.dropna(axis=0, subset=[&#39;age&#39;])  # 고려해야할 다른 축의 레이블 (ex. 행을 삭제하는 경우엔 열 지정.)

df.dropna(axis=0, ignore_index=True)  # True로 지정할 경우 결측치가 제거된 DataFrame의  index가 reset됨.

df.dropna(axis=0, ignore_index=True, inplace=True)  # True로 지정할 경우 해당 DataFrame 의 값이 변경됨.</code></pre>
<h3 id="결측치-대치">결측치 대치</h3>
<p>✅ <strong>fillna()</strong></p>
<pre><code class="language-python">#결측치 0으로 채우기
new_df[&#39;age&#39;] = new_df[&#39;age&#39;].fillna(0)

#평균값으로 대체
new_df[&#39;age&#39;] = new_df[&#39;age&#39;].fillna(new_df[&#39;age&#39;].mean())

#최빈값으로 대체
new_df[&#39;age&#39;] = new_df[&#39;age&#39;].fillna(new_df[&#39;age&#39;].mode()[0])</code></pre>
<p>✅ <strong>fowardfill, backwardfill</strong></p>
<pre><code class="language-python">import yfinance as yf
import pandas as pd
df1 = yf.download( &#39;005930.KS&#39;, &#39;2023-03-01&#39;,&#39;2024-03-01&#39;)  # 종목코드(삼성전자), 시작일자, 종료일자
df2 = yf.download( &#39;035420.KS&#39;, &#39;2023-03-01&#39;,&#39;2024-03-01&#39;)   # 종목코드(네이버), 시작일자, 종료일자
df3 = yf.download( &#39;035720.KS&#39;, &#39;2023-03-01&#39;,&#39;2024-03-01&#39;)   # 종목코드(카카오), 시작일자, 종료일자

# 각 데이터프레임에서 &#39;High&#39;와 &#39;Volume&#39; 컬럼만 선택하고, 컬럼명 변경
df1_selected = df1[[&#39;High&#39;, &#39;Volume&#39;]].rename(columns={&#39;High&#39;: &#39;High_samsung&#39;, &#39;Volume&#39;: &#39;Volume_samsung&#39;})
df2_selected = df2[[&#39;High&#39;, &#39;Volume&#39;]].rename(columns={&#39;High&#39;: &#39;High_naver&#39;, &#39;Volume&#39;: &#39;Volume_naver&#39;})
df3_selected = df3[[&#39;High&#39;, &#39;Volume&#39;]].rename(columns={&#39;High&#39;: &#39;High_kakao&#39;, &#39;Volume&#39;: &#39;Volume_kakao&#39;})

# 인덱스를 기준으로 세 데이터 프레임 합치기
df_merged = pd.concat([df1_selected, df2_selected, df3_selected], axis=1)</code></pre>
<pre><code class="language-python">#인덱스 설정
df_merged.index = pd.to_datetime(df_merged.index)

#연습을 위해 임의로 결측치 넣어줌
import numpy as np
np.random.seed(0)  # 재현 가능성을 위해 랜덤 시드 고정

# 모든 컬럼에 대해 10%의 값들을 랜덤으로 선택하여 NaN으로 설정
for column in df_merged.columns:
    # 결측치로 만들 인덱스를 랜덤 선택
    idxs = np.random.choice(df_merged.index, size=int(len(df_merged) * 0.3), replace=False)
    df_merged.loc[idxs, column] = np.nan

# np.random.choice(모집단, random으로 추출할 표본의 size, 복원추출여부(똑같은 값을 또 뽑을 수 있는지 여부))
np.random.choice(df_merged.index, size=int(len(df_merged) * 0.1), replace=False)

#결측치 확인
df_merged.isnull().sum()</code></pre>
<p>✅ <strong>ffill(), bfill()</strong></p>
<pre><code class="language-python">#결측치를 앞 방향으로 채우기(가장 최근의 비결측치로)
df_merged.ffill()
#결측치를 뒷 방향으로 채우기(해당 열에서 이후의 값으로 채우기)
df_merged.fillna(method=&#39;ffill&#39;)</code></pre>
<p>✅ <strong>보간법(interpolation)</strong></p>
<pre><code class="language-python">#결측치를 선형으로 채움
plt.figure(figsize=(20,10))

plt.plot(df_merged[&#39;High_samsung&#39;].interpolate(method=&#39;linear&#39;))
plt.plot(df_merged[&#39;High_samsung&#39;], marker=&#39;o&#39;)

# 결측치를 spline(곡선)으로 채움
# 더 과장될 수 있음
plt.figure(figsize=(20,10))
plt.plot(df_merged[&#39;High_samsung&#39;].interpolate(method=&#39;spline&#39;, order=2))
plt.plot(df_merged[&#39;High_samsung&#39;], marker=&#39;o&#39;)</code></pre>
<h2 id="2-이상치-처리">2. 이상치 처리</h2>
<pre><code class="language-python">#주식데이터 불러오기
import yfinance as yf

samsung_df = pd.DataFrame(yf.download(&#39;005930.KS&#39;, &#39;2023-03-01&#39;,&#39;2024-03-01&#39;))
naver_df = pd.DataFrame(yf.download(&#39;035420.KS&#39;, &#39;2023-03-01&#39;,&#39;2024-03-01&#39;))
kakao_df = pd.DataFrame(yf.download(&#39;035720.KS&#39;, &#39;2023-03-01&#39;,&#39;2024-03-01&#39;))


samsung_df = samsung_df[[&#39;High&#39;, &#39;Volume&#39;]].rename(columns = {&#39;High&#39; : &#39;High_samsung&#39;, &#39;Volume&#39; : &#39;Volume_samsung&#39;})
naver_df = naver_df[[&#39;High&#39;, &#39;Volume&#39;]].rename(columns = {&#39;High&#39; : &#39;High_naver&#39;, &#39;Volume&#39; : &#39;Volume_naver&#39;})
kakao_df = kakao_df[[&#39;High&#39;, &#39;Volume&#39;]].rename(columns = {&#39;High&#39; : &#39;High_kakao&#39;, &#39;Volume&#39; : &#39;Volume_kakao&#39;})</code></pre>
<p>✅ <strong>z-score 기반 이상치 확인</strong>
naver_df[&#39;Valume_naver&#39;]열 이상치 확인</p>
<pre><code class="language-python"># 컬럼 선택
data = df_merged[&#39;Volume_naver&#39;]

# 평균과 표준편차 계산
mean = np.mean(data)
std_dev = np.std(data)

# 각 데이터 포인트에 대한 Z-score 계산
z_scores = [(x - mean) / std_dev for x in data]

# Z-score의 절댓값이 3 이상인 데이터 포인트를 이상치로 판별
outliers = [data[i] for i in range(len(z_scores)) if abs(z_scores[i]) &gt; 3]

print(&quot;이상치:&quot;, outliers) # 이상치: [2725703, 3102468, 2561625, 3055268, 3013711]

#z-score 값 붙이기
merge_df[&#39;Volume_naver_z_score&#39;] = z_scores</code></pre>
<p>✅ <strong>boxplot 그래프</strong></p>
<pre><code class="language-python">df = sns.load_dataset(&quot;titanic&quot;)
plt.boxplot(df[&#39;age&#39;].dropna())
plt.xlabel(&#39;age&#39;)
plt.show()</code></pre>
<p>✅ <strong>IQR</strong></p>
<pre><code class="language-python"># 1사분위수(Q1)와 3사분위수(Q3) 계산
Q1 = df[&#39;age&#39;].quantile(0.25)
Q3 = df[&#39;age&#39;].quantile(0.75)

# IQR 계산
IQR = Q3 - Q1

# 하한과 상한 계산
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 이상치 필터링
outliers = df[(df[&#39;age&#39;] &lt; lower_bound) | (df[&#39;age&#39;] &gt; upper_bound)]

print(&quot;이상치를 포함하는 행:\n&quot;)
outliers</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[pandas 기본 메소드(T, sorting, 인덱싱, 슬라이싱, 필터링)]]></title>
            <link>https://velog.io/@waterglasses_k/pandas-%EA%B8%B0%EB%B3%B8-%EB%A9%94%EC%86%8C%EB%93%9CT-sorting-%EC%9D%B8%EB%8D%B1%EC%8B%B1-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EC%8B%B1-%ED%95%84%ED%84%B0%EB%A7%81</link>
            <guid>https://velog.io/@waterglasses_k/pandas-%EA%B8%B0%EB%B3%B8-%EB%A9%94%EC%86%8C%EB%93%9CT-sorting-%EC%9D%B8%EB%8D%B1%EC%8B%B1-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EC%8B%B1-%ED%95%84%ED%84%B0%EB%A7%81</guid>
            <pubDate>Wed, 27 Mar 2024 07:58:05 GMT</pubDate>
            <description><![CDATA[<p>여러 기본 메소드를 익히긴 했지만 새로 배우고 잘 까먹는 메소드를 다시 한 번 정리해보자.</p>
<h3 id="타이타닉-데이터">타이타닉 데이터</h3>
<ul>
<li>불러오기<pre><code class="language-python">import pandas as pd 
import seaborn as sns
</code></pre>
</li>
</ul>
<p>df = sns.load_dataset(&quot;titanic&quot;)
df.head()</p>
<pre><code>- T : 행과 열을 자리를 바꿈
```python
df.T</code></pre><p>✅ <strong>sort_counts()</strong></p>
<pre><code class="language-python"># column 별 값의 분포를 확인할 때 사용합니다.
df[&#39;who&#39;].value_counts()

df[&#39;who&#39;].value_counts(ascending=True)  # 오름차순정렬

df[&#39;who&#39;].value_counts(normalize=True)  # 비율구하기 

df[&#39;age&#39;].value_counts(bins=3, sort=False)  # 연속형 자료를 이산형 자료로 변환 후 개수 확인. 3개 구간으로 범주화. 
# &#39;()&#39;는 미포함, &#39;[]&#39;는 포함.

df[&#39;age&#39;].value_counts(bins=[0, 20, 40, 60, 100], sort=False)  # 연속형 자료를 사용자 지정 구간으로 Binning 
</code></pre>
<p>✅ <strong>sort_values()</strong></p>
<pre><code class="language-python">df.sort_values(by=&#39;age&#39;).head()

#오름차순 정렬
df.sort_values(by=&#39;age&#39;, ascending=False).head() 

#여러개 컬럼 정렬
df.sort_values(by=[&#39;fare&#39;, &#39;age&#39;], ascending=[False, True]).head()</code></pre>
<p>✅** indexing / slicing / 조건 필터링**</p>
<pre><code class="language-python">df.loc[0, &#39;class&#39;]  # indexing 예시

df.loc[2:5, &#39;class&#39;:&#39;deck&#39;].head()  # slicing 예시 (slicing은 [시작(포함): 끝(포함)])

df.loc[:6, &#39;class&#39;:&#39;deck&#39;] #6행까지 열 지정</code></pre>
<p>✅ <strong>조건필터링</strong></p>
<pre><code class="language-python"># 조건1 정의
cond1 = (df[&#39;fare&#39;] &gt; 30)
# 조건2 정의
cond2 = (df[&#39;who&#39;] == &#39;woman&#39;)
df.loc[cond1 &amp; cond2] # 또는 -&gt; |</code></pre>
<p>✅ <strong>iloc : loc과 유사하지만 index만 허용</strong></p>
<pre><code class="language-python">df.iloc[[0, 3, 4], [0, 1, 5, 6]]  # Fancy Indexing

df.iloc[:3, :5]  # Slicing</code></pre>
<p>✅ <strong>isin : 포함여부</strong></p>
<pre><code class="language-python">sample = pd.DataFrame({&#39;name&#39;: [&#39;kim&#39;, &#39;lee&#39;, &#39;park&#39;, &#39;choi&#39;], 
                        &#39;age&#39;: [24, 27, 34, 19]
                      })
condition = sample[&#39;name&#39;].isin([&#39;kim&#39;, &#39;lee&#39;])  # loc를 활용한 조건 필터링으로도 찰떡궁합입니다.

sample.loc[condition]</code></pre>
<h3 id="연습문제">연습문제</h3>
<ul>
<li>tips 데이터셋 중 day가 금요일(Fri), 토요일(Sat) 만 필터링 합니다.</li>
<li>tip이 $10보다 적게 낸 데이터만 필터링합니다.</li>
<li>컬럼은 total_bill, tip, smoker, time만 출력합니다.</li>
<li>상위 10개 행만 출력합니다.<pre><code class="language-python">#풀이1
con1 = tips[&#39;day&#39;] == &#39;Fri&#39;
con2 = tips[&#39;day&#39;] == &#39;Sat&#39;
con3 = tips[&#39;tip&#39;] &lt; 10 
</code></pre>
</li>
</ul>
<p>tips[(con1 | con2)&amp; con3][[&#39;total_bill&#39;, &#39;tip&#39;, &#39;smoker&#39;, &#39;time&#39;]].head(10) </p>
<p>#풀이2
con1 = tips[&#39;day&#39;].isin([&#39;Fri&#39;, &#39;Sat&#39;])
con2 = tips[&#39;tip&#39;] &lt; 10</p>
<p>tips.loc[con1&amp;con2][[&#39;total_bill&#39;, &#39;tip&#39;, &#39;smoker&#39;, &#39;time&#39;]].head(10) 
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[python_코드카타(2023.03.27)]]></title>
            <link>https://velog.io/@waterglasses_k/python%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802023.03.27</link>
            <guid>https://velog.io/@waterglasses_k/python%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802023.03.27</guid>
            <pubDate>Wed, 27 Mar 2024 00:45:46 GMT</pubDate>
            <description><![CDATA[<h2 id="27-핸드폰-번호-가리기">27. <a href="https://school.programmers.co.kr/learn/courses/30/lessons/12948">핸드폰 번호 가리기</a></h2>
<blockquote>
</blockquote>
<h3 id="문제">문제</h3>
<p>프로그래머스 모바일은 개인정보 보호를 위해 고지서를 보낼 때 고객들의 전화번호의 일부를 가립니다.
전화번호가 문자열 phone_number로 주어졌을 때, 전화번호의 뒷 4자리를 제외한 나머지 숫자를 전부 *으로 가린 문자열을 리턴하는 함수, solution을 완성해주세요.</p>
<h3 id="👩🏻💻-my-coding">👩🏻‍💻 my coding</h3>
<ul>
<li>인덱스 슬라이싱 사용</li>
<li>문자 대체 &#39;replace&#39;<pre><code class="language-python">def solution(phone_number) : 
  back = phone_number[-4:]
  front = phone_number[:-4]
  return phone_number.replace(front, &#39;*&#39;*len(front))</code></pre>
</li>
</ul>
<hr>
<h2 id="28-없는-숫자-더하기">28. <a href="https://school.programmers.co.kr/learn/courses/30/lessons/86051">없는 숫자 더하기</a></h2>
<blockquote>
</blockquote>
<h3 id="문제-1">문제</h3>
<p>0부터 9까지의 숫자 중 일부가 들어있는 정수 배열 numbers가 매개변수로 주어집니다. numbers에서 찾을 수 없는 0부터 9까지의 숫자를 모두 찾아 더한 수를 return 하도록 solution 함수를 완성해주세요.</p>
<h3 id="👩🏻💻-my-coding-1">👩🏻‍💻 my coding</h3>
<ul>
<li>total을 먼저 정의하고</li>
<li>total을 for문으로 반복하며 그 숫자가 numbers에 없는 수들의 합<pre><code class="language-python">def solution(numbers) : 
  sum = 0
  total = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
  for i in total : 
      if i not in numbers : 
          sum  = sum + i 
  return sum
</code></pre>
</li>
</ul>
<p>````</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[pandas 데이터 불러오기, 공공데이터 API]]></title>
            <link>https://velog.io/@waterglasses_k/pandas-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0-%EA%B3%B5%EA%B3%B5%EB%8D%B0%EC%9D%B4%ED%84%B0-API</link>
            <guid>https://velog.io/@waterglasses_k/pandas-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0-%EA%B3%B5%EA%B3%B5%EB%8D%B0%EC%9D%B4%ED%84%B0-API</guid>
            <pubDate>Wed, 20 Mar 2024 02:09:13 GMT</pubDate>
            <description><![CDATA[<p>pandas 라이브러리를 활용한 다양한 방법들을 학습하였다.</p>
<h3 id="👩🏻💻-학습한-것">👩🏻‍💻 학습한 것</h3>
<blockquote>
</blockquote>
<p><strong>1. 불러오기 관련</strong>
✅ nrows
✅ tsv 파일 불러오기
<strong>2. 불러올때 column 설정</strong>
✅ header
✅ names
✅ index_col
✅ index.name 
✅ parse_dates
✅ dtype
<strong>3. API활용하여 XML 데이터 파싱
4. 저장하기</strong>
✅ to_csv(encoding, index=False, header = False)
✅ mode </p>
<h3 id="1-pandas로-데이터-불러오기">1. pandas로 데이터 불러오기</h3>
<ul>
<li><p><strong>shape</strong>
행과 열의 갯수 표시</p>
<pre><code class="language-python">df = pd.read_csv(&quot;week1_1.csv&quot;)
display (df.head())
print (df.shape) # (50, 6)</code></pre>
</li>
<li><p><strong>nrows</strong>
데이터의 크기가 너무 커서 일부만 가져온 뒤 빠르게 데이터를 확인하고 싶을 때</p>
<pre><code class="language-python">df = pd.read_csv(&quot;week1_1.csv&quot;, nrows=7)
display (df.head())
print (df.shape)</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/7c257961-aee3-4dd0-9db1-9ac111312819/image.png" alt=""></p>
</li>
<li><p><strong>sep</strong>
불러오는 파일의 구분자</p>
</li>
<li><p><strong>tsv파일?</strong>
TSV 파일은 Tab Separated Values의 약자로, 데이터를 탭(tab) 문자로 구분하여 저장하는 텍스트 파일 형식. 쉼표로 구분되는 csv보다 가독성이 좋을 수 있다.</p>
<pre><code class="language-python">df = pd.read_csv(&#39;/Users/sookyeong/Documents/내배캠/스탠다드B/week1_1.tsv&#39;, sep = &#39;\t&#39;)
df.head()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/3c2b422a-b4ca-4b89-adfa-45f6dbc4f19f/image.png" alt=""></p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/f9b55fd4-0cde-444c-b3ef-6d8bf7e3dde4/image.png" alt=""></p>
<hr>
<h3 id="2-데이터-불러오기---column">2. 데이터 불러오기 - COLUMN</h3>
<ul>
<li><p><strong>header = None</strong>
첫 행이 컬럼명이 아니고, 컬럼명 없이 데이터로만 이뤄져 있을 때. (데이터에 헤더가 없을 때 사용)</p>
<pre><code class="language-python">df = pd.read_csv(&quot;week1_1.csv&quot;, header=None) 
df.head()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/7b187672-ffb2-48e0-84b0-e09f2d49560c/image.png" alt=""></p>
</li>
<li><p><strong>names</strong>
헤더가 없는 상황에서 컬럼명을 넣어주고 싶을 때</p>
<pre><code class="language-python">df = pd.read_csv(&quot;week1_1.csv&quot;, names=[&#39;c1&#39;, &#39;c2&#39;, &#39;c3&#39;, &#39;c4&#39;, &#39;c5&#39;, &#39;c6&#39;]) 
df.head()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/07536b94-d545-43a1-ba20-594d3352ad12/image.png" alt=""></p>
</li>
<li><p><strong>header &amp; names</strong>
첫 행이 컬럼명이 맞는데, 컬럼명을 새로 지정해주고 싶을 때.</p>
<pre><code class="language-python">df = pd.read_csv(&quot;week1_1.csv&quot;, header=None, names=[&#39;c1&#39;, &#39;c2&#39;, &#39;c3&#39;, &#39;c4&#39;, &#39;c5&#39;, &#39;c6&#39;]) 
df.head()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/ac71aa16-bf3f-4978-850c-9610cb21db94/image.png" alt=""></p>
</li>
<li><p><strong>header = 1</strong>
두번째 행을 컬럼명으로 지정하고 싶을 때. 주로 엑셀 형태로 관리되었던 파일에서 사용한다.(위에 공백을 처리하기 위해)</p>
<pre><code class="language-python">df = pd.read_csv(&quot;week1_1.csv&quot;, header=1) # 두번 째 행을 컬럼명으로 하고 싶을 때 (주로 엑셀 형태로 관리되었던 파일에서 사용.)
df.head()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/0b44ca21-15dc-4fb4-96b3-f901d3c2c9c6/image.png" alt=""></p>
</li>
</ul>
<h3 id="3-데이터-불러오기---index">3. 데이터 불러오기 - INDEX</h3>
<ul>
<li><p><strong>index_col</strong>
n번째 열을 index로 사용하고 싶을 때</p>
<pre><code class="language-python">df = pd.read_csv(&quot;week1_1.csv&quot;, index_col=0) 
df.head()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/65e16ea2-319a-4110-b5b6-7a27ea0b9d29/image.png" alt=""></p>
</li>
<li><p><strong>index.name = None</strong>
index 이름을 없애고 싶을 때</p>
<pre><code class="language-python">df = pd.read_csv(&quot;week1_1.csv&quot;, index_col=0)
df.index.name = None
df.head()</code></pre>
</li>
<li><p><strong>parse_date</strong>
컬럼을 날짜형식으로 불러올때.</p>
<ul>
<li>인덱스 : parse_dates = True</li>
<li>일반컬럼 : parse_dates = &#39;column&#39;<pre><code class="language-python">df = pd.read_csv(&quot;week1_1.csv&quot;, index_col=0, parse_dates = True)
df.index.name = None
df.head()
print(df.index.dtype) # datetime64[ns]</code></pre>
</li>
</ul>
</li>
<li><p><em>날짜형식 활용*</em>
원하는 날짜를 기준으로 데이터를 불러올 수 있음</p>
<pre><code class="language-python">df[df.index.month == 10] #10월달의 데이터만
</code></pre>
</li>
</ul>
<p>from datetime import datetime
cutoff_date = datetime(2023, 10, 1) # 해당날짜보다 큰 날짜 출력
df[df.index &gt; cutoff_date]</p>
<pre><code>![](https://velog.velcdn.com/images/waterglasses_k/post/8da451d9-28ac-41ac-b66e-a85780cb52f2/image.png)

- **dtype**
데이터 타입을 지정하여 불러옴
```python
df = pd.read_csv(&quot;week1_1.csv&quot;, dtype={&#39;number&#39;:&#39;object&#39;})
df.dtypes</code></pre><p><img src="https://velog.velcdn.com/images/waterglasses_k/post/cd41601c-c8ef-48c2-b573-81019cff006e/image.png" alt=""></p>
<hr>
<h3 id="4-데이터-불러오기---api-활용한-xml-data-파싱">4. 데이터 불러오기 - API 활용한 XML Data 파싱</h3>
<ul>
<li>xml 공공데이터 불러오기
<img src="https://velog.velcdn.com/images/waterglasses_k/post/10914b64-ea91-4bce-ad6c-9adaf6171882/image.png" alt=""></li>
</ul>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/f1de86c8-738c-4302-a3f9-b5915422c192/image.png" alt=""></p>
<pre><code class="language-python">import requests

serviceKey = &quot;~~~~~&quot;  # 일반 인증키 (Decoding)

url = &#39;http://apis.data.go.kr/B551182/yadmOpCloInfoService1/getHospPharmacyOpCloList&#39;
params ={&#39;serviceKey&#39; : serviceKey, &#39;numOfRows&#39; : &#39;10&#39;, &#39;pageNo&#39; : &#39;1&#39;, &#39;crtrYm&#39; : &#39;202401&#39;, &#39;yadmTp&#39; : &#39;0&#39;, &#39;opCloTp&#39; : &#39;0&#39; }

response = requests.get(url, params=params)
# print(response.content)  # bytes 형태여서 보기 힘듦.
content = response.content.decode(&#39;utf-8&#39;)  # utf-8로 디코딩함. 

df = pd.read_xml(response.content, xpath=&quot;.//item&quot;)</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/38143abe-3af5-4cb2-a91e-6e1e5929aee1/image.png" alt=""></p>
<hr>
<h3 id="저장하기">저장하기</h3>
<ul>
<li><strong>to_csv</strong><pre><code class="language-python">df.to_csv(&#39;file_name.csv&#39;)
</code></pre>
</li>
</ul>
<p>#저장한 파일이 글자가 깨졌다면
df.to_scv(&#39;file_name.csv&#39;, encoding = &#39;cp949&#39;)</p>
<p>#index 저장하지 않을 때
df.to_scv(&#39;file_name.csv&#39;, index = False)</p>
<p>#header 저장하지 않을 때
df.to_scv(&#39;file_name.csv&#39;, header = False)</p>
<p>````</p>
<ul>
<li><strong>mode</strong><pre><code class="language-python">#파일이 이미 있을 경우 덮어쓰기
df.to_csv(&quot;file_name.csv&quot;, mode=&#39;w&#39;)
</code></pre>
</li>
</ul>
<p>#파일이 이미 있을 경우 append하기 (모델 성능을 csv 파일로 저장할 때)
df.to_csv(&quot;file_name.csv&quot;, mode=&#39;a&#39;)</p>
<p>#파일이 이미 있을 경우 생성하지 않음
df.to_csv(&quot;file_name.csv&quot;, mode=&#39;x&#39;)</p>
<p>#tsv로 저장(자주사용하지 않음)
df.to_csv(&quot;file_name.tsv&quot;, sep = &#39;\t&#39;)
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python_가상환경 설치]]></title>
            <link>https://velog.io/@waterglasses_k/Python%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BD-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@waterglasses_k/Python%EA%B0%80%EC%83%81%ED%99%98%EA%B2%BD-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Wed, 13 Mar 2024 04:43:49 GMT</pubDate>
            <description><![CDATA[<h2 id="가상환경-설치❓">가상환경 설치❓</h2>
<p>컴알못인 나에게 가상환경는 말조차 이해가 안갔다.
처음에는 아~ 이런게 있나보구나 나중에 필요할때가 있겠지 싶었는데, 처음에 안된다고 이것저것 설치한 파이썬 버전에 패키지들까지, 도저히 정리가 안돼서 떠오른 것이 가상환경이었다.</p>
<h2 id="가상환경-필요한-이유">가상환경 필요한 이유</h2>
<ul>
<li>파이썬 프로젝트의 프로젝트별로 격리시켜 관리</li>
<li>하나의 시스템에서 여러 프로젝트를 다룰 때, 각각의 프로젝트가 서로 다른 라이브러리 또는 동일 라이브러리의 다른 버전을 요구할 수 있다.</li>
<li><strong>즉, 가상환경을 사용하면 프로젝트별로 안정적으로 패키지 버전을 관리할 수 있다.</strong>
<img src="https://velog.velcdn.com/images/waterglasses_k/post/d03b4627-3d79-4593-881a-0916f8f1d84a/image.png" alt="">
위 그림처럼 상위버전을 설치해도 프로젝트A의 에러를 방지할 수 있다.
▶️ <a href="https://heytech.tistory.com/316">출처 블로그</a></li>
</ul>
<h2 id="가상환경-설치하기">가상환경 설치하기</h2>
<ul>
<li>VSCode사용<pre><code class="language-python">#현재 경로 보여줌
!pwd
</code></pre>
</li>
</ul>
<p>#현재 위치의 폴더들 보여줌
!ls</p>
<p>#&#39;myenv&#39; 폴더 생성
!python -m venv myenv</p>
<p>#폴더생성한 것 확인
!ls</p>
<p>#생성한 폴더 실행
!source myenv/bin/activate # 맥</p>
<h1 id="myenvscriptsactivate----윈도우">myenv\Scripts\activate   # 윈도우</h1>
<p>#커널설치
!pip install ipkernel</p>
<h1 id="내가-지금-쓰고있는-가상환경-확인">내가 지금 쓰고있는 가상환경 확인</h1>
<p>!which python3</p>
<h1 id="ipykernel-커널-설치">ipykernel 커널 설치</h1>
<p>!pip install ipykernel</p>
<h1 id="ipython-커널-생성-및-연결">IPython 커널 생성 및 연결</h1>
<p>!python -m ipykernel install --user --name myenv_kernel --display-name &quot;커널이름(peach)&quot;</p>
<p>```</p>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/36064c99-713c-4d85-a875-70f887ce1ca5/image.png" alt=""></p>
<p>그러면 주피터에서
<img src="https://velog.velcdn.com/images/waterglasses_k/post/b3abc1ce-884e-4f05-8878-8a24566c664a/image.png" alt=""></p>
<p>또는 VSCode에서도 
<img src="https://velog.velcdn.com/images/waterglasses_k/post/d82f2424-89a6-47f8-bdec-48d0ee87902f/image.png" alt=""></p>
<p>peach이름이 커널 확인
이 커널을 선택해서 프로젝트를 관리하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python_머신러닝 pycaret]]></title>
            <link>https://velog.io/@waterglasses_k/Python%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-pycaret</link>
            <guid>https://velog.io/@waterglasses_k/Python%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-pycaret</guid>
            <pubDate>Tue, 12 Mar 2024 09:10:16 GMT</pubDate>
            <description><![CDATA[<p>꾸역꾸역 머신러닝 열심히 배웠는데
튜터링에서 기가막힌 라이브러리를 알게 되었다.
저코드로 수십개의 머신러닝 모델을 돌릴 수 있는 <code>pycaret</code></p>
<h3 id="👩🏻💻-pycaret-메소드">👩🏻‍💻 Pycaret 메소드</h3>
<ul>
<li><code>setup()</code> : 데이터 전처리</li>
<li><code>compare_models()</code>: 여러 회귀모델을 훈련하여 비교</li>
<li><code>tune_model()</code> : 오토튜닝, 자동으로 모델 최적화</li>
<li><code>plot_model()</code>: pycaret 시각화(잔차, 오차) </li>
<li><code>predict_model()</code>: 모델의 예측성능 평가</li>
</ul>
<blockquote>
</blockquote>
<h2 id="pycaret">pycaret?</h2>
<p>Python에서 사용할 수 있는 저코드 머신러닝 라이브러리
데이터 전저리, 모델선택, 최적화 및 배포까지 한번에 해주는 치트키</p>
<h2 id="pycaret-용도">pycaret 용도</h2>
<ul>
<li>베이스라인 모델을 정할때 활용</li>
<li>머신러닝의 통상 과정들을 한번에 스킵할 수 있다.<ul>
<li><ol>
<li><strong>데이터 클리닝</strong>: 결측치 처리, 이상치 감지 및 제거</li>
</ol>
</li>
<li><ol start="2">
<li><strong>특성 공학</strong>: 새로운 특성 생성 및 변환, 비선형 관계를 갖는 변수 변환</li>
</ol>
</li>
<li><ol start="3">
<li><strong>데이터 분할</strong>: 훈련 데이터와 테스트 데이터로 분할</li>
</ol>
</li>
<li><ol start="4">
<li><strong>정규화/표준화</strong>: 데이터의 스케일 조정</li>
</ol>
</li>
<li><ol start="5">
<li><strong>인코딩</strong>: 범주형 변수를 수치형 변수로 변환</li>
</ol>
</li>
<li><ol start="6">
<li><strong>다중 공선성 확인</strong>: 변수 간의 고도의 상관관계 분석 및 처리</li>
</ol>
</li>
<li><ol start="7">
<li><strong>특성 선택</strong>: 중요한 특성 선택 및 불필요한 특성 제거</li>
</ol>
</li>
</ul>
</li>
</ul>
<hr>
<pre><code class="language-python"># pycaret 설치
! pip install pycaret full

# 데이터 불러오기
from pycaret.dataset import get_data
boston_df = get_data(&#39;boston&#39;)

# pycaret 회귀분석 라이브러리 불러오기
from pycaret.regression import * 

# pycaret 한번에 전처리하기
s = setup(data = boston_df,
    target = &#39;medv&#39;, #예측 대상변수
    session_id = 123,    #실험의 재현성과 관리를 위위함
    normalize = True,    #정규화
    transformation = True,    #데이터변환(정규분포를 더 정규분포와 유사하게)
    remove_outliers = True,        #이상치제거
    remove_multicollinearity = True,    #다중공선성제거 
    multicollinearity_threshold = 0.9,    #다중공선성제거 임계치
    feature_selection = True)    #특성선택(불필요한 특성 제거)</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/9aa68bab-4595-431f-81f5-9d96ce2e6590/image.png" alt="">
전처리된 결과를 한번에 확인할 수 있다.
데이터분리, 결측치 제거, 이상치제거, 정규화 등 어떻게 처리되었는지 확인</p>
<pre><code class="language-python">#전처리된 trian data 확인
s.train_transformed</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/22879bdc-ced7-42b5-a9fe-b5ca04647d16/image.png" alt="">
선택된 변수는 age, lstat </p>
<pre><code class="language-python"># 머신러닝 모델 비교
best_model = compare_models()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/0c449b37-58ba-40d1-9f44-78229debf4d9/image.png" alt="">
정말 신세계라 할 수 있다. 위 모델을 전부 비교해주고 가장 베스트 알아서 골라준다.
베스트 모델은 knn
여기서 끝이 아니다. 설명력을 더 높일 수 있게 모델을 tune할 수 있다.</p>
<pre><code class="language-python">#자동 하이퍼파라미터 튜닝(오토튜닝)
tuned_model = tune_model(best_model, optimize = &#39;R2&#39;)</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/35d6ca0e-8909-4b2e-99a8-104760f61124/image.png" alt="">
R2 : 0.6709 -&gt; 0.6857
모델 성능 최적화도 쉽게 할 수 있다.</p>
<pre><code class="language-python">#모델 분석 시각화 
import matplotlib.pyplot as plt

#원본 histogram
plt.hist(boston_df[&#39;medv&#39;], bins = 100)</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/3ba07036-42c2-4c8b-a7f2-2f5370f6cc03/image.png" alt=""></p>
<pre><code class="language-python">plot_model(tuned_model, plot = &#39;residuals&#39;)
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/955520b2-37fb-4da6-b53e-a079392757c0/image.png" alt="">
잔차그래프는 예측값과 실제값의 차이를 보여준다.
잔차가 무작위로 분포하고 특정 패턴이 없어야 모델이 잘 학습했다고 할 수 있다. </p>
<pre><code class="language-pycaret"># 오차그래프
plot_model(tuned_model, plot = &#39;error&#39;)</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/0671031f-63b8-4569-ae95-0dca35f1f5bf/image.png" alt="">
오차그래프는 모델의 예측 오차를 시각화 한다.
일반적으로 예측값 대비 실제값의 오차를 보여주고, 잔차 분포의 특성을 파악하는데 도움된다.</p>
<pre><code class="language-python">#모델 최종평가
new_boston_df = boston_df
final_prediction = predict_model(tuned_model, data = new_boston_df)</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/2e5c8bd6-3327-48ee-ab3a-b97b5397095a/image.png" alt="">
knn접근법으로 설명력이 0.7039까지 상승했다. 
다만, pycaret 모델을 바로 사용하는게 아니라 참고하여 모델을 선정하고 설명력의 기준을 잡으면 되겠다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQLD 시험 준비 과정 기록]]></title>
            <link>https://velog.io/@waterglasses_k/SQLD-%EC%8B%9C%ED%97%98-%EC%A4%80%EB%B9%84-%EA%B3%BC%EC%A0%95-%EA%B8%B0%EB%A1%9D</link>
            <guid>https://velog.io/@waterglasses_k/SQLD-%EC%8B%9C%ED%97%98-%EC%A4%80%EB%B9%84-%EA%B3%BC%EC%A0%95-%EA%B8%B0%EB%A1%9D</guid>
            <pubDate>Tue, 12 Mar 2024 02:48:06 GMT</pubDate>
            <description><![CDATA[<p>3월 9일 SQLD 시험 준비과정을 기록한다. </p>
<h2 id="시험-접수-팁">시험 접수 팁!</h2>
<p>웬걸, 시험 접수시작한 날 저녁쯤 접수할려니까 근처 시험장 모두 이미 자리가 없었다.
지역마다 차이가 있겠지만 내가 가려고 했던 수원, 용인은 자리가 빨리 빠지는것 같으니 재시험(?)을 치게 되거나 다른 자격증 시험 접수하려면 접수오픈에 맞춰서 접수해야겠다. 
어쩔 수 없이 4-50분 걸리는 평택으로 신청했다.</p>
<ul>
<li>데이터자격검정(시험접수)
<a href="https://www.dataq.or.kr/www/main.do">https://www.dataq.or.kr/www/main.do</a></li>
</ul>
<hr>
<h2 id="강의">강의</h2>
<p>강의는 스파르타코딩클럽 SQLD 강의를 수강했다.
이건 내일배움캠프 데이터분석 부트캠프 과정에 있는 커리큘럼으로, 이 수업을 듣기 전에 SQL 실습 교육을 먼저 수강한 덕분에 SQLD 자격증 수업을 듣는데 더욱 도움 되었다. 
<img src="https://velog.velcdn.com/images/waterglasses_k/post/555d4248-08e6-461a-bebe-d566dbabebd6/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/aa3ac664-774b-4730-984d-de5169334a52/image.png" alt=""></p>
<p>SQLD는 필기시험만 보기 때문에 이론만 잘 공부하면 되는데, 수업은 그렇다 치고 강의 노트가 생각보다 자세해서 이것만 읽어봐도 개념을 공부하는데 많은 도움이 되었다. </p>
<p>혹시라도 누가 관심있을지 모르니까 수강하고 있는 데이터분석캠프 홈페이지 링크를 달아둔다. 기간이 끝나면 부트캠프 후기도 기록해두어야겠다.
<a href="https://nbcamp.spartacodingclub.kr/data">https://nbcamp.spartacodingclub.kr/data</a></p>
<hr>
<h2 id="교재">교재</h2>
<p>사실 부트캠프 과정에서 SQLD자격증 시험은 메인 커리큘럼이 아니라서 개인적으로 추가 공부를 해야했다. 강의 교재로 이론공부하기는 좋지만 시험대비 문제지도 필요했다.
<img src="https://velog.velcdn.com/images/waterglasses_k/post/822ffdd1-f7c6-4690-b508-0727ed8cd325/image.png" alt="">
<a href="https://www.yes24.com/Product/Goods/124645703">https://www.yes24.com/Product/Goods/124645703</a></p>
<p>교재는 유명한 노랭이
시험 주관하는 곳에서 출판하는 책이니 이건 무조건 풀어보아야 한다.
실제 시험에서 해당 교재에 있는 문제가 2문제 정도 출제됐다. 
교재 공부는 3회독했다. 처음 풀때는 이론 공부했던게 생각이 안나서 어려웠는데 2, 3회 나름 감이 잡혔다.</p>
<p>그런데 이 책은 SQLD+SQLP 교재이기 때문에 뒤의 분량은 SQLP 범위다. 책의 반만 풀기 때문에 문제가 적게 느껴질 수 있다. 문제가 부족하다면 기출문제지를 따로 사서 풀어보는게 좋겠다.</p>
<hr>
<h2 id="학습일정">학습일정</h2>
<p>누구는 2주, 누구는 두 달도 걸릴 수 있다.
기초지식이 있다면 2주도 가능할 것 같다.
그치만 짬짬이 공부해야 하는 탓에 날짜만 나는 두 달쪽에 속하는 것 같다.
두 달 동안 공부를 안한 날이 더 많았지만~ 한 열흘 전부터는 하루 2-3시간씩은 공부했다.</p>
<ul>
<li>빡세게 공부하겠다! : 2주 가능할듯</li>
<li>짬나는 시간에 조금씩 하겠다 : 1~2달 가능</li>
</ul>
<hr>
<h2 id="시험후기">시험후기</h2>
<p>뭐 별거라고 후기까지 남기는가 싶겠지만, 예~전에 토익, NCS 시험 본 이후로 처음 이런 시험을 보게 됐는데 나름 떨렸다.
어떤 시험을 보아도 빨리 푸는 편은 아닌데 이번에도 마찬가지로 시간을 거의 꽉 채웠다. 시험을 처음 보는 사람이라면 한번 쯤 시간 체킹하며 풀어보는 연습을 해보면 좋을 것 같다. 빨리 푸는 사람은 1시간, 나같은 사람은 꽉채워서 1시간 30분 다쓰고 퇴실했다.</p>
<p>다른 책들은 안풀어봐서 모르겠지만 시험 난이도는 위의 노랭이 책과 비슷했다. 아리까리한 문제들이 제법 있었어서 확실히 하려면 문제지 하나 더 풀걸 그랬다 ㅠㅠ</p>
<p>암튼 60점은 넘길 바라며,,,! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[python_코드카타(2024.02.23)]]></title>
            <link>https://velog.io/@waterglasses_k/python%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802024.02.23</link>
            <guid>https://velog.io/@waterglasses_k/python%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802024.02.23</guid>
            <pubDate>Fri, 23 Feb 2024 03:20:20 GMT</pubDate>
            <description><![CDATA[<h2 id="24-서울에서-김서방-찾기">24. <a href="https://school.programmers.co.kr/learn/courses/30/lessons/12919">서울에서 김서방 찾기</a></h2>
<blockquote>
</blockquote>
<h3 id="문제">문제</h3>
<p>String형 배열 seoul의 element중 &quot;Kim&quot;의 위치 x를 찾아, &quot;김서방은 x에 있다&quot;는 String을 반환하는 함수, solution을 완성하세요. seoul에 &quot;Kim&quot;은 오직 한 번만 나타나며 잘못된 값이 입력되는 경우는 없습니다.</p>
<h3 id="👩🏻💻-my-coding">👩🏻‍💻 my coding</h3>
<ul>
<li>반복문으로 리스트 내의 &#39;Kim&#39;찾기라고 생각했는데, 이 경우에는 index를 사용해준다.<pre><code class="language-python">def solution(seoul) :
  if &#39;Kim&#39; in seoul : 
      x = seoul.index(&#39;Kim&#39;)
      answer = f&#39;김서방은 {x}에 있다&#39;
  return answer </code></pre>
</li>
</ul>
<h2 id="25-나누어-떨어지는-숫자-배열">25. 나누어 떨어지는 숫자 배열</h2>
<blockquote>
<h3 id="문제-1">문제</h3>
<p>문제 설명
array의 각 element 중 divisor로 나누어 떨어지는 값을 오름차순으로 정렬한 배열을 반환하는 함수, solution을 작성해주세요.
divisor로 나누어 떨어지는 element가 하나도 없다면 배열에 -1을 담아 반환하세요.</p>
</blockquote>
<h3 id="👩🏻💻-my-coding-1">👩🏻‍💻 my coding</h3>
<ul>
<li>arr 리스트 생성</li>
<li>조건문과 반복문 사용</li>
<li>오름차순 정렬<pre><code class="language-python">def solution(arr, divisor) : 
  answer = []
  for i in arr : 
      if i % divisor == 0 : 
          answer.append(i)
      elif len(answer) == 0 :
          answer.append(-1)
  return sorted(answer)</code></pre>
테스트케이스는 통과했는데 오답이다.
[3, 2, 6, 10], 10을 넣으니 [-1, 10]이 출력되버린다.<pre><code class="language-python">def solution(arr, divisor) : 
  answer = []
  for i in arr : 
      if i % divisor == 0 : 
          answer.append(i)
  if len(answer) == 0 :
          answer.append(-1)
  return sorted(answer)</code></pre>
들여쓰기에 문제가 있었다. 위에 구문처럼 하면 나누어 떨어지는 요소가 없어도 -1을 추가하게 된다. 반복문을 다 돌고, 리스트에 값이 없으면 -1을 넣어주기 위해 하나 더 내어써야 함.</li>
</ul>
<h2 id="26-음양-더하기">26. <a href="https://school.programmers.co.kr/learn/courses/30/lessons/76501">음양 더하기</a></h2>
<blockquote>
<h3 id="문제-2">문제</h3>
<p>어떤 정수들이 있습니다. 이 정수들의 절댓값을 차례대로 담은 정수 배열 absolutes와 이 정수들의 부호를 차례대로 담은 불리언 배열 signs가 매개변수로 주어집니다. 실제 정수들의 합을 구하여 return 하도록 solution 함수를 완성해주세요.</p>
</blockquote>
<h3 id="입출력-예">입출력 예</h3>
<p>absolutes    signs    result
[4,7,12]    [true,false,true]    9
[1,2,3]    [false,false,true]    0</p>
<h3 id="👩🏻💻-my-coding-2">👩🏻‍💻 my coding</h3>
<p>이건 각 리스트에서 어떻게 하나씩 추출하느냐 골머리 앓다가, 찾아보니 zip을 이용하면 된다는걸 알았다.</p>
<ul>
<li>zip : 리스트 내 병렬 추출</li>
<li>true이면 더하기, false면 빼주기<pre><code class="language-python">def solution(absolutes, signs) : 
  answer = 0
  for i, j in zip(absolutes, signs) : 
      if j == True : 
          answer = answer + i
      else : 
          answer = answer - i 
  return answer </code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[머신러닝_비지도학습(KMeans, RFM)]]></title>
            <link>https://velog.io/@waterglasses_k/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EB%B9%84%EC%A7%80%EB%8F%84%ED%95%99%EC%8A%B5KMeans-RFM</link>
            <guid>https://velog.io/@waterglasses_k/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EB%B9%84%EC%A7%80%EB%8F%84%ED%95%99%EC%8A%B5KMeans-RFM</guid>
            <pubDate>Thu, 22 Feb 2024 02:44:49 GMT</pubDate>
            <description><![CDATA[<h3 id="👩🏻💻-학습한-것">👩🏻‍💻 학습한 것</h3>
<blockquote>
</blockquote>
<ul>
<li>비지도학습 개념 : 정답을 알려주지 않고 데이터간 유사성으로 정답을 지정하는 것.</li>
<li>Kmeans Clustering 군집화</li>
<li>RFM으로 고객 세그멘테이션<ul>
<li>고객 군집화의 방법</li>
<li>Recency 구하기</li>
<li>불균형 군집화에 대한 로그스케일 적용</li>
</ul>
</li>
<li>군집화모델 평가 : 실루엣 스코어</li>
</ul>
<hr>
<h1 id="1-비지도학습">1. 비지도학습</h1>
<h2 id="지도학습과-비지도학습">지도학습과 비지도학습</h2>
<ul>
<li>지도학습 : 문제(X)와 정답(Y)가 주어지고 정답(Y)를 맞추는 학습</li>
<li>비지도학습 : 정답(Y)를 알려주지 않고 데이터간 유사성을 이용해서 정답(Y)을 지정하는 방법
<img src="https://velog.velcdn.com/images/waterglasses_k/post/beba47c3-64a3-4ab1-9af2-b8b384a6c0a1/image.png" alt=""></li>
</ul>
<hr>
<h1 id="2-k-means-clustering">2. K-Means Clustering</h1>
<h2 id="k-means-수행순서">K-Means 수행순서</h2>
<ol>
<li><ol>
<li>K개 군집 수 설정</li>
</ol>
</li>
<li>임의의 중심을 선정</li>
<li>해당 중심점과 거리가 가까운 데이터를 그룹화
<img src="https://velog.velcdn.com/images/waterglasses_k/post/25fef883-89ce-4b2a-9938-a5ad7115b822/image.png" alt=""></li>
<li>데이터의 그룹의 무게 중심으로 중심점을 이동</li>
<li>중심점을 이동했기 때문에 다시 거리가 가까운 데이터를 그룹화
(3~5번 반복)
<img src="https://velog.velcdn.com/images/waterglasses_k/post/b8975f0a-101e-44ac-ad48-c35471bda406/image.png" alt=""></li>
</ol>
<p>-&gt; 좀 무식한 방법이라 할 수 있음</p>
<h2 id="k-means-정리">K-Means 정리</h2>
<ul>
<li>장점<ul>
<li>일반적이고 적용하기 쉬움</li>
</ul>
</li>
<li>단점<ul>
<li>거리 기반으로 가까움을 측정하기 때문에 차원이 많을 수록 정확도가 떨어짐</li>
<li>반복 횟수가 많을 수록 시간이 느려짐</li>
<li>몇 개의 군집(K)을 선정할지 주관적임</li>
<li>평균을 이용하기 때문에(중심점) 이상치에 취약함</li>
</ul>
</li>
<li>Python 라이브러리<ul>
<li><code>sklearn.cluster.KMeans</code><ul>
<li>함수 입력 값<ul>
<li><code>n_cluster</code>: 군집화 갯수</li>
<li><code>max_iter</code>: 최대 반복 횟수</li>
</ul>
</li>
<li>메소드<ul>
<li><code>labels_</code>: 각 데이터 포인트가 속한 군집 중심점 레이블</li>
<li><code>cluster_centers</code>: 각 군집 중심점의 좌표</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h1 id="3-군집평가-지표---실루엣계수">3. 군집평가 지표 - 실루엣계수</h1>
<h2 id="실루엣-계수란-">실루엣 계수란 ?</h2>
<p>비지도 학습 특성상 답이 없기 때문에 평가를 하기 쉽지 않다.
다만, 군집화가 잘 되어있다는 것은 다른 군집간의 거리가 떨어져 있고 동일한 구집끼리는 가까이 있다는 것을 의미한다.
<strong>실루엣 분석(Silhouette Analaysis)</strong> : 군집간의 거리가 얼마나 효율적으로 분리되어잇는지 측정</p>
<h2 id="실루엣-계수-특징">실루엣 계수 특징</h2>
<ul>
<li><p>수식:</p>
<p>  $$
  S(i) = \frac{b(i)-a(i)}{max(a(i),b(i))} \ 단\ i는 데이터
  $$</p>
</li>
<li><p><strong>해석</strong>: <strong>1로 갈수록 근처의 군집과 더 멀리 떨어짐.</strong> 0에 가까울 수록 근처 군집과 가까워 진다는 것</p>
</li>
</ul>
<aside>
📌 수식을 해석해보자면 특정한 데이터 i의 실루엣 계수는  얼마나 떨어져있는가($b(i) -a(i)$)가 클 수록 크며, 이를 단위 정규화를 위해 $a(i), b(i)$ 값 중에 큰 값으로 나눕니다.
</aside>

<ul>
<li>Python 라이브러리<ul>
<li><code>sklearn.metrics.sihouette_score</code>: 전제 데이터의 실루엣 계수 평균 값 반환<ul>
<li>함수 입력 값<ul>
<li><code>X</code>: 데이터 세트</li>
<li><code>labels</code>: 레이블</li>
<li><code>metrics</code>: 측정 기준 기본은 <code>euclidean</code><h2 id="좋은-군집화의-조건">좋은 군집화의 조건</h2>
<ul>
<li>실루엣 값이 높을수록(1에 가까울 수록)</li>
<li>0에 가까울수록 클러스터링 불확실</li>
<li>음수값은 클러스터링 결과가 잘못됨</li>
<li>개별 군집의 평균 값의 편차가 크지 않을 수록</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h1 id="4-붓꽃-데이터-군집화">4. 붓꽃 데이터 군집화</h1>
<ul>
<li>원본 데이터 분포 확인<pre><code class="language-python">import pandas as pd
import seaborn as sns 
import sklearn 
import matplotlib.pyplot as plt 
</code></pre>
</li>
</ul>
<p>iris_df = sns.load_dataset(&#39;iris&#39;)
iris_df.head(3)</p>
<p>sns.scatterplot(data = iris_df, x = &#39;sepal_length&#39;, y = &#39;sepal_width&#39;)</p>
<pre><code>![](https://velog.velcdn.com/images/waterglasses_k/post/6e0926d9-b4fc-48d7-93fd-eaeb3fae503c/image.png)

- KMeans 모델 학습 및 예측
```python
iris_df_2 = iris_df.copy().drop(columns = &#39;species&#39;)

iris_df_2.head(3)

from sklearn.cluster import KMeans
X = iris_df_2[[&#39;sepal_length&#39;, &#39;sepal_width&#39;, &#39;petal_length&#39;, &#39;petal_width&#39;]]

kmeans = KMeans(n_clusters = 3, random_state=42, init = &#39;k-means++&#39;, max_iter= 300)
kmeans.fit(X) #비지도학습이기 때문에 y값을 넣어주지 않음
iris_df_2[&#39;cluster&#39;] = kmeans.predict(X)  

iris_df_2.head(3) </code></pre><p><img src="https://velog.velcdn.com/images/waterglasses_k/post/b8fe8db4-3dd6-4221-a472-5ea13b38d798/image.png" alt=""></p>
<ul>
<li>그래프 비교<pre><code class="language-python">plt.figure(figsize = (12, 6))
plt.subplot(1, 2, 1)
sns.scatterplot(data = iris_df, x = &#39;sepal_length&#39;, y = &#39;sepal_width&#39;, hue = &#39;species&#39;)
plt.title(&#39;Original&#39;)
</code></pre>
</li>
</ul>
<p>plt.subplot(1, 2, 2)
sns.scatterplot(data = iris_df_2, x = &#39;sepal_length&#39;, y = &#39;sepal_width&#39;, hue = &#39;cluster&#39;, palette = &#39;winter&#39;)
plt.title(&#39;Clustering&#39;)
plt.show()</p>
<pre><code>![](https://velog.velcdn.com/images/waterglasses_k/post/abaeedbc-295d-465a-83ec-fd9b0eb1b04d/image.png)

왼쪽 그래프는 군집화 그래프와 비교해보기 위해 species를 그려본 것.
1번 군집은 잘 군집화 된 것으로 보임
- 평가지표 - 실루엣 계수
```python
from sklearn.metrics import silhouette_score
silhouette_score(X, iris_df_2[&#39;cluster&#39;])
```
0.5528190123564097
이 수준이면 클러스터링이 잘 되었다고 판단할 수 있다고 gpt가 말해주었다.

---

# 5. RFM 고객 군집화 실습
## 고객 세그멘테이션 정의
비지도 학습이 가장 많이 사용되는 곳이 고객관리(CRM)
타겟마케팅을 위해 고객 특성에 맞게 세분화할 수 있다. 
## RFM
- Recency(R) 가장 최근 구입 일에서 오늘까지의 시간
- Frequency(F): 상품 구매 횟수
- Monetary value(M): 총 구매 금액

---
- 데이터 불러오기 및 전처리를 위한 확인과정
```python
import pandas as pd 
import matplotlib.pyplot
import seaborn as sns 
import sklearn 

retail_df = pd.read_excel(&#39;/Users/sookyeong/Desktop/Online Retail.xlsx&#39;)

retail_df.isnull().sum()

retail_df.describe(include = &#39;all&#39;)
```
- 전처리 대상
   - customerid , description null값 삭제
   - quantity, unitprice (-)값 삭제
   - county 영국 대상
```python
con_customer = retail_df[&#39;CustomerID&#39;].notnull()
con_quan = retail_df[&#39;Quantity&#39;] &gt; 0 
con_price = retail_df[&#39;UnitPrice&#39;] &gt; 0
con_county = retail_df[&#39;Country&#39;] == &#39;United Kingdom&#39;
retail_df2 = retail_df[con_customer &amp; con_quan &amp; con_price &amp; con_county]</code></pre><ul>
<li>RFM<ul>
<li>R : 최근방문일 : InvoiceDate 컬럼 사용해 가장최근(2011-12-09 + 1)일에서 고객별 최신방문일 빼줌</li>
<li>F : 방문빈도 : 고객별 방문건수</li>
<li>M : 구매합계 --&gt; 고객별 amount_monetary<pre><code class="language-python">#매출총합
retail_df2[&#39;amount_monetary&#39;] = retail_df2[&#39;Quantity&#39;] * retail_df2[&#39;UnitPrice&#39;]
retail_df2[&#39;amount_monetary&#39;] = retail_df2[&#39;amount_monetary&#39;].astype(&#39;int&#39;)
</code></pre>
</li>
</ul>
</li>
</ul>
<p>#최근방문경과일 
import datetime as dt 
#2011.12.10일 기준으로 각 날짜를 빼고 + 1 </p>
<h1 id="추후-customerid-기준으로-period의-최소의-period를-구하면-그것이-recency">추후 customerid 기준으로 period의 최소의 period를 구하면 그것이 recency</h1>
<p>retail_df2[&#39;Period&#39;] = (dt.datetime(2011, 12, 10) - retail_df2[&#39;InvoiceDate&#39;]).apply(lambda x : x.days + 1)
retail_df2</p>
<p>#고객별 RFM
rfm_df = retail_df2.groupby(&#39;CustomerID&#39;).agg({&#39;Period&#39; : &#39;min&#39;,
                                      &#39;InvoiceNo&#39; : &#39;count&#39;,
                                      &#39;amount_monetary&#39; : &#39;sum&#39;})
rfm_df.columns = [&#39;Recency&#39;, &#39;Frequency&#39;, &#39;Monetary&#39;]</p>
<p>rfm_df</p>
<pre><code>![](https://velog.velcdn.com/images/waterglasses_k/post/a35293f4-be06-44fb-ae3c-32afa2063237/image.png)

- 분포도 확인 및 스케일링
```python
sns.pairplot(rfm_df)


from sklearn.preprocessing import StandardScaler
sc = StandardScaler() 

X = rfm_df[[&#39;Recency&#39;, &#39;Frequency&#39;, &#39;Monetary&#39;]]

X_features = sc.fit_transform(X)
X_features</code></pre><ul>
<li>KMeans 군집화<pre><code class="language-python">from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
</code></pre>
</li>
</ul>
<p>kmeans = KMeans(n_clusters = 3, random_state = 42)
labels = kmeans.fit_predict(X_features)
rfm_df[&#39;label&#39;] = labels</p>
<p>silhouette_score(X_features, labels) -- 0.592575402996014</p>
<pre><code>
- 군집화 그래프를 위한 함수
```python
### 여러개의 클러스터링 갯수를 List로 입력 받아 각각의 실루엣 계수를 면적으로 시각화한 함수 작성
def visualize_silhouette(cluster_lists, X_features): 

    from sklearn.cluster import KMeans
    from sklearn.metrics import silhouette_samples, silhouette_score

    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    import numpy as np

    # 입력값으로 클러스터링 갯수들을 리스트로 받아서, 각 갯수별로 클러스터링을 적용하고 실루엣 개수를 구함
    n_cols = len(cluster_lists)

    # plt.subplots()으로 리스트에 기재된 클러스터링 수만큼의 sub figures를 가지는 axs 생성 
    fig, axs = plt.subplots(figsize=(4*n_cols, 4), nrows=1, ncols=n_cols)

    # 리스트에 기재된 클러스터링 갯수들을 차례로 iteration 수행하면서 실루엣 개수 시각화
    for ind, n_cluster in enumerate(cluster_lists):

        # KMeans 클러스터링 수행하고, 실루엣 스코어와 개별 데이터의 실루엣 값 계산. 
        clusterer = KMeans(n_clusters = n_cluster, max_iter=500, random_state=0)
        cluster_labels = clusterer.fit_predict(X_features)

        sil_avg = silhouette_score(X_features, cluster_labels)
        sil_values = silhouette_samples(X_features, cluster_labels)

        y_lower = 10
        axs[ind].set_title(&#39;Number of Cluster : &#39;+ str(n_cluster)+&#39;\n&#39; \
                          &#39;Silhouette Score :&#39; + str(round(sil_avg,3)) )
        axs[ind].set_xlabel(&quot;The silhouette coefficient values&quot;)
        axs[ind].set_ylabel(&quot;Cluster label&quot;)
        axs[ind].set_xlim([-0.1, 1])
        axs[ind].set_ylim([0, len(X_features) + (n_cluster + 1) * 10])
        axs[ind].set_yticks([])  # Clear the yaxis labels / ticks
        axs[ind].set_xticks([0, 0.2, 0.4, 0.6, 0.8, 1])

        # 클러스터링 갯수별로 fill_betweenx( )형태의 막대 그래프 표현. 
        for i in range(n_cluster):
            ith_cluster_sil_values = sil_values[cluster_labels==i]
            ith_cluster_sil_values.sort()

            size_cluster_i = ith_cluster_sil_values.shape[0]
            y_upper = y_lower + size_cluster_i

            color = cm.nipy_spectral(float(i) / n_cluster)
            axs[ind].fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_sil_values, \
                                facecolor=color, edgecolor=color, alpha=0.7)
            axs[ind].text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
            y_lower = y_upper + 10

        axs[ind].axvline(x=sil_avg, color=&quot;red&quot;, linestyle=&quot;--&quot;)</code></pre><ul>
<li><p>그래프 함수적용1. </p>
<pre><code class="language-python">visualize_silhouette([2,3,4,5,6], X_features)</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/64096ab9-c02e-4690-b0ad-c7d11c8ba95e/image.png" alt="">
실루엣 스코어는 높은데 군집의 불균형이 너무 심함</p>
</li>
<li><blockquote>
<p>로그 스케일 적용</p>
</blockquote>
</li>
<li><p>그래프 함수적용2. 로그 스케일</p>
<pre><code class="language-python">#log 스케일을 통한 추가전처리
import numpy as np
</code></pre>
</li>
</ul>
<p>rfm_df[&#39;Recency_log&#39;] = np.log1p(rfm_df[&#39;Recency&#39;])
rfm_df[&#39;Frequency_log&#39;] = np.log1p(rfm_df[&#39;Frequency&#39;])
rfm_df[&#39;Monetary_log&#39;] = np.log1p(rfm_df[&#39;Monetary&#39;])</p>
<p>X_features2 = rfm_df[[&#39;Recency_log&#39;,&#39;Frequency_log&#39;,&#39;Monetary_log&#39;]]
sc2 = StandardScaler()
X_features2_sc = sc2.fit_transform(X_features2)</p>
<p>visualize_silhouette([2,3,4,5,6], X_features2_sc)</p>
<pre><code>![](https://velog.velcdn.com/images/waterglasses_k/post/298ff0a4-e765-4e73-ac10-896aa7336a84/image.png)

실루엣 스코어는 줄었지만 군집화가 균일하게 잘 적용됨을 확인 할 수 있음.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[머신러닝_의사결정나무, 랜덤포레스트, 
KNN(최근접이웃), 부스팅 알고리즘]]></title>
            <link>https://velog.io/@waterglasses_k/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EC%9D%98%EC%82%AC%EA%B2%B0%EC%A0%95%EB%82%98%EB%AC%B4-%EB%9E%9C%EB%8D%A4%ED%8F%AC%EB%A0%88%EC%8A%A4%ED%8A%B8-KNN%EC%B5%9C%EA%B7%BC%EC%A0%91%EC%9D%B4%EC%9B%83-%EB%B6%80%EC%8A%A4%ED%8C%85</link>
            <guid>https://velog.io/@waterglasses_k/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EC%9D%98%EC%82%AC%EA%B2%B0%EC%A0%95%EB%82%98%EB%AC%B4-%EB%9E%9C%EB%8D%A4%ED%8F%AC%EB%A0%88%EC%8A%A4%ED%8A%B8-KNN%EC%B5%9C%EA%B7%BC%EC%A0%91%EC%9D%B4%EC%9B%83-%EB%B6%80%EC%8A%A4%ED%8C%85</guid>
            <pubDate>Wed, 21 Feb 2024 07:06:24 GMT</pubDate>
            <description><![CDATA[<h3 id="👩🏻💻-학습한-것">👩🏻‍💻 학습한 것</h3>
<blockquote>
<p>분류모델 학습과 실습</p>
</blockquote>
<ul>
<li>로지스틱스회귀</li>
<li>의사결정나무</li>
<li>랜덤포레스트</li>
<li>KNN</li>
<li>부스팅알고리즘(Grediant, Xboost, Lightgbm)</li>
</ul>
<h1 id="1-의사결정나무decision-tree">1. 의사결정나무(Decision Tree)</h1>
<h2 id="의사결정나무란">의사결정나무란?</h2>
<p>의사결정 규칙을 나무 구조로 나타내어 전체 자료를 몇 개의 소집단으로 분류하거나 예측을 수행하는 분석방법
<img src="https://velog.velcdn.com/images/waterglasses_k/post/ea4c2613-8e0a-4b60-84b2-5f6f7a05afb1/image.png" alt=""></p>
<h2 id="의사결정나무-구조">의사결정나무 구조</h2>
<ul>
<li>루트 노드(Root Node): 의사결정나무의 시작점. 최초의 분할조건</li>
<li>리프 노드(Leaf Node): 루트 노드로부터 파생된 중간 혹은 최종 노드</li>
<li>분류기준(criteria): sex는 여성인 경우 0, 남성인 경우 1로 인코딩. 여성인 경우 좌측 노드로, 남성인 경우 우측 노드로 분류</li>
<li>불순도(impurity)<ul>
<li>불순도 측정 방법 중 하나 인 지니 계수는 0과 1사이 값으로 0이 완벽한 순도(모든 샘플이 하나의 클래스), 1은 완전한 불순도(노드의 샘플의 균등하게 분포) 됨을 나타냄</li>
<li>리프 노드로 갈수록 불순도가 작아지는(한쪽으로 클래스가 분류가 잘되는)방향으로 나무가 자람<ul>
<li>샘플(samples): 해당 노드의 샘플 개수(891개의 관측치)</li>
<li>값(value): Y변수에 대한 배열. 549명이 죽었고(Y = 0), 342명이 살았음(Y = 1)</li>
<li>클래스(class)</li>
</ul>
</li>
<li>가장 많은 샘플을 차지하는 클래스를 표현</li>
<li>위에서는 주황색(Y = 0 다수), 파란색(Y=1 다수)를 표현<h2 id="의사결정나무-정리">의사결정나무 정리</h2>
</li>
</ul>
</li>
<li>장점<ul>
<li>쉽고 해석하기 용이</li>
<li>다중분류와 회귀에 모두 적용이 가능</li>
<li>이상치에 견고하며 데이터 스케일링이 불필요(데이터의 상대적인 순서를 고려해서)</li>
</ul>
</li>
<li>단점<ul>
<li>나무가 성장을 너무 많이하면 과대 적합의 오류에 빠질 수 있다.</li>
<li>훈련 데이터에 민감하게 반응하여 작은 변화가 노이즈에도 나무의 구조가 크게 달라짐(불안정성)</li>
</ul>
</li>
<li>Python 라이브러리<ul>
<li><code>sklearn.tree.DecisionTreeClassifier</code></li>
<li><code>sklearn.tree.DecisionTreeRegressor</code><pre><code class="language-python">X = titanic_df[[&#39;Pclass&#39;, &#39;Sex&#39;, &#39;Age&#39;]]
y_true = titanic_df[&#39;Survived&#39;]
</code></pre>
</li>
</ul>
</li>
</ul>
<p>#labelencoder : Pclass, Sex</p>
<h1 id="결측치제거--age">결측치제거 : Age</h1>
<p>from sklearn.preprocessing import LabelEncoder
le1 = LabelEncoder() 
le2 = LabelEncoder()</p>
<p>titanic_df[&#39;Sex&#39;] = le1.fit_transform(titanic_df[&#39;Sex&#39;])
titanic_df[&#39;Pclass&#39;] = le2.fit_transform(titanic_df[&#39;Pclass&#39;])
titanic_df[&#39;Age&#39;] = titanic_df[&#39;Age&#39;].fillna(titanic_df[&#39;Age&#39;].mean()) </p>
<h1 id="decisiontree">decisiontree</h1>
<p>from sklearn.tree import DecisionTreeClassifier
from sklearn import tree </p>
<p>model_dt = DecisionTreeClassifier(max_depth = 1, random_state=42) 
model_dt.fit(X, y_true)</p>
<p>plt.figure(figsize = (10, 5))
tree.plot_tree(model_dt, feature_names = X.columns.tolist(), class_names = [&#39;Not Survived&#39;, &#39;Survived&#39;], filled = True)
plt.show()</p>
<pre><code>![](https://velog.velcdn.com/images/waterglasses_k/post/5dffd8b1-58a6-40b5-94a9-842ff2264fbe/image.png)

---

# 2. 랜덤포레스트(Random Forest) 
## 랜덤포레스트란?

의사결정나무의 과적합과 불안정성을 해결하기 위함
## 배깅(Bagging)의 원리
- 언제나 머신러닝은 데이터의 부족이 문제
- 이를 해결 하기 위한 Bootstrapping + Aggregating 방법론
    - Bootstrapping: 데이터를 복원 추출해서 유사하지만 다른 데이터 집단을 생성하는 것
    - Aggregating: 데이터의 예측,분류 결과를 합치는 것
    - Ensemble(앙상블): 여러 개의 모델을 만들어 결과를 합치는 것
![](https://velog.velcdn.com/images/waterglasses_k/post/d30ce71a-469e-4723-9a3e-0ab61d6c916f/image.png)
## Tree를 Forest로 만들기
- 여러개의 데이터 샘플에서 각자 의사결정트리를 만들어서 다수결 법칙에 따라 결론을 냄
ex) 1번 승객에 대해서 모델 2개는 생존, 모델 1개는 사망을 분류하였다면, 1번 승객은 최종적으로 생존으로 분류
- 이로써 의사결정모델이 훈련 데이터에 민감한 점을 극복함.
![](https://velog.velcdn.com/images/waterglasses_k/post/90452615-582b-4bec-8584-24179cc98ef7/image.png)
## 랜덤포레스트 정리
- 장점
    - Bagging  과정을 통해 과적합을 피할 수 있다.
    - 이상치에 견고하며 데이터 스케일링이 불필요
    - 변수 중요도를 추출하여 모델 해석에 중요한 특징을 파악 할 수 있다.
- 단점
    - 컴퓨터 리소스 비용이 크다.
    - 앙상블 적용으로 해석이 어렵다.
- Python 패키지
    - `sklearn.ensemble.RandomForestClassifer`
    - `sklearn.ensemble.RandomForestRegressor`

```python
#로지스틱스회귀, 디시전트리, 랜덤포레스트(--학습한 분류모델 비교)
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier

X = titanic_df[[&#39;Pclass&#39;, &#39;Sex&#39;, &#39;Age&#39;]]
y_true = titanic_df[&#39;Survived&#39;]

model_lr = LogisticRegression()
model_dt = DecisionTreeClassifier()
model_rf = RandomForestClassifier()

#학습
model_lr.fit(X, y_true)
model_dt.fit(X, y_true)
model_rf.fit(X, y_true)

#예측 
lr_y_pred = model_lr.predict(X)
dt_y_pred = model_dt.predict(X)
rf_y_pred = model_rf.predict(X)

#평가, acc, f1
from sklearn.metrics import accuracy_score, f1_score
print(&#39;로지스틱스회귀 : acc&#39;, accuracy_score(y_true, lr_y_pred).round(2), &#39;f1&#39;, f1_score(y_true, dt_y_pred).round(2))
print(&#39;의사결정나무 : acc&#39;, accuracy_score(y_true, dt_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, dt_y_pred).round(3))
print(&#39;랜덤포레스트 : acc&#39;, accuracy_score(y_true, rf_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, rf_y_pred).round(3))</code></pre><p>로지스틱스회귀 : acc 0.8 f1 0.83
의사결정나무 : acc 0.88 f1 0.833
랜덤포레스트 : acc 0.88 f1 0.835</p>
<hr>
<h1 id="3-knnk-nearest-neighbor-최근접-이웃">3. KNN(K-Nearest Neighbor, 최근접 이웃)</h1>
<h2 id="knn이란">KNN이란?</h2>
<ul>
<li>주변의 데이터를 보고 내가 알고 싶은 데이터를 예측하는 방식
<img src="https://velog.velcdn.com/images/waterglasses_k/post/79f6651d-7c0f-4379-9530-b2845855f72b/image.png" alt=""><ul>
<li>K=3이라면 별 1개와 세모 2개이므로 ? 는 세모로 예측될 것<ul>
<li>K=7이라면 별 4개와 세모 3개이므로 ?는 별로 예측될 것<h2 id="하이퍼마라미터">하이퍼마라미터</h2>
</li>
</ul>
</li>
</ul>
</li>
<li><strong>파라미터(Parameter):</strong> 머신러닝 모델이 학습 과정에서 추정하는 내부 변수이며 자동으로 결정 되는 값<ul>
<li>Ex) 선형회귀에서 가중치와 편향</li>
<li>(혼동주의) Python에서는 함수 정의에서 함수가 받을 수 있는 인자(입력 값)를 지정하는 개념</li>
</ul>
</li>
<li><strong>하이퍼 파라미터(Hyper parameter):</strong> 데이터 과학자가 기계 학습 모델 훈련을 관리하는데 사용하는 외부 구성변수이며 모델 학습과정이나 구조에 영향을 미침
  즉, 분석가가 지정하는 값. <h2 id="거리의-개념">거리의 개념</h2>
</li>
<li>유클리드 거리 : 2차원에서는 두 점 좌표 사이의 거리</li>
<li>맨해튼거리 : 가로와 세로의 거리</li>
<li><em><strong>거리는 단위의 영향을 많이 받기 때문에 스케일링 필수!</strong></em>
<img src="https://velog.velcdn.com/images/waterglasses_k/post/039c0a66-f763-4396-91a3-d95243758651/image.png" alt=""></li>
</ul>
<h2 id="knn-모델-정리">KNN 모델 정리</h2>
<ul>
<li>장점<ul>
<li>이해하기 쉽고 직관적</li>
<li>모집단의 가정이나 형태를 고려하지 않음</li>
<li>회귀, 분류 모두 가능함</li>
</ul>
</li>
<li>단점<ul>
<li>차원 수가 많을 수록 계산량이 많아짐</li>
<li>거리 기반의 알고리즘이기 때문에 피처의 표준화가 필요함</li>
</ul>
</li>
<li>Python 라이브러리<ul>
<li><code>sklearn.neighbors.KNeighborsClassifier</code></li>
<li><code>sklearn.neighbors.KNeighborsRegressor</code></li>
</ul>
</li>
</ul>
<hr>
<h1 id="4-부스팅-알고리즘">4. 부스팅 알고리즘</h1>
<h2 id="부스팅-알고리즘이란">부스팅 알고리즘이란?</h2>
<p>여러개의 약한 학습을 순차적으로 학습하면서 잘못 예측한 데이터에 가중치를 부여하여 오류를 개선해나가는 학습 방법
<img src="blob:https://velog.io/f90d2e8c-31b6-42a5-ac99-3b84a3eb4318" alt="업로드중.."></p>
<h2 id="부스팅-알고리즘-종류">부스팅 알고리즘 종류</h2>
<ul>
<li>Gradient Boosting Model<ul>
<li>특징<ul>
<li>가중치 업데이트를 경사하강법 방법을 통해 진행</li>
</ul>
</li>
<li>Python 라이브러리<ul>
<li><code>sklearn.ensemble.GradientBoostingClassifier</code></li>
<li><code>sklearn.ensemble.GradientBoostingRegressor</code><ul>
<li>XGBoost</li>
</ul>
</li>
</ul>
</li>
<li>특징<ul>
<li>트리기반 앙상블 기법으로, 가장 각광받으며 Kaggle의 상위 알고리즘</li>
<li>병렬학습이 가능해 속도가 빠름</li>
</ul>
</li>
<li>Python 라이브러리<ul>
<li><code>xgboost.XGBRegressor</code></li>
<li><code>xgboost.XGBRegressor</code><ul>
<li>LightGBM</li>
</ul>
</li>
</ul>
</li>
<li>특징<ul>
<li>XGBoost와 함께 가장 각광받는 알고리즘</li>
<li>XGBoost보다 학습시간이 짧고 메모리 사용량이 작음</li>
<li>작은 데이터(10,000건 이하)의 경우 과적합 발생</li>
</ul>
</li>
<li>Python 라이브러리<ul>
<li><code>lightgbm.LGBMClassifier</code></li>
<li><code>lightgbm.LGBMRegressor</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-python"># KNN
# 부스팅알고리즘(gradient, XGboost, LightGBM) &amp; 회귀, 의사결정, 랜포 함께 비교

from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import GradientBoostingClassifier
from xgboost import XGBRFClassifier
from lightgbm import LGBMClassifier

model_knn = KNeighborsClassifier()
model_gbm = GradientBoostingClassifier(random_state=42)
model_xgbm = XGBRFClassifier(random_state=42)
model_lgbm = LGBMClassifier(random_state=42)

#학습
model_knn.fit(X, y_true)
model_gbm.fit(X, y_true)
model_xgbm.fit(X, y_true)
model_lgbm.fit(X, y_true)

#예측
knn_y_pred = model_knn.predict(X)
gbm_y_pred = model_gbm.predict(X)
xgbm_y_pred = model_xgbm.predict(X)
lgbm_y_pred = model_lgbm.predict(X)

#평가
print(&#39;로지스틱스회귀 : acc&#39;, accuracy_score(y_true, lr_y_pred).round(2), &#39;f1&#39;, f1_score(y_true, dt_y_pred).round(3))
print(&#39;의사결정나무 : acc&#39;, accuracy_score(y_true, dt_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, dt_y_pred).round(3))
print(&#39;랜덤포레스트 : acc&#39;, accuracy_score(y_true, rf_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, rf_y_pred).round(3))
print(&#39;KNN : acc&#39;, accuracy_score(y_true, knn_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, knn_y_pred).round(3))
print(&#39;GBM : acc&#39;, accuracy_score(y_true, gbm_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, gbm_y_pred).round(3))
print(&#39;XBOOST : acc&#39;, accuracy_score(y_true, xgbm_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, xgbm_y_pred).round(3))
print(&#39;LightGBM : acc&#39;, accuracy_score(y_true, lgbm_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, lgbm_y_pred).round(3))</code></pre>
<p>로지스틱스회귀 : acc 0.8 f1 0.833
의사결정나무 : acc 0.88 f1 0.833
랜덤포레스트 : acc 0.88 f1 0.835
KNN : acc 0.833 f1 0.77
GBM : acc 0.855 f1 0.805
XBOOST : acc 0.82 f1 0.752
LightGBM : acc 0.862 f1 0.812</p>
<hr>
<h2 id="모델-평가지수-높여보기">모델 평가지수 높여보기</h2>
<ul>
<li>x변수 추가<pre><code class="language-python">#fare와 embarked(결측치처리) 추가하여 평가점수 높여보기
</code></pre>
</li>
</ul>
<p>X = titanic_df[[&#39;Pclass&#39;, &#39;Sex&#39;, &#39;Age&#39;, &#39;Fare&#39;, &#39;Embarked&#39;]]
y_true = titanic_df[&#39;Survived&#39;]
titanic_df[&#39;Embarked&#39;] = titanic_df[&#39;Embarked&#39;].fillna(&#39;S&#39;)</p>
<p>le3 = LabelEncoder()
titanic_df[&#39;Embarked&#39;] = le3.fit_transform(titanic_df[&#39;Embarked&#39;])</p>
<p>model_lr = LogisticRegression()
model_dt = DecisionTreeClassifier()
model_rf = RandomForestClassifier()
model_knn = KNeighborsClassifier()
model_gbm = GradientBoostingClassifier(random_state=42)
model_xgbm = XGBRFClassifier(random_state=42)
model_lgbm = LGBMClassifier(random_state=42)</p>
<p>#학습</p>
<p>model_lr.fit(X, y_true)
model_dt.fit(X, y_true)
model_rf.fit(X, y_true)
model_knn.fit(X, y_true)
model_gbm.fit(X, y_true)
model_xgbm.fit(X, y_true)
model_lgbm.fit(X, y_true)</p>
<p>#예측 
lr_y_pred = model_lr.predict(X)
dt_y_pred = model_dt.predict(X)
rf_y_pred = model_rf.predict(X)
knn_y_pred = model_knn.predict(X)
gbm_y_pred = model_gbm.predict(X)
xgbm_y_pred = model_xgbm.predict(X)
lgbm_y_pred = model_lgbm.predict(X)</p>
<p>#평가
print(&#39;로지스틱스회귀 : acc&#39;, accuracy_score(y_true, lr_y_pred).round(2), &#39;f1&#39;, f1_score(y_true, dt_y_pred).round(3))
print(&#39;의사결정나무 : acc&#39;, accuracy_score(y_true, dt_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, dt_y_pred).round(3))
print(&#39;랜덤포레스트 : acc&#39;, accuracy_score(y_true, rf_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, rf_y_pred).round(3))
print(&#39;KNN : acc&#39;, accuracy_score(y_true, knn_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, knn_y_pred).round(3))
print(&#39;GBM : acc&#39;, accuracy_score(y_true, gbm_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, gbm_y_pred).round(3))
print(&#39;XBOOST : acc&#39;, accuracy_score(y_true, xgbm_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, xgbm_y_pred).round(3))
print(&#39;LightGBM : acc&#39;, accuracy_score(y_true, lgbm_y_pred).round(3), &#39;f1&#39;, f1_score(y_true, lgbm_y_pred).round(3))</p>
<p>````
로지스틱스회귀 : acc 0.79 f1 0.973
의사결정나무 : acc 0.98 f1 0.973
랜덤포레스트 : acc 0.98 f1 0.973
KNN : acc 0.809 f1 0.732
GBM : acc 0.889 f1 0.845
XBOOST : acc 0.869 f1 0.813
LightGBM : acc 0.945 f1 0.927</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[python_코드카타(2024.02.16)]]></title>
            <link>https://velog.io/@waterglasses_k/python%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802024.02.16</link>
            <guid>https://velog.io/@waterglasses_k/python%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802024.02.16</guid>
            <pubDate>Fri, 16 Feb 2024 03:56:59 GMT</pubDate>
            <description><![CDATA[<h2 id="22-두-정수의-합">22. <a href="https://school.programmers.co.kr/learn/courses/30/lessons/12912">두 정수의 합 </a></h2>
<blockquote>
</blockquote>
<h3 id="문제">문제</h3>
<p>두 정수 a, b가 주어졌을 때 a와 b 사이에 속한 모든 정수의 합을 리턴하는 함수, solution을 완성하세요.
예를 들어 a = 3, b = 5인 경우, 3 + 4 + 5 = 12이므로 12를 리턴합니다.</p>
<h3 id="👩🏻💻-my-coding">👩🏻‍💻 my coding</h3>
<p>처음엔 a, b 중간의 값들을 어떻게 빼야하는지 계속 골머리를 앓았다. 
a, b 사이에 정수가 여러개면 어째야 하지 고민하다보니 리스트에 넣어서 모두 더하기로.</p>
<pre><code class="language-python">def solution(a, b):
    if a != b:
        n = abs(a - b)
        num = min(a, b)
        x = []
        for i in range(n + 1):
            num = num + i 
            x.append(num)
        return sum(x)
    else:
        return a</code></pre>
<p>그런데 함수를 작동해보니 테스트케이스가 틀린다.
노트에 하나씩 써봐도 왜 틀린지를 모르겠다.
gpt 해보니</p>
<pre><code class="language-python">def solution(a, b):
    if a != b:
        n = abs(a - b)
        num = min(a, b)
        x = []
        for i in range(n + 1):
            num = num 
            x.append(num + i)
        return sum(x)
    else:
        return a</code></pre>
<p>리스트에 직접 +i 를 해준다.
어떻게 다른지 물어봐도 지피티도 계속 같은 함수라는 말만 한다. 
튜터님에게 물어봐야겠다. </p>
<p>아대박 😇 멍청한게 여기서 드러나네
함수하면 if, for을 써야하겠다는 댕초보의 강박관념...
쉽게! 생각하면 된다고 하시며 알려줌</p>
<pre><code class="language-python">def solution(a, b) : 
    start_value = min(a, b)
    final_value = max(a, b)
    return sum(range(start_value, final_value+1))</code></pre>
<p>한번만 보고도 코드를 쳤다. 
등차수열을 이용하는게 가장 빠르다고 하셨지만 어차피 내가 응용을 못할 것 같아서 패스했다.
상단에 내가 틀린 반복문은 num이 계속 자라나는 형태라는데, 크게 중요하진 않은듯</p>
<p>정말 아차싶었던 이번 문제였다.
혼자풀지말고 쉽게 풀어가는 길을 찾아야겠다.</p>
<hr>
<h2 id="22-콜라츠-추측">22. 콜라츠 추측</h2>
<blockquote>
<h3 id="문제-1">문제</h3>
<p>1937년 Collatz란 사람에 의해 제기된 이 추측은, 주어진 수가 1이 될 때까지 다음 작업을 반복하면, 모든 수를 1로 만들 수 있다는 추측입니다. 작업은 다음과 같습니다.</p>
</blockquote>
<hr>
<p>1-1. 입력된 수가 짝수라면 2로 나눕니다. 
1-2. 입력된 수가 홀수라면 3을 곱하고 1을 더합니다. 
2. 결과로 나온 수에 같은 작업을 1이 될 때까지 반복합니다. </p>
<hr>
<p>예를 들어, 주어진 수가 6이라면 6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1 이 되어 총 8번 만에 1이 됩니다. 위 작업을 몇 번이나 반복해야 하는지 반환하는 함수, solution을 완성해 주세요. 단, 주어진 수가 1인 경우에는 0을, 작업을 500번 반복할 때까지 1이 되지 않는다면 –1을 반환해 주세요.</p>
<h3 id="👩🏻💻-my-coding-1">👩🏻‍💻 my coding</h3>
<pre><code class="language-python">def solution(num) : 
    count = 0
    for _ in range(500) : 
        if num == 1 : 
            return count 
        if num % 2 == 0 : 
            num  = num // 2
        elif num % 2 != 0 : 
            num  = num * 3 + 1
        count = count + 1 
    return -1 </code></pre>
<p>여기서는 순서가 중요하다.
1인지 아닌지 먼저 판별하고 그 뒤에 홀짝여부 판별 뒤 카운트를 해준다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python_기초실습 2 (feat. temperature data)]]></title>
            <link>https://velog.io/@waterglasses_k/Python%EA%B8%B0%EC%B4%88%EC%8B%A4%EC%8A%B5-2-feat.-temperature-data</link>
            <guid>https://velog.io/@waterglasses_k/Python%EA%B8%B0%EC%B4%88%EC%8B%A4%EC%8A%B5-2-feat.-temperature-data</guid>
            <pubDate>Thu, 15 Feb 2024 09:25:37 GMT</pubDate>
            <description><![CDATA[<h3 id="🎯-오늘의-목표">🎯 오늘의 목표</h3>
<blockquote>
</blockquote>
<ul>
<li>SQLite 데이터베이스에서 SQL을 사용하여 데이터를 전처리하고</li>
<li>Python을 활용해 필요한 데이터를 시각화하기!</li>
</ul>
<h3 id="👩🏻💻-오늘-배운-것">👩🏻‍💻 오늘 배운 것</h3>
<blockquote>
</blockquote>
<p>*<em>✅ SQLite 활용법
✅ 파이썬에서 SQL연결, 테이블 생성하기
✅ 시각화 스킬업(plt.grid(True), plt.tight_layout())
✅ <code>pd.to_datetime</code>으로 날짜타입으로 바꿔 그래프 정리해주기
✅ 변동성 분석(절대값으로!)
✅ `LAG(윈도우함수, 이전행을 가져옴)
✅ 자기상관성 분석(np 이용해 자기상관계수 구하기, 그래프 그리기)
*</em></p>
<h2 id="sqlite란">SQLite란?</h2>
<p><code>장점</code></p>
<ul>
<li>별도의 서버 프로세스 없이 SQL 데이터베이스 엔진을 제공</li>
<li>모바일 애플리케이션, 소규모 프로젝트에 적합</li>
<li>접근이 용이하고 관리가 간편함</li>
</ul>
<p><code>단점</code></p>
<ul>
<li>대용량 데이터베이스나 고성능을 요구하는 애플리케이션에서는 부적합</li>
<li>동시성 처리가 제한적</li>
</ul>
<p><code>MySQL과 비교</code></p>
<ul>
<li>MySQL은 서버 기반의 DBMS로, 대규모 데이터베이스와 고성능을 요구하는 애플리케이션에 적합</li>
<li>고급 기능과 보안, 복잡한 트랜잭션 처리 제공</li>
<li>단, 설치와 관리가 복잡하며 리소스 사용량이 더 높음</li>
</ul>
<p>✅ 규모로 따지면, <code>Oracle &gt; MySQL &gt; SQLite</code></p>
<hr>
<h3 id="1-라이브러리-임포트">1. 라이브러리 임포트</h3>
<pre><code class="language-python">import pandas as pd
import sqlite3. #SQLite를 사용하기 위한 파이썬 내장 라이브러리
import matplotlib.pyplot as plt</code></pre>
<h3 id="2-데이터-로드-및-sqlite-데이터베이스로-변환">2. 데이터 로드 및 SQLite 데이터베이스로 변환</h3>
<pre><code class="language-python">url = &#39;https://raw.githubusercontent.com/jbrownlee/Datasets/master/daily-min-temperatures.csv&#39;
data = pd.read_csv(url)

conn = sqlite3.connect(&#39;daily_temperatures.db&#39;)

data.to_sql(&#39;temperatures&#39;, conn, if_exists = &#39;replace&#39;, index = False)</code></pre>
<p>✅ <strong>sql 연결, 테이블 생성</strong>
<code>conn = sqlite3.connect(&#39;daily_temperatures.db&#39;)</code></p>
<ul>
<li>sqlite에 있는 daily_temperatures.db에 연결</li>
<li>해당 파일이 없다면 새로 생성하고, 존재하는 경우 파일에 연결</li>
</ul>
<p><code>.to_sql</code></p>
<ul>
<li>&#39;temperatures&#39;라는 이름의 테이블로 데이터를 SQLite에 저장</li>
</ul>
<p><code>if_exists = replace</code></p>
<ul>
<li>해당 테이블이 이미 존재하는 경우, 기존 테이블을 대체</li>
</ul>
<p><code>index = False</code></p>
<ul>
<li>dataframe의 인덱스를 테이블에 저장하지 않겠다</li>
</ul>
<h3 id="3-sql-쿼리실행-연도별-최대-기온">3. SQL 쿼리실행: 연도별 최대 기온</h3>
<pre><code class="language-python">yearly_max_temp_query = &quot;&quot;&quot;
SELECT strftime(&#39;%Y&#39;, Date) as Year,
       max(Temp) as MaxTemp
FROM temperatures 
GROUP BY Year
ORDER BY Year ; 
&quot;&quot;&quot;

yearly_max_temp = pd.read_sql_query(yearly_max_temp_quaery)</code></pre>
<p>✅ <strong>파이썬에서 &quot;&quot;&quot;사이에 SQL 쿼리문을 작성하여 전처리 가능</strong></p>
<h3 id="4-데이터-시각화--연도별-최대-기온">4. 데이터 시각화 : 연도별 최대 기온</h3>
<pre><code class="language-python">plt.figure(figsize = (12, 6))
plt.plot(yearly_max_temp[&#39;Year&#39;], yearly_max_temp[&#39;MaxTemp&#39;], marker = &#39;o&#39;, color = &#39;darkblue&#39;, linestyle = &#39;--&#39;)
plt.title(&#39;Yearly Maximum Temperature&#39;)
plt.xlabel(&#39;Year&#39;)
plt.ylabel(&#39;Max Temperature (°C)&#39;)
plt.xticks(rotation=45)
plt.grid(True)
plt.tight_layout()
plt.show()</code></pre>
<p>✅ <strong>시각화 스킬 업</strong>
<code>plt.grid(True)</code> : 그리드를 표시해 포인트 위치를 잘 식별
<code>plt.tight_layout()</code>: 그래프 레이아웃 자동 조정, 이쁘게</p>
<h3 id="5-sql-쿼리-실행--월별-평균-기온">5. SQL 쿼리 실행 : 월별 평균 기온</h3>
<pre><code class="language-python">monthly_avg_temp_query = &quot;&quot;&quot;
select strftime(&#39;%Y-%m&#39;, Date) as YearMonth,
       avg(Temp) as AvgTemp
from temperatures
group by YearMonth
order by YearMonth ; 
&quot;&quot;&quot;

monthly_avg_temp = pd.read_sql_query(monthly_avg_temp_query, conn)</code></pre>
<h3 id="6-데이터-시각화--월별-평균-기온">6. 데이터 시각화 : 월별 평균 기온</h3>
<pre><code class="language-python">plt.figure(figsize=(15, 7))
plt.plot(monthly_avg_temp[&#39;YearMonth&#39;], monthly_avg_temp[&#39;AvgTemp&#39;], marker=&#39;o&#39;, linestyle=&#39;-&#39;, color=&#39;coral&#39;)
plt.title(&#39;Monthly Average Temperature&#39;)
plt.xlabel(&#39;Year-Month&#39;)
plt.ylabel(&#39;Average Temperature (°C)&#39;)
plt.xticks(rotation=45)
plt.grid(True)
plt.tight_layout()
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/b5fb28f1-4de3-4f4a-a00a-653d876b4777/image.png" alt="">
이러면 x축 눈금이 너무 많아 보기 안좋다. 
<code>pd.to_datetime</code>으로 시각화 수정하기</p>
<pre><code class="language-python">plt.figure(figsize=(15, 7))
plt.plot(pd.to_datetime(monthly_avg_temp[&#39;YearMonth&#39;]), monthly_avg_temp[&#39;AvgTemp&#39;], marker=&#39;o&#39;, linestyle=&#39;-&#39;, color=&#39;coral&#39;)
plt.title(&#39;Monthly Average Temperature&#39;)
plt.xlabel(&#39;Year-Month&#39;)
plt.ylabel(&#39;Average Temperature (°C)&#39;)
plt.xticks(rotation=45)
plt.grid(True)
plt.tight_layout()
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/f0e080fa-e305-4d5e-be95-fcdde517e143/image.png" alt=""></p>
<hr>
<h3 id="7-변동성-분석">7. 변동성 분석</h3>
<ul>
<li>변동성 분석은 기온데이터의 일일변동폭을 측정하여 기온이 얼마나 변동성이 큰지 파악하는 분석</li>
<li>특정기간 동안 기온 변화의 안정성을 평가할 수 있다.<pre><code class="language-python">query = &quot;&quot;&quot;
select Date,
        ABS(Temp - LAG(Temp,1) over (order by Date)) as DailyChange
from temperatures
&quot;&quot;&quot;
daily_change = pd.read_sql_query(query, conn)</code></pre>
<pre><code class="language-python"># 일별 기온 변동성 시각화
plt.figure(figsize=(14, 7))
plt.plot(pd.DataFrame(daily_change[&#39;Date&#39;]), daily_change[&#39;DailyChange&#39;], color=&#39;blue&#39;, alpha=0.5)
plt.title(&#39;Daily Temperature Change&#39;)
plt.xlabel(&#39;Date&#39;)
plt.ylabel(&#39;Temperature Change (°C)&#39;)
plt.show()</code></pre>
<img src="https://velog.velcdn.com/images/waterglasses_k/post/dc70402c-01bb-407d-b897-0cc40241baab/image.png" alt=""></li>
</ul>
<p>✅ <strong>변동성 분석 : 얼마나 변동성이 큰지 파악(절대값 사용)
✅ <code>LAG</code>: 이전의 행을 가져옴</strong></p>
<h2 id="오늘의-킥---자기상관성-분석">오늘의 킥! - 자기상관성 분석</h2>
<ul>
<li>자기상관성 분석?
시계열 데이터에서 한 시점의 데이터가 이전 시점의 데이터와 어떤 관계를 가지는지 분석하는 방법. 시간의 흐름에 따른 데이터의 패턴 파악하는데 유용함.<pre><code class="language-python">import numpy as np
</code></pre>
</li>
</ul>
<p>query = &quot;&quot;&quot;
select Date, 
       Temp,
       LAG(Temp, 1) over (order by Date)as PrevDayTemp
from temperatures 
order by Date
&quot;&quot;&quot;</p>
<p>temp_data  = pd.to_sql_query(query, conn)
temp_data.dropna(inplace = True)
temp_data[&#39;TempChange&#39;] = temp_data[&#39;Temperature&#39;] - temp_data[&#39;PrevDayTemp&#39;]
temp_data</p>
<p>````
<img src="https://velog.velcdn.com/images/waterglasses_k/post/5e24c5d4-9f10-49bd-93a3-4ae0fe74a55a/image.png" alt=""></p>
<h3 id="자기상관성-분석-그래프">자기상관성 분석 그래프</h3>
<pre><code class="language-python">correlation = np.corrcoef(temp_data[&#39;TempChange&#39;][1:], temp_data[&#39;TempChange&#39;][:-1])[0, 1]
print(f&#39;1일차 기온 변화의 자기상관계수 {correlation : 2.f}&#39;)

pd.plotting.autocorrelation_plot(temp_data[&#39;Temperature&#39;])
plt.title[&#39;Autocorrelation of Daily Temperature&#39;]
plt.show()
</code></pre>
<p>1일 시차 기온 변화의 자기상관 계수: -0.18
<img src="https://velog.velcdn.com/images/waterglasses_k/post/8dee9f06-7995-4c20-b6f8-a1b62da38e1c/image.png" alt=""></p>
<p><strong>✅ 자기상관성 계수는 -1에서 1 사이
✅ 자기상관성 계수 그래프 : <code>pd.plotting.autocorrelation_plot</code>
✅ 첫번째와 마지막 요소 제외(인덱싱) 이유 : 이전값과 현재값의 쌍을 맞춰 데이터 포인트의 불균형을 줄이고 신뢰성을 높일 수 있음
✅<code>[0, 1]</code>은 상관 계수행렬의 인덱싱. 상관계수 행렬의 <code>[i, j]</code>위치의 값은 i번째 배열과 j번째 배열의 상관관계를 나타냄. [0,1]은 상관계수 행렬에 인덱싱하여 두 배열간의 상관계수를 추출함.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[sql_코드카타(2024.02.14)]]></title>
            <link>https://velog.io/@waterglasses_k/sql%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802024.02.14</link>
            <guid>https://velog.io/@waterglasses_k/sql%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802024.02.14</guid>
            <pubDate>Wed, 14 Feb 2024 09:59:37 GMT</pubDate>
            <description><![CDATA[<h2 id="percentage-of-users-attended-a-contest"><a href="https://leetcode.com/problems/percentage-of-users-attended-a-contest/description/">Percentage of Users Attended a Contest</a></h2>
<blockquote>
</blockquote>
<h3 id="table-1--user">Table 1 : User</h3>
<p>+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| user_id     | int     |
| user_name   | varchar |
+-------------+---------+
user_id is the primary key (column with unique values) for this table.
Each row of this table contains the name and the id of a user.</p>
<h3 id="table-2--register">Table 2 : Register</h3>
<p>+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| contest_id  | int     |
| user_id     | int     |
+-------------+---------+</p>
<h3 id="문제">문제</h3>
<p>각 콘테스트에 등록된 사용자의 비율을 소수점 이하 두 자리 까지 반올림하여 구하는 솔루션을 작성하세요.
percentage로 내림차순으로 반환합니다 . 동점인 경우 contest_id 오름차순으로 정렬 합니다.</p>
<h3 id="👩🏻💻my-coding">👩🏻‍💻my coding</h3>
<pre><code class="language-sql"># 콘테스트별 참여 유저
SELECT contest_id, COUNT(DISTINCT user_id) AS users_participated
FROM Register
GROUP BY contest_id;

# 유저의 총 합
SELECT COUNT(DISTINCT user_id) AS total_users
FROM Register;

# 합치기
select contest_id,
round(count(distinct user_id) *100 / (select count(distinct user_id) as total_users from register),2) as percentage
from register
group by contest_id 
order by percentage desc, contest_id </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python_기초실습 1 (feat. temperature data)]]></title>
            <link>https://velog.io/@waterglasses_k/Python%EA%B8%B0%EC%B4%88%EC%8B%A4%EC%8A%B5-unstack-parsedates-%EC%9D%B4%EB%8F%99%ED%8F%89%EA%B7%A0-feat.-temperature-data</link>
            <guid>https://velog.io/@waterglasses_k/Python%EA%B8%B0%EC%B4%88%EC%8B%A4%EC%8A%B5-unstack-parsedates-%EC%9D%B4%EB%8F%99%ED%8F%89%EA%B7%A0-feat.-temperature-data</guid>
            <pubDate>Wed, 14 Feb 2024 09:17:54 GMT</pubDate>
            <description><![CDATA[<h2 id="기온-데이터를-통한-기초-분석">기온 데이터를 통한 기초 분석</h2>
<h3 id="👩🏻💻-학습한-것">👩🏻‍💻 학습한 것</h3>
<p>✅ <code>parse_dates</code> : 컬럼을 날짜형식으로 파싱
✅ <code>data.isnull().values.any()</code> : 데이터 결측지 있는지 확인
✅ <code>data.dropna(inplace = true)</code> : 결측치 행 삭제
✅ <code>unstack()</code> : 다중인덱스 중 하나를 열로 변환
✅ 이동평균 : 데이터의 장기적인 추세를 파악
✅ <code>rolling(window=)</code> : 이동평균 계산시 얼마나 말아주느냐
✅ <code>resample</code> : 동일 간격별로 데이터를 뽑음(WAU, MAU에도 많이 사용)
✅ 추세선 : 선형회귀 모델을 활용한 추세선 그리기
✅ 히트맵 - <code>cmap</code> : colormap / <code>annot</code> : annotion / <code>fmt</code> : format
✅ IQR 이상치 전처리</p>
<blockquote>
<p>Q1 = data[&#39;column&#39;].quantile(0.25)
Q3 = data[&#39;column&#39;].quantile(0.75)
IQR = Q3 - Q1
upper_limit = Q3 + 1.5 IQR
lower_limit = Q1 - 1.5 IQR</p>
</blockquote>
<h3 id="1-데이터-로드-및-전처리">1. 데이터 로드 및 전처리</h3>
<pre><code class="language-python"># 필요한 라이브러리 임포트
import pandas as pd  # 데이터를 다루는데 사용되는 라이브러리
import matplotlib.pyplot as plt  # 시각화를 위한 라이브러리
import seaborn as sns  # Matplotlib을 기반으로 한 시각화 라이브러리

# 데이터 로드
url = &#39;https://raw.githubusercontent.com/jbrownlee/Datasets/master/daily-min-temperatures.csv&#39;  # 데이터가 저장된 URL
data = pd.read_csv(url, parse_dates=[&#39;Date&#39;], index_col=&#39;Date&#39;)  # CSV 파일을 Pandas DataFrame으로 읽어들임
# parse_dates 옵션은 &#39;Date&#39; 열을 날짜로 파싱하도록 지정함
# index_col 옵션은 &#39;Date&#39; 열을 인덱스로 사용하도록 지정함

# 데이터 확인
print(data.head())  # 데이터의 처음 몇 개 행을 출력하여 내용을 확인함

# 결측치 확인 및 처리
if data.isnull().values.any():  # 데이터에 결측치(NaN)가 있는지 확인
    data.dropna(inplace=True)  # 결측치가 있으면 해당 행을 삭제함

# 데이터 타입 확인
print(data.dtypes)  # 데이터프레임의 각 열의 데이터 타입을 출력함</code></pre>
<p>✅  <strong>parse_dates : 컬럼을 날짜형식으로 파싱</strong>
✅ <strong>data.isnull().values.any() : 데이터 결측지 있는지 확인</strong>
✅ <strong>data.dropna(inplace = true) : 결측치 행 삭제</strong></p>
<h3 id="2-기초-통계-분석">2. 기초 통계 분석</h3>
<pre><code class="language-python"># 연도와 월 컬럼 추가
data[&#39;Year&#39;] = data.index.year  # 인덱스에서 연도를 추출하여 &#39;Year&#39; 열로 추가
data[&#39;Month&#39;] = data.index.month  # 인덱스에서 월을 추출하여 &#39;Month&#39; 열로 추가

# 연도별 평균 기온 계산
yearly_avg_temp = data.groupby(&#39;Year&#39;)[&#39;Temp&#39;].mean()  # &#39;Year&#39;로 그룹화하여 각 연도별 평균 기온을 계산

# 월별 평균 기온 계산
monthly_avg_temp = data.groupby([&#39;Year&#39;, &#39;Month&#39;])[&#39;Temp&#39;].mean().unstack()
# &#39;Year&#39;와 &#39;Month&#39;로 그룹화하여 각 연도별, 월별 평균 기온을 계산하고,
# unstack() 함수를 사용하여 다중 인덱스에서 월을 열로 변환하여 표 형태로 만듦

# 연도별 평균 기온 통계 정보 출력
print(yearly_avg_temp.describe())
# 연도별 평균 기온에 대한 통계 정보(평균, 표준편차, 최솟값, 1사분위수, 중위값, 3사분위수, 최댓값)를 출력</code></pre>
<p>✅ <strong>unstack() : 다중인덱스 중 하나를 열로 변환</strong></p>
<h3 id="3-이동평균-분석">3. 이동평균 분석</h3>
<pre><code class="language-python"># 12개월 이동 평균 계산
data[&#39;Moving_Avg&#39;] = data[&#39;Temp&#39;].rolling(window=365).mean()
# &#39;Temp&#39; 열을 기준으로 12개월 이동 평균을 계산하여 &#39;Moving_Avg&#39; 열에 저장
# rolling(window=365) 메서드는 이동 평균을 계산하는데 사용되며, 창(window) 크기를 365로 지정하여 12개월 이동 평균을 계산

# 이동 평균 시각화
plt.figure(figsize=(12, 6))  # 시각화 영역의 크기를 설정
plt.plot(data[&#39;Moving_Avg&#39;], color=&#39;orange&#39;, label=&#39;12-Month Moving Average&#39;)  # 이동 평균 데이터를 주황색으로 선 그래프로 플롯
plt.title(&#39;12-Month Moving Average of Temperature&#39;)  # 그래프 제목 설정
plt.xlabel(&#39;Date&#39;)  # x축 레이블 설정
plt.ylabel(&#39;Temperature&#39;)  # y축 레이블 설정
plt.legend()  # 범례 표시
plt.show()  # 그래프 출력</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/fd0e9575-386b-4b4f-a57f-b662f13931ca/image.png" alt="">
✅ <strong>이동평균 : 데이터의 장기적인 추세를 파악</strong>
✅ <strong>window : 이동평균 계산시 얼마나 말아주느냐</strong></p>
<ul>
<li>window=12 : 이전 12개(월데이터에 적절)</li>
</ul>
<h3 id="4-이동평균-추세선">4. 이동평균 추세선</h3>
<pre><code class="language-python">import numpy as np  # 수치 연산을 위한 라이브러리
from sklearn.linear_model import LinearRegression  # 선형 회귀 모델 라이브러리 임포트

# 연도별 이동 평균 기온 준비
yearly_moving_avg = data[&#39;Moving_Avg&#39;].resample(&#39;Y&#39;).mean()
# &#39;Moving_Avg&#39; 열의 연도별 이동 평균을 계산하기 위해 연도(Year)별로 리샘플링하고, 각 연도별 평균값을 계산함
# .resample : 계열 index를 연도 단위의 동일 간격별로 데이터를 뽑으라는 뜻

# 선형 회귀 모델을 사용하여 추세선 계산
model = LinearRegression().fit(np.arange(len(yearly_moving_avg)).reshape(-1, 1), yearly_moving_avg.values)
# 선형 회귀 모델을 초기화하고, 연도별 이동 평균 기온 데이터에 대해 학습함
# np.arange(len(yearly_moving_avg)).reshape(-1, 1)은 데이터를 피팅하기 위한 형태로 변환함

# 추세선을 위한 예측 값 계산
trend = model.predict(np.arange(len(yearly_moving_avg)).reshape(-1, 1))
# 학습된 모델을 사용하여 각 연도별 추세 값을 예측함

# 이동 평균과 함께 추세선 그리기
plt.figure(figsize=(12, 6))  # 그래프 영역의 크기를 설정함
plt.plot(yearly_moving_avg.index, yearly_moving_avg.values, label=&#39;12-Month Moving Average&#39;)  # 12개월 이동 평균을 플롯함
plt.plot(yearly_moving_avg.index, trend, label=&#39;Trend&#39;, color=&#39;red&#39;)  # 추세선을 빨간색으로 플롯함
plt.title(&#39;12-Month Moving Average with Trend Line&#39;)  # 그래프 제목 설정
plt.xlabel(&#39;Year&#39;)  # x축 레이블 설정
plt.ylabel(&#39;Temperature&#39;)  # y축 레이블 설정
plt.legend()  # 범례 표시
plt.show()  # 그래프 출력</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/90f9e913-ff29-42d0-8c3d-6e74bfc4d5a8/image.png" alt=""></p>
<p>✅ ** resample : 동일 간격별로 데이터를 뽑음(WAU, MAU에도 많이 사용)
✅ 추세선 : 선형회귀 모델을 활용한 추세선 그리기**</p>
<h3 id="5-box-plot과-이상치-탐색">5. Box Plot과 이상치 탐색</h3>
<pre><code class="language-python"># 월별 기온 분포 상자 그림
sns.boxplot(x=&#39;Month&#39;, y=&#39;Temp&#39;, data=data)
# 월별로 기온 데이터를 상자 그림으로 표시
# x=&#39;Month&#39;는 x축에 월을, y=&#39;Temp&#39;는 y축에 기온을 나타냄
# data=data는 사용할 데이터프레임을 지정함

plt.title(&#39;Box Plot of Temperatures by Month&#39;)
# 그래프 제목 설정
plt.show()
# 그래프 출력</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/d18ebf5b-3554-484d-88aa-033aed46d63c/image.png" alt=""></p>
<h3 id="6-iqr-이상치-처리">6. IQR 이상치 처리</h3>
<pre><code>#IQR로 이상치 제거하기(혼자 실습))
Q1 = data[&#39;Temp&#39;].quantile(0.25)
Q3 = data[&#39;Temp&#39;].quantile(0.75)
IQR = Q3 - Q1 

upper_limit = Q3 + 1.5 * IQR
lower_limit = Q1 - 1.5 * IQR 

data_no_outliers = data[(data[&#39;Temp&#39;] &lt;= upper_limit) &amp; (data[&#39;Temp&#39;] &gt;= lower_limit)]

sns.boxplot(data = data_no_outliers, x = &#39;Month&#39;, y = &#39;Temp&#39;)</code></pre><p><img src="https://velog.velcdn.com/images/waterglasses_k/post/54afd493-6a62-4239-9bdf-ff1e5a40ca18/image.png" alt=""></p>
<p>✅ <strong>IQR 수식 외우기</strong></p>
<blockquote>
</blockquote>
<p><strong>Q1</strong> = data[&#39;column&#39;].quantile(0.25)
<strong>Q3 *<em>= data[&#39;column&#39;].quantile(0.75)
*</em>IQR</strong> = Q3 - Q1 
<strong>upper_limit</strong> = Q3 + 1.5 * IQR
<strong>lower_limit</strong> = Q1 - 1.5 * IQR </p>
<h3 id="7-히트맵-시각화">7. 히트맵 시각화</h3>
<pre><code class="language-python">plt.figure(figsize=(12, 9))
# 그래프의 크기를 설정함

sns.heatmap(monthly_avg_temp, cmap=&#39;coolwarm&#39;, annot=True, fmt=&quot;.1f&quot;)
# seaborn의 heatmap 함수를 사용하여 월별 평균 기온 데이터를 열 지도(heat map)로 시각화함
# monthly_avg_temp는 월별 평균 기온 데이터를 포함하는 DataFrame이며, 각 셀에는 기온 값이 표시됨
# cmap=&#39;coolwarm&#39;은 컬러맵을 설정하는데, coolwarm은 차가운 색과 따뜻한 색의 대비를 나타냄
# annot=True는 각 셀에 값의 주석을 추가하라는 의미이며, fmt=&quot;.1f&quot;는 주석의 형식을 소수점 첫째 자리까지 표시하라는 의미임

plt.title(&#39;Heatmap of Monthly Average Temperatures&#39;)
# 그래프의 제목을 설정함

plt.xlabel(&#39;Month&#39;)
# x축 레이블을 설정함

plt.ylabel(&#39;Year&#39;)
# y축 레이블을 설정함

plt.show()
# 그래프를 출력함</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/c3242a1e-9dd0-4cce-8d24-648440191bc8/image.png" alt=""></p>
<p>✅ <strong>cmap : colormap</strong>
✅ <strong>annot : annotion</strong>
✅ <strong>fmt : format</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Project] GA4 데이터 분석 (DAU/WAU/MAU, ECDF, HEATMAP)]]></title>
            <link>https://velog.io/@waterglasses_k/Project-GA4-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-DAUWAUMAU-ECDF-HEATMAP</link>
            <guid>https://velog.io/@waterglasses_k/Project-GA4-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-DAUWAUMAU-ECDF-HEATMAP</guid>
            <pubDate>Thu, 08 Feb 2024 09:52:55 GMT</pubDate>
            <description><![CDATA[<p>어제 구했던 DAU, WAU, MAU는 코드가 복잡하다.
groupby를 사용해 다시 구했다.</p>
<p>✅ <strong>DAU, WAU, MAU - groupby 이용해 구하기</strong></p>
<pre><code class="language-python">dau = df3.groupby(df3[&#39;new_date&#39;])[&#39;fullVisitorId&#39;].nunique()
wau = df3.groupby(df3[&#39;new_date&#39;].dt.to_period(&#39;W&#39;))[&#39;fullVisitorId&#39;].nunique()
mau = df3.groupby(df3[&#39;new_date&#39;].dt.to_period(&#39;M&#39;))[&#39;fullVisitorId&#39;].nunique()

plt.figure(figsize=(10,5))
plt.plot(dau, label = &#39;DAU&#39;)
plt.plot(wau, label = &#39;WAU&#39;)
plt.plot(mau, label = &#39;MAU&#39;)
plt.xlabel(&#39;DATE&#39;)
plt.ylabel(&#39;Number of User&#39;)
plt.title(&#39;DAU / WAU / MAU&#39;)
plt.legend()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/65be5a49-0eaa-492c-96f4-0d53556b380e/image.png" alt="">
데이터 타입이 날짜형식이라면 <code>dt.to_period</code>메소드를 사용해 주별, 연도별 활동유저를 구할 수 있다!</p>
<hr>
<h2 id="유저별-평균접속시간의-분포를-ecdf로-시각화">유저별 평균접속시간의 분포를 ECDF로 시각화</h2>
<p>: 데이터의 누적분포를 시각화 한 것이다.
이건 답이 아닌것 같지만 작업한 과정을 기록해보기로</p>
<ul>
<li><strong>방법 : daily로 첫 접속과 마지막 접속 사이의 길이를 평균 접속 시간으로 간주</strong><pre><code class="language-python">#유저별 첫 번째 접속과 마지막 접속을 파악하여 DataFrame을 재구성
first_last_visit = df3.groupby([df3[&#39;fullVisitorId&#39;], df3[&#39;new_visitStartTime&#39;].dt.date])[&#39;new_visitStartTime&#39;].agg([&#39;first&#39;, &#39;last&#39;])
</code></pre>
</li>
</ul>
<h1 id="각-사용자의-접속-기간을-계산하여-새로운-열로-추가">각 사용자의 접속 기간을 계산하여 새로운 열로 추가</h1>
<p>first_last_visit[&#39;session_duration&#39;] = first_last_visit[&#39;last&#39;] - first_last_visit[&#39;first&#39;]
#session_duration이 음수값도 있음 -&gt; 제외 필요</p>
<h1 id="마지막-접속-시간이-처음-접속-시간보다-큰-행만-선택하여-새로운-dataframe을-생성">마지막 접속 시간이 처음 접속 시간보다 큰 행만 선택하여 새로운 DataFrame을 생성</h1>
<p>filtered_data = first_last_visit[first_last_visit[&#39;last&#39;] &gt; first_last_visit[&#39;first&#39;]]</p>
<p>#유저별 평균 접속시간 계산하기
#이미 사용자별 접속시간을 구했으므로(session_duration) 해당 컬럼으로 groupby 
#level = 0 : 사용자별로 다 시그룹화하는데 사용되는 인덱스 레벨 -&gt; fullVisitorId
mean_session_duration = filtered_data[&#39;session_duration&#39;].groupby(level=0).mean()</p>
<p>#ecdf계산
def ecdf(data):
    n = len(data)
    x = np.sort(data)
    y = np.arange(1, n + 1) / n
    return x, y</p>
<p>x, y = ecdf(mean_session_duration)</p>
<h1 id="시각화">시각화</h1>
<p>plt.figure(figsize=(6, 5))
plt.plot(x, y, marker=&#39;.&#39;, linestyle=&#39;none&#39;)
plt.xlabel(&#39;Average Session Duration&#39;)
plt.ylabel(&#39;ECDF&#39;)
plt.title(&#39;ECDF of Average Session Duration by User&#39;)
plt.grid(True)
plt.show()</p>
<pre><code>![](https://velog.velcdn.com/images/waterglasses_k/post/452c41b2-47ca-4b3f-915b-b073ea1f4fdc/image.png)
내가 해석한 내용은
- y축 0.5기준으로 평균접속시간이 늘어난다.
- 데이터 분포가 right-skew됨을 알 수 있다. 

---
## 요일/시간대별 사용자 수를 구하고 이를 heatmap으로 시각화
```python
#요일별, 시간대별 사용자수 구하기
week_hour_user = df3.groupby([df3[&#39;new_visitStartTime&#39;].dt.hour, df3[&#39;new_visitStartTime&#39;].dt.weekday])[&#39;fullVisitorId&#39;].nunique()

# 히트맵을 그리기위한 피벗테이블
# unstack은 다중 인덱스를 가진 데이터프레임을 사용할 때 하나의 인덱스를 컬럼으로 변환할 수 있음
week_hour_user = week_hour_user.unstack()</code></pre><p>여기서 unstack()이 킥이다.
.unstack()을 해주면 인덱스컬럼이 열로 변환되어 피봇으로 이쁘게 변환된다.</p>
<pre><code class="language-python"># heatmap그리기
plt.figure(figsize=(15, 8))
sns.heatmap(data = week_hour_user, cmap=&#39;YlGnBu&#39;, annot = True, fmt = &#39;d&#39;, linewidths=0.5)
plt.title(&#39;Weekday/Hour User Count&#39;)
plt.xlabel(&#39;Week of Day&#39;)
plt.ylabel(&#39;Hour&#39;)
plt.xticks(ticks=np.arange(7), labels=[&#39;Monday&#39;, &#39;Tuesday&#39;, &#39;Wednesday&#39;, &#39;Thursday&#39;, &#39;Friday&#39;, &#39;Saturday&#39;, &#39;Sunday&#39;])
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/7b7d2aa9-deae-4e58-96a1-d2df20ff1786/image.png" alt=""></p>
<p>비교적 히트맵은 이쁘게 그려진듯
평일 오후 6시정도가 가장 유저 활동이 많다! </p>
<hr>
<h3 id="👩🏻💻-오늘-써먹어본-것">👩🏻‍💻 오늘 써먹어본 것</h3>
<blockquote>
</blockquote>
<ul>
<li>goupby : 사용법에 대해 이제 좀 감이 잡힌듯</li>
<li>unstack() : 히트맵그릴때, 피봇테이블 만들때 유용</li>
<li>ECDF : 분포를 확인하는 그래프같은데 아직 잘 모르겠음..!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Project] GA4 데이터 분석 전처리(drop, fillna, astype, DAU/WAU/MAU 구하기)]]></title>
            <link>https://velog.io/@waterglasses_k/Project-GA4-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%EC%A0%84%EC%B2%98%EB%A6%ACdrop-fillna-astype-DAUWAUMAU-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@waterglasses_k/Project-GA4-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%EC%A0%84%EC%B2%98%EB%A6%ACdrop-fillna-astype-DAUWAUMAU-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 07 Feb 2024 09:45:41 GMT</pubDate>
            <description><![CDATA[<p>팀원들과 논의 후 필요없는 컬럼 재정리</p>
<pre><code class="language-python"># new_date는 new_visitstarttime과 같은 값이라 제외
df3 = df3.drop([&#39;keyword&#39;, &#39;newVisits&#39;, &#39;new_date&#39;], axis =1)</code></pre>
<p>✅ <strong>drop을 쓸때도 axis=1을 해준다.</strong>
<img src="https://velog.velcdn.com/images/waterglasses_k/post/3f97b023-e9df-41d1-80f7-0c08a44a8a34/image.png" alt="">
null값이 있는게 눈에 띄는데
pageview는 조회수, bounce는 이탈, transactionrevenue는 거래금액으로 분석의 중요한 지표라 판단해서 결측치를 처리해 사용하기로 했다.
결측치는 평균값을 대체하거나 0을 넣거나 하는 등 적절하게 채워주면 된다.
세 컬럼 모두 기록이 없는 것이 결측치라 판단, 0을 넣어주었다.</p>
<pre><code class="language-python">#transactionrevenue, bounces 결측치 0으로 채우기
df3[&#39;transactionRevenue&#39;] = df3[&#39;transactionRevenue&#39;].fillna(0)
df3[&#39;bounces&#39;] = df3[&#39;bounces&#39;].fillna(0)
df3[&#39;pageviews&#39;] = df3[&#39;pageviews&#39;].fillna(0)</code></pre>
<p>✅ <strong>fillna(0) 으로 결측치 처리하기</strong></p>
<hr>
<h2 id="dauwaumau">DAU/WAU/MAU</h2>
<p>전처리가 모두 완료된건 아닌 것 같지만, 필요한 것은 그때그때 분석때 하기로하고 먼저 DAU/WAU/MAU 구하는 것을 시도해보기로!</p>
<ul>
<li>유저는 &#39;fullVisitorID&#39;</li>
<li>일자는 new_visitStartTime</li>
</ul>
<p>✅ <strong>1. 시각까지 포함된 컬럼값 수정(dt.date)</strong></p>
<pre><code class="language-python">timestamp_day = df3[&#39;new_visitStartTime&#39;].dt.date</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/df126dad-bcaf-4563-81e0-c2d8bd2977a5/image.png" alt=""></p>
<p>✅ <strong>DAU 구하기(groupby 사용)</strong></p>
<pre><code class="language-python">dau = df3.groupby(timestamp_day)[&#39;fullVisitorId&#39;].nunique()</code></pre>
<p>groupby 메소드로 날짜별 고유한 유저수를 구한다.
<img src="https://velog.velcdn.com/images/waterglasses_k/post/b390dd2a-8861-43d7-81fe-8ac2c7aa9346/image.png" alt=""></p>
<p>✅ <strong>WAU/MAU 구하기(resample 사용)</strong>
WAU와 MAU는 단순히 일자를 보는게 아니라 일주일별, 달별로 기간을 쪼개고 유저수를 따져주어야 한다. 
resample 메소드를 사용해봄</p>
<pre><code class="language-python">#wau 구하기
start_date = pd.Timestamp(&#39;2016-08-01&#39;)
end_date = pd.Timestamp(&#39;2017-07-31&#39;)
filtered_data = df[(df[&#39;new_visitStartTime&#39;] &gt;= start_date) &amp; (df[&#39;new_visitStartTime&#39;] &lt;= end_date)]

wau = filtered_data.resample(&#39;W-Mon&#39;, on=&#39;new_visitStartTime&#39;)[&#39;fullVisitorId&#39;].nunique()
wau</code></pre>
<p>wau에서 <code>filtered_data</code> 대신 <code>df3</code>데이터를 넣으면 로딩이 한참걸린다. 
데이터 기준을 잡고 필터링을 하고 &#39;W-Mon&#39;을 기준으로 구한다.
&#39;M&#39;을 기준으로 구하면 MAU
&#39;D&#39;로 잡으면 DAU겠지?</p>
<pre><code class="language-python">#mau 구하기
start_date = pd.Timestamp(&#39;2016-08-01&#39;)
end_date = pd.Timestamp(&#39;2017-07-31&#39;)
filtered_data = df[(df[&#39;new_visitStartTime&#39;] &gt;= start_date) &amp; (df[&#39;new_visitStartTime&#39;] &lt;= end_date)]

# 월별로 사용자를 그룹화하고 MAU 계산
mau = filtered_data.resample(&#39;M&#39;, on=&#39;new_visitStartTime&#39;)[&#39;fullVisitorId&#39;].nunique()
mau</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/cef85fe4-ca21-4a6c-a370-0c500f5f5682/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/70ac18c9-e582-47e2-a129-8798cefa78c2/image.png" alt=""></p>
<p>✅ <strong>DAU/WAU/MAU 그래프 합치기</strong></p>
<pre><code class="language-python">#dau, mau 그래프 합치기
plt.figure(figsize=(8,5))
plt.plot(dau, label = &#39;DAU&#39;, color = &#39;blue&#39;)
plt.plot(wau, label = &#39;WAU&#39;, color = &#39;green&#39;)
plt.plot(mau, label = &#39;MAU&#39;, color = &#39;red&#39;)
plt.xlabel(&#39;Date&#39;)
plt.ylabel(&#39;users&#39;)
plt.legend()
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/waterglasses_k/post/e60ac6bc-9400-4805-884e-7f25da338717/image.png" alt=""></p>
<p>내가 혼자 해본거라 틀릴수도 있음!</p>
<blockquote>
<p><strong>👩🏻‍💻오늘 써먹어본 것!</strong></p>
</blockquote>
<ul>
<li>.fillna()</li>
<li>drop.df[&#39;column&#39;], axis = 1</li>
<li>filterdata.resample(&#39;M&#39;, on=&#39;date&#39;)[&#39;use_id&#39;].nunique()</li>
<li>df.groupby(&#39;date&#39;)[&#39;user_id&#39;].nunique()</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[python_코드카타(2024.01.06)]]></title>
            <link>https://velog.io/@waterglasses_k/python%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802024.01.06</link>
            <guid>https://velog.io/@waterglasses_k/python%EC%BD%94%EB%93%9C%EC%B9%B4%ED%83%802024.01.06</guid>
            <pubDate>Tue, 06 Feb 2024 11:38:13 GMT</pubDate>
            <description><![CDATA[<h2 id="18-문자열을-정수로-바꾸기">18. <a href="https://school.programmers.co.kr/learn/courses/30/lessons/12925">문자열을 정수로 바꾸기</a></h2>
<blockquote>
</blockquote>
<h3 id="문제설명">문제설명</h3>
<p>문자열 s를 숫자로 변환한 결과를 반환하는 함수, solution을 완성하세요.</p>
<h3 id="제한조건">제한조건</h3>
<p>s의 길이는 1 이상 5이하입니다.
s의 맨앞에는 부호(+, -)가 올 수 있습니다.
s는 부호와 숫자로만 이루어져있습니다.
s는 &quot;0&quot;으로 시작하지 않습니다.</p>
<h3 id="입출력-예">입출력 예</h3>
<p>예를들어 str이 &quot;1234&quot;이면 1234를 반환하고, &quot;-1234&quot;이면 -1234를 반환하면 됩니다.
str은 부호(+,-)와 숫자로만 구성되어 있고, 잘못된 값이 입력되는 경우는 없습니다.</p>
<h3 id="👩🏻💻-my-coding">👩🏻‍💻 my coding</h3>
<pre><code class="language-python">def solution(n) : 
    return int(n)</code></pre>
<h2 id="19-정수-제곱근-판별">19. <a href="https://school.programmers.co.kr/learn/courses/30/lessons/12934">정수 제곱근 판별</a></h2>
<blockquote>
</blockquote>
<h3 id="문제설명-1">문제설명</h3>
<p>임의의 양의 정수 n에 대해, n이 어떤 양의 정수 x의 제곱인지 아닌지 판단하려 합니다.
n이 양의 정수 x의 제곱이라면 x+1의 제곱을 리턴하고, n이 양의 정수 x의 제곱이 아니라면 -1을 리턴하는 함수를 완성하세요.</p>
<h3 id="👩🏻💻-my-coding-1">👩🏻‍💻 my coding</h3>
<pre><code class="language-python">def solution(n): 
    for i in range(n) : 
        if n == i**2 : 
            return (i+1)**2
        else : 
            return -1</code></pre>
<p>처음 이렇게 코딩했는데, 이렇게 하면 첫번째 반복문에서 조건 검사 후 무조건 -1이 출력된다. 
return -1을 반복문이 끝난 후에 실행해 반복문을 모두 실행한 후에도 정답을 못찾을 때만 -1이 출려되게 한다.</p>
<pre><code class="language-python">def solution(n):
    for i in range(n):
        if n == i ** 2:
            return (i + 1) ** 2
    return -1</code></pre>
<p>그런데 이렇게 해도 예외 테스트 케이스에서 걸린다.
실제로는 i가 n-1까지 돌기 때문에  </p>
<pre><code class="language-python">def solution(n):
    for i in range(n+1):
        if n == i ** 2:
            return (i + 1) ** 2
    return -1</code></pre>
<p>😇 n 자기 자신인 경우에도 고려되어야 하기 때문에 range(n+1)이 되어야 한다.</p>
]]></description>
        </item>
    </channel>
</rss>