데이터 시각화
matplotlib 설치

plt.plot(y)처럼 y 값만 전달했을 때 Matplotlib은 다음과 같이 동작한다.
- 인덱스 활용: 데이터의 개수(n)를 파악한 뒤, 0부터 n-1까지의 정수를 $x$ 값으로 자동 생성한다.
- 좌표 대응: 주어진 예시 y = [1, 2, 3, 4]의 경우, 내부적으로 생성된 x = [0, 1, 2, 3]과 결합하여 (0, 1), (1, 2), (2, 3), (3, 4) 지점을 선으로 잇는다.
import matplotlib.pyplot as plt
y = [1,2,3,4] # x값을 안 넣으면 알아서 값을 넣어준다
plt.plot(y)
plt.show()

독립변수와 종속변수의 정의
데이터 분석과 머신러닝에서 두 변수는 다음과 같은 역할을 수행한다.
- 독립변수 (Independent Variable, x): 원인이 되는 변수다. 머신러닝에서는 특성(Feature) 또는 설명 변수라고 부른다. 실험자가 직접 조절하거나 관찰의 기준으로 삼는 값이다.
- 종속변수 (Dependent Variable, y): 결과가 되는 변수다. 머신러닝에서는 타깃(Target) 또는 **레이블(Label)**이라고 부른다. 독립변수 $x$의 변화에 따라 그 값이 결정된다.
y = [1,2,3,4]
x = [1,2,3,4]
plt.plot(x, y)
plt.ylabel('y label')
plt.xlabel('x label')
plt.show()

비선형(Non-linear) 관계를 시각화
- np.arange(-10, 11): -10부터 10까지 21개의 점을 생성한다. 이 점들을 연결해 곡선처럼 보이게 만든다.
- plt.axis([-10, 10, 0, 100]): 그래프의 뷰포트를 설정한다.
- x축: -10에서 10까지 표시
- y축: 0에서 100까지 표시
- 이 설정을 통해 데이터가 그래프 영역에 꽉 차게 보이거나, 특정 부분을 확대해서 볼 수 있다.
import numpy as np
x = np.arange(-10, 11) # 독립변수
y = x ** 2 # 종속변수
print(x)
print(y)
plt.plot(x, y)
plt.show()
plt.plot(x, y)
# -10, 10: x축의 최소값을 -10, 최대값을 10으로 설정
# 0, 100: y축의 최소값을 0, 최대값을 100으로 설정
plt.axis([-10, 10, 0, 100]) # 비율에 맞춰서 그림을 그려준다
plt.show()

선형과 비선형을 그래프에 시각화

x = np.arange(-20, 21)
y1 = 2*x
y2 = (1/3) * x ** 2 + 5
y3 = -x ** 2 - 5
plt.plot(x, y1, 'g--') # 끊어진선으로 초록
plt.plot(x, y2, 'r^-') # --: 점선, -: 실선, : 점선
plt.plot(x, y3, 'b*:')
plt.axis([-30, 30, -30, 30])
plt.show()

| 코드 | 색상 (Color) | 마커 (Marker) | 선 스타일 (Line Style) |
| 'g--' | Green (초록) | 없음 | Dashed (파선/끊어진 선) |
| 'r^-' | Red (빨강) | Triangle Up (삼각형) | Solid (실선) |
| 'b*:' | Blue (파랑) | Star (별표) | Dotted (점선) |
무작위 데이터를 시각화(이산적)
N = 50
x = np.arange(N)
y = np.random.random(size=N)
plt.plot(x, y, 'g^:')

이산적 데이터, 연속적 데이터
import numpy as np
import matplotlib.pyplot as plt
# 1. arange: 간격 중심 (이산적 느낌)
x_discrete = np.arange(0, 10, 1) # 0, 1, 2, ..., 9
y_discrete = np.sin(x_discrete)
# 2. linspace: 개수 중심 (연속적 느낌)
x_continuous = np.linspace(0, 10, 100) # 0부터 10 사이를 100개로 쪼갬
y_continuous = np.sin(x_continuous)
plt.plot(x_discrete, y_discrete, 'ro', label='arange (Discrete)')
plt.plot(x_continuous, y_continuous, 'b-', label='linspace (Continuous)')
plt.legend()
plt.show()

삼각함수의 시각화
np.linspace(0, np.pi * 2, 1000)은 0도부터 360도까지를 1000개로 쪼갠 것이다.
import numpy as np
import matplotlib.pyplot as plt
# 0서부터 360도를 1000개로 나눠줘라?
x = np.linspace(0, np.pi * 2, 1000)
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x, y1, 'r-') # 사인함수: 기함수
plt.plot(x, y2, 'b:') # 코사인: 우함수
# 저장
plt.savefig('sin_cosine.jpg')
plt.savefig('sin_cosine.png')
plt.savefig('sin_cosine.svg')
plt.savefig('sin_cosine.pdf')
plt.show() # 이걸 먼저 호출하면 현재 생성된 그래프창을 화면에 띄우고 내부적으로 그래프를 그리는데 사용된 메모리를 비워버림

x = np.linspace(0, np.pi * 2, 100)
plt.title('Sin cos curve')
plt.plot(x, np.sin(x), 'r-', label='sin curve')
plt.plot(x, np.cos(x), 'b:', label='cos curve')
plt.xlabel('x value')
plt.ylabel('y value')
# plt.legend() # 범례
plt.legend(loc='upper right') # 위쪽 오른편에 범례를 표시
# matplotlib 에서 사용할 수 있는 범례의 위치를 알려줘
plt.show()

| 위치 문자열 (String) | 정수 코드 (Code) | 설명 |
| 'best' | 0 | 그래프 데이터와 가장 덜 겹치는 곳을 자동으로 계산 |
| 'upper right' | 1 | 오른쪽 위 (기본값) |
| 'upper left' | 2 | 왼쪽 위 |
| 'lower left' | 3 | 왼쪽 아래 |
| 'lower right' | 4 | 오른쪽 아래 |
| 'right' | 5 | 오른쪽 중앙 |
| 'center left' | 6 | 왼쪽 중앙 |
| 'center right' | 7 | 오른쪽 중앙 |
| 'lower center' | 8 | 아래쪽 중앙 |
| 'upper center' | 9 | 위쪽 중앙 |
| 'center' | 10 | 정중앙 |
# 스타일 시트 - 배경을 예쁘게 하고 싶을 때 (토너 많이 먹음..)
import numpy as np
import matplotlib.pyplot as plt
# 1. 스타일 설정 (그래프를 그리기 전에 설정해야 함)
plt.style.use('seaborn-v0_8-whitegrid')
# 2. 데이터 생성
x = np.linspace(0, np.pi * 2, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# 3. 그래프 그리기
plt.figure(figsize=(8, 5)) # 그래프 크기 설정
plt.plot(x, y1, label='Sin Wave', color='tab:blue', linewidth=2)
plt.plot(x, y2, label='Cos Wave', color='tab:red', linestyle='--')
# 4. 꾸미기
plt.title('Sine & Cosine with Whitegrid Style')
plt.xlabel('X (radians)')
plt.ylabel('Amplitude')
plt.legend() # 범례 표시
# 5. 출력 및 저장
plt.show()

1. Figure와 Axes의 개념 정립
Matplotlib의 구조는 계층적이다. 이 관계를 이해하는 것이 커스터마이징의 시작이다.
- Figure (fig): 도화지 전체를 의미함. 여러 개의 서브플롯(Axes)을 담는 가장 큰 바구니이다. 전체 크기(figsize), 배경색 등을 결정한다.
- Axes (ax): 도화지 안에 그려지는 개별 '그래프'이다. 실제 데이터가 그려지는 공간이며, $x$축, $y$축, 제목, 눈금 등을 개별적으로 가진다.
- Axis: 그래프의 축($x$축 또는 $y$축) 자체를 의미하며, 눈금(tick)과 라벨을 관리한다.
2. plt.subplots()의 반환값
fig, ax = plt.subplots(2, 2)는 튜플(Tuple) 형태의 데이터를 반환하며, 언패킹(Unpacking)을 통해 각각 변수에 할당된다.
- fig: Figure 객체 하나.
- ax: 지정한 행렬 크기에 따른 Axes 객체들의 NumPy 배열.
- 2x2로 설정했으므로 ax는 shape=(2, 2)인 행렬이 된다.
- ax[0, 0], ax[0, 1], ax[1, 0], ax[1, 1]처럼 인덱스로 접근하여 각각 다른 그림을 그릴 수 있다.
np.random.randn(n): 표준 정규 분포(평균 0, 표준편차 1)를 따르는 난수를 생성함. 중앙에 데이터가 몰려 있는 종 모양의 분포를 가짐.
np.random.uniform(low, high, size): 지정한 범위 내에서 모든 값이 나올 확률이 동일한 균일 분포를 가짐. imshow에서 노이즈 이미지를 만들거나 가중치 초기화 시 자주 사용됨.
fig, ax = plt.subplots(2, 2)
# 랜덤
X = np.random.randn(100) # 정규분포를 가지는 데이터
Y = np.random.randn(100) # 정규분포를 가지는 데이터
# (0,0) :처음에다가 scatter, 상관적인 산점도 그려주세요
ax[0, 0].scatter(X, Y) # 산점도 그림
# (0, 1): 여기에다가 bar 타입으로 그려주세요, 플롯 타입을 그려주세요
X = np.arange(10) # 0에서 9 사이의 연속값
Y = np.random.uniform(1, 10, 10) # 균일분포값
ax[0, 1].bar(X, Y) # 막대차트
# (1, 0): cos 그림을 그려주세요
X = np.linspace(0, 10, 100)
Y = np.cos(X)
ax[1, 0].plot(X, Y) # 실선을 함수로 그림
# (0, 1): 가로 5, 세로 5 픽셀값을 만들어주세요
Z = np.random.uniform(0, 1, (5,5))
ax[1, 1].imshow(Z) # 분포를 2D 이미지로 그림

scatter (산점도)
- 용도: 두 변수 사이의 상관관계를 파악할 때 사용함.
- 특징: 점들이 모여 있는 형태를 보고 양의 상관관계, 음의 상관관계, 혹은 무상관인지 판단할 수 있음.
bar (막대 그래프)
- 용도: 범주형 데이터의 수치 비교에 적합함.
- 종류: bar(수직), barh(수평)가 있음.
plot (선 그래프)
- 용도: 시간의 흐름에 따른 변화(시계열)나 연속적인 함수를 표현할 때 사용함.
imshow (이미지 표시)
- 용도: 2차원 배열 데이터를 이미지 형태로 시각화함.
- 활용: 딥러닝에서 필터의 가중치 확인, 픽셀 데이터 확인, 혹은 히트맵(Heatmap)을 그릴 때 필수적임.
이중 for문을 활용하여 여러 개의 서브플롯(Axes)을 효율적으로 제어하는 전형적인 패턴
# fig, ax = plt.subplots(2, 3)
_, ax = plt.subplots(2, 3)
# i,j를 문자열로 만들어주고 폰트사이즈로 출력을 해주세요
for i in range(2): # 2행
for j in range(3): # 3열
ax[i, j].text(0.3, 0.5, str((i, j)), fontsize=11) # 텍스트만 표시

**산점도(Scatter Plot)**의 핵심 기능과 이를 확장한 **버블 차트(Bubble Chart)**의 개념
N = 30
x = np.random.rand(N) # 1미만 1은 안나옴
print(x)
y = np.random.rand(N)
print(y)
colors = np.random.rand(N)
area = (30 * np.random.rand(N)) ** 2
plt.scatter(x, y, s=area, c=colors, alpha=0.5)
plt.show()

상관관계

- 상관관계 0 (무상관/독립):
- 현재 코드의 결과물이다. x와 y가 완전히 랜덤하게 생성되었으므로 서로 아무런 영향을 주지 않는다.
- 그래프상에서 점들이 규칙 없이 듬성듬성 퍼져 있다.
- 해석: "x값만으로는 y값을 전혀 예측할 수 없다."
- 양의 상관관계 (Positive Correlation):
- x가 증가할 때 y도 대체로 증가하는 경향이 있다.
- 그래프는 왼쪽 아래에서 오른쪽 위로 향하는 대각선 형태를 띤다.
- 예: 키와 몸무게, 공부 시간과 성적.
- 음의 상관관계 (Negative Correlation):
- x가 증가할 때 y는 대체로 감소하는 경향이 있다.
- 그래프는 왼쪽 위에서 오른쪽 아래로 향하는 대각선 형태를 띤다.
- 예: 자동차의 속도와 연비(속도가 너무 빠르면 연비 감소), 알코올 섭취량과 판단력.
중첩 막대 그래프 - 막대그래프 하나가 가려짐
x = np.arange(3)
years = ['2010', '2011', '2012']
domestic = [6801, 7695, 8010]
foreign = [777, 1046, 1681]
# domestic 과 foreign 순서 바꾸면 forieing 이 사라져버림
plt.bar(x, domestic)
plt.bar(x, foreign)
plt.xticks(x, years
| 개념 | 설명 |
| Tick (눈금) | 그래프의 축에 값을 표시하는 지점. xticks는 x축의 눈금 위치와 이름을 결정한다. |
| Width (너비) | 막대의 두께. 그룹형 그래프에서는 이 너비를 계산하여 x 좌표를 이동시킨다. |
| Bottom | 누적 막대그래프에서 위에 쌓일 막대의 시작 높이를 결정하는 옵션이다. |
**오프셋(0.3)**을 더하고 **너비(width=0.25)**를 조절해서 막대가 겹치는 문제를 해결
x = np.arange(3)
years = ['2010', '2011', '2012']
domestic = [6801, 7695, 8010]
foreign = [777, 1046, 1681]
plt.bar(x, domestic, width=0.25)
plt.bar(x+0.3, foreign, width=0.25)
plt.xticks(x, years)
plt.show()

가로막대그래프
import numpy as np
import matplotlib.pyplot as plt
years = ['2010', '2011', '2012']
domestic = [6801, 7695, 8010]
foreign = [777, 1046, 1681]
y = np.arange(len(years))
height = 0.3 # 막대 두께
fig, ax = plt.subplots(figsize=(8, 5))
# 가로 막대 그리기 (위치 조절 포함)
ax.barh(y, domestic, height=height, label='Domestic', color='tab:blue')
ax.barh(y + 0.35, foreign, height=height, label='Foreign', color='tab:orange')
# 축 설정
ax.set_yticks(y + 0.175) # 두 막대의 중간에 연도가 오도록 조정
ax.set_yticklabels(years)
ax.set_xlabel('Number of Tourists')
ax.set_title('Tourist Statistics (2010-2012)')
# 시간 순서대로 위에서 아래로 배치
ax.invert_yaxis()
ax.legend()
plt.tight_layout()
plt.show()

파이차트
data = [5,4,6,11]
clist = ['cyan', 'gray', 'orange', 'red']
# 폭파할 수 있음
explode = [.06, .07, .08, .09]
plt.pie(data, autopct = '%.2f%%', colors=clist,
labels=clist, explode=explode
)
plt.show()

히트맵
data = np.random.random((10, 10))
# data = data.astype(np.unit8) # openCV 는 이렇게함
plt.imshow(data, cmap='hot', interpolation='nearest') # gray scale 출력하기 위해 reverse
# plt.imshow(data)
plt.colorbar()
plt.show()

히스토그램
- 빈 (Bins): 메모에서 언급한 '깡통' 또는 '바구니'다. 데이터의 최솟값부터 최댓값까지의 범위를 몇 개의 구간으로 나눌지 결정한다.
- bins=6이면 전체 범위를 동일한 간격으로 6등분한다.
- 구간이 너무 적으면 분포가 뭉뚱그려지고, 너무 많으면 노이즈가 심해져 흐름을 보기 어렵다.
- 도수 (Frequency): 각 바구니에 들어간 데이터의 개수다. $y$축이 바로 이 도수를 나타낸다.
heights = np.array([175, 165, 164, 164, 171, 165, 160, 169, 164, 159, 163, 167,
163, 172, 159, 160, 156, 162, 166, 162, 158, 167, 160, 161, 156, 172, 168, 165, 165,
177])
plt.hist(heights, bins=6) # 히스토그램 bins는 구간의 수
plt.xlabel("height")
plt.ylabel("frequency")
plt.show()
히스토그램에서 bins의 개수를 조절하는 것은 데이터의 해상도를 결정하는 것과 같다. bins를 6에서 12로 늘리면 데이터의 분포를 더 세밀하게 관찰할 수 있지만, 동시에 전체적인 흐름을 파악하기 어려워질 수도 있다.
heights = np.array([175, 165, 164, 164, 171, 165, 160, 169, 164, 159, 163, 167,
163, 172, 159, 160, 156, 162, 166, 162, 158, 167, 160, 161, 156, 172, 168, 165, 165,
177])
plt.hist(heights, bins=12) # 히스토그램, bins 의 갯수에 따라 그림이 달라보이는 현상. bins는 구간의 수
plt.xlabel("height")
plt.ylabel("frequency")
plt.show()

cumulative=True 옵션을 사용하는 순간 히스토그램은 단순한 빈도 측정을 넘어 **누적 분포 함수(CDF, Cumulative Distribution Function)**의 성질을 갖게 된다. 일반 히스토그램은 bins 설정에 따라 데이터가 왜곡되어 보일 위험이 있지만, 누적 히스토그램은 전체적인 흐름을 안정적으로 보여준다.
- 히스토그램 왜곡: bins의 경계값을 교묘하게 설정하면 특정 데이터가 강조되거나 사라져 보이게 할 수 있다.
- 누적의 안정성: 누적 히스토그램은 데이터가 쌓여가는 '기울기'를 보여준다. 기울기가 급하다면 해당 구간에 데이터가 밀집되어 있다는 뜻이고, 완만하다면 데이터가 적다는 뜻이다. 이는 구간을 어떻게 나누느냐보다 전체적인 데이터의 흐름을 파악하는 데 더 큰 가치를 둔다.
heights = np.array([175, 165, 164, 164, 171, 165, 160, 169, 164, 159, 163, 167,
163, 172, 159, 160, 156, 162, 166, 162, 158, 167, 160, 161, 156, 172, 168, 165, 165,
177])
plt.hist(heights, bins=12, label='cumulative=True', cumulative=True) # 히스토그램, bins 의 갯수에 따라 그림이 달라보이는 현상. bins는 구간의 수
plt.hist(heights, bins=12, label='cumulative=False', cumulative=False)
plt.xlabel("height")
plt.ylabel("frequency")
plt.show()

표준정규분포
이 그래프에서 $x$값이 3보다 크거나 -3보다 작은 구간에 위치한 데이터는 전체의 0.3% 미만이다. 데이터 분석 시 이런 값들은 보통 **이상치(Outlier)**로 간주하여 제거하거나 별도로 관리하는 기준이 된다.

import numpy as np
import matplotlib.pyplot as plt
f1 = np.random.randn(100000)
plt.hist(f1, bins=200, color='red', alpha=.7,\
label='avg 0 std 1')
plt.axis([-8, 8, -2, 2500])
plt.legend()
표준정규분포2
작성한 코드에서 두 분포는 표준편차가 동일하기 때문에 그래프의 **기형(Shape)**은 완벽히 같다. 단지 중심점만 0에서 3으로 이동했을 뿐이다.
데이터 분류와 중첩의 한계 (Error 영역)
- 교집합 영역 (Purple): 두 그래프가 겹치는 구간에서 추출된 데이터는 그것이 어디에서 왔는지 확신할 수 없다.
- 결정 경계 (Decision Boundary): 두 분포가 만나는 중간 지점(약 1.5)을 기준으로 삼아 데이터를 분류하더라도, 겹치는 영역만큼은 반드시 **오분류(Misclassification)**가 발생한다.
- 학습 데이터로서의 가치: 데이터가 겹치는 구간이 적을수록(두 평균의 차이가 표준편차에 비해 클수록) 모델은 데이터를 더 명확하게 구분할 수 있고 학습 성능도 올라간다.

# 평균 0, 표준편차 1
# 평균 3, 표준편차 1
f1 = np.random.normal(loc=0, scale=1, size=100000)
f2 = np.random.normal(loc=3, scale=1, size=100000)
plt.hist(f1, bins=200, color='red', alpha=.4, label='avg 0 std 1')
plt.hist(f2, bins=200, color='blue', alpha=.4, label='avg 3 std 1')
plt.axis([-8, 8, -2, 2500])
plt.legend()

표준정규분포3
1. 분산(Scale)이 분류에 미치는 영향
- 빨간색 (f_1): 표준편차가 1로 작아서 평균 0 근처에 아주 뾰족하게 모여 있다. 데이터의 정체성이 명확하다.
- 초록색 (f_2): 평균은 3이지만 표준편차가 3으로 크다. 이 때문에 평균에서 멀리 떨어진 값들이 많이 나타나고, 그래프가 낮고 넓게 퍼진다.
- 문제점: 초록색 데이터의 상당 부분이 빨간색 데이터의 영역($-2 \sim 2$)을 완전히 덮어버린다. 이 구간의 데이터는 모델 입장에서 어느 쪽인지 판단하기 매우 모호해진다.
2. 임계값(Threshold)과 쓰레기 데이터 처리
분류 모델은 보통 특정 임계값(Threshold)을 기준으로 결정을 내린다.
- 교집합의 딜레마: 메모한 것처럼 교집합 영역에 있는 데이터를 그대로 학습시키면 모델은 혼란에 빠진다. 이를 노이즈 또는 애매한 데이터로 취급할 수 있다.
- 데이터 정제 전략:
- Confidence 필터링: 모델이 예측한 확률이 높은(예: 90% 이상) 데이터만 사용하고, 애매한 중간 데이터는 버리는 방식이다.
- Hard Example Mining: 오히려 겹치는 영역의 '어려운 데이터'를 집중적으로 학습시켜 경계선을 정교하게 긋는 방법도 있다. 하지만 데이터 자체가 레이블링 오류이거나 구분이 불가능한 수준이라면 버리는 것이 성능 향상에 도움이 된다.
3. 통계적 해석
- 데이터 유효성: 분산이 너무 큰 데이터셋은 특성(Feature)으로서의 가치가 떨어진다. f_2처럼 넓게 퍼진 데이터는 x값이 무엇이냐에 따라 클래스를 예측하기가 매우 힘들기 때문이다.
- 차원의 저주와 연결: 변수가 많아질 때 이런 식으로 겹치는 구간이 많아지면 분류 정확도는 급격히 떨어진다.
f1 = np.random.normal(loc=0, scale=1, size=100000)
f2 = np.random.normal(loc=3, scale=3, size=100000)
plt.hist(f1, bins=200, color='red', alpha=.4, label='avg 0 std 1')
plt.hist(f2, bins=200, color='green', alpha=.4, label='avg 3 std 3')
plt.axis([-8, 8, -2, 2500])
plt.legend()

상자수염
하나의 상자에는 다섯 가지 주요 통계 지표(Five-number summary)가 담겨 있다.
- 중앙값 (Q2, Median): 상자 내부의 가로선. 데이터를 크기순으로 나열했을 때 정중앙에 위치한 값이다.
- 제1사분위수 (Q1) / 제3사분위수 (Q3): 상자의 밑면과 윗면. 각각 하위 25%와 75% 지점을 나타낸다.
- IQR (Interquartile Range): 상자의 높이 (Q3 - Q1). 데이터의 중간 50%가 모여 있는 구간이다.
- 수염 (Whisker): 상자 위아래로 뻗은 선.
- 이상치 (Outlier): 수염 범위를 벗어난 점들. 데이터 수집 오류이거나 특별한 케이스다.
plt.style.use('dark_background')
np.random.seed(85)
data1 = np.random.normal(100, 10, 200) # 평균 100, 분산 10
data2 = np.random.normal(100, 40, 200) # 평균 100, 분산 40
data3 = np.random.normal(80, 40, 200) # 평균 80, 분산 40
data4 = np.random.normal(80, 60, 200) # 평균 80, 분산 60
plt.boxplot([data1, data2, data3, data4])
plt.title('Box Plot of Random Data')
plt.xlabel('Group')
plt.ylabel('Value')
plt.show()

| 데이터 그룹 | 특성 (μ,σ) | 상자 모양 특징 |
| Data 1 | (100, 10) | 분산이 작아 상자의 높이(IQR)가 매우 낮고 데이터가 조밀함. |
| Data 2 | (100, 40) | 평균은 같으나 분산이 4배 커서 상자가 길고 수염도 길게 뻗음. |
| Data 3 | (80, 40) | 평균이 80으로 낮아져 상자 자체가 아래쪽($y$축 기준)에 배치됨. |
| Data 4 | (80, 60) | 분산이 가장 커서 데이터가 매우 넓게 퍼져 있으며 이상치가 발생할 확률이 가장 높음. |
그래프와 그리드 그리기 - 그래프에 격자(Grid)를 그리면 데이터의 위치를 눈으로 쫓기 훨씬 수월해진다.
X = np.linspace(0, 2*np.pi, 200)
Y = np.sin(X)
plt.figure(figsize=(4.2, 3.6))
plt.plot(X, Y)
# plt.grid()
plt.grid(color='r', linestyle='dotted', linewidth=2)

'머신러닝' 카테고리의 다른 글
| PANDAS (0) | 2026.01.08 |
|---|---|
| SEABORN (0) | 2026.01.07 |
| 넘파이(NumPy) 2 (0) | 2026.01.07 |
| 넘파이(NumPy) 1 (0) | 2026.01.06 |
| 파이참 설치 (0) | 2026.01.05 |