AI 부트캠프/챕터1(9.30~10.11)

TIL 7 인공지능을 위한 파이썬 라이브러리 (4 - 1 ~ 5 - 4)

musukie 2024. 10. 8. 14:36

   데이터 정렬은 데이터 분석의 기본

sort_values()를 사용해 값(Value)을 기준으로 데이터를 정렬할 수 있는데, 내림차순으로 정렬하려면 ascending=False를 지정해야 한다. 또 여러 열을 기준으로 정렬할 수 있는데, 우선 순위에 따라 첫 번째 열부터 정렬된다.

# '나이' 기준으로 내림차순 정렬
sorted_df_desc = df.sort_values(by='나이', ascending=False)

# '직업'을 기준으로, 같은 직업 내에서 '나이' 오름차순 정렬
sorted_df_multi = df.sort_values(by=['직업', '나이'])

 

sort_index()를 사용해 인덱스를 기준으로 정렬할 수 있는데, 마찬가지로 내림차순 정렬하려면 ascending=False를 지정해야 한다.

sorted_index_df_desc = df.sort_index(ascending=False)

 

ascending도 각각 지정해줄 수 있는데, True와 False로 오름차순과 내림차순을 나타낸다.

   데이터 병합

merge()를 사용해서 데이터프레임을 병합할 수 있다. 이는 SQL의 JOIN과 유사하게 두 데이터프레임을 공통 열을 기준으로 병합한다. merge()의 방식으로는 공통된 데이터만 병합하는 inner (기본값), 공통되지 않은 데이터도 포함하는 outer, 왼쪽 데이터프레임을 기준으로 하는 left, 오른쪽을 기준으로 하는 right가 있다.

# outer join을 사용한 병합
merged_df_outer = pd.merge(df1, df2, on='이름', how='outer')

 

concat()을 사용해서 행(row) 또는 열 단위(column)로 데이터프레임을 연결할 수 있다. 열 단위로 연결할 때는 axis=1을 지정해야 한다.

# 행 단위로 데이터프레임 연결
concat_df = pd.concat([df1, df2], axis=0)

# 열 단위로 데이터프레임 연결
concat_df_axis1 = pd.concat([df1, df2], axis=1)

 

join()인덱스를 기준으로 데이터프레임을 병합할 때 사용한다.

joined_df = df1.set_index('이름').join(df3)

   데이터 그룹화 및 집계

데이터 그룹화는 데이터를 특정한 기준에 따라 그룹으로 나누고, 집계는 각 그룹에 대해 요약 통계를 계산하는 과정이다.

Pandas에서는 goupby() 함수로 데이터를 특정 열을 기준으로 그룹화하며, 이에 대해 집계함수 mean, sum, count 등을 사용할 수 있다. 여러 개의 집계 함수를 동시에 사용할 수도 있는데, 그 결과는 표 형태로 얻을 수 있다.

 

   피벗 테이블

피벗테이블은 데이터를 요약해주는 도구로, 엑셀의 피벗테이블과 유사하며, 특정 기준에 따라 데이터를 재구조화할 수 있다. pivot_table()로 그 기능을 사용할 수 있다. groupby() 함수와 마찬가지로 여러 집계함수를 동시에 사용할 수 있다. 또

피벗테이블을 만들 때  fill_value사용하면 NaN을 대신할 값을 지정할 수 있다.

 fill_value : 피벗 테이블을 만들 때 별다른 옵션없이 진행하면 결측치 부분은 NaN으로 채워짐. 이를 사용해 NaN을 대신할 값을 지정해주면 됨

이 경우 fill_value=0을 사용해 NaN값을 모두 0으로 바꿔준 것이다.

 

 margins=True 옵션을 사용하면, 각 행과 열의 합계가 추가된 피벗테이블을 생성할 수 있다. 이 옵션을 사용하면 aggfunc에 여러 함수를 지정하고 해당 옵션을 사용해서 전체 데이터에 대해 요약을 제공할 수 있다.


   결측치 탐지

데이터 분석에서 결측치는 흔히 발생하며, 이를 올바르게 처리하는 게 중요하다. isna() isnull() 함수는 같은 기능을 한다. 이들은 데이터프레임의 각 요소의 결측치 여부를 확인한다.

 

sum()을 사용해 결측치 여부를 확인한다. 그 이유는 결측치는 True라서 값이 1이고, 정상값은 False라서 값이 0이기 때문에 합을 측정하면 결측치의 개수만큼 값이 나오게 되는 것이다.

   결측치 처리 방법

결측치가 포함된 행을 삭제할 때는 dropna()함수를 사용하는데, 열을 삭제할 때는 axis=1을 지정한다. 결측치를 삭제하는 것이 항상 정답은 아니기 때문에, 상황에 맞게 결측치를 처리해야 한다.

 

fillna() 함수로 결측치를 특정한 값으로 대체할 수 있다. 아래의 예시는 특정 열의 결측치만 특정 값으로 대체하는 예시다.

# '나이' 열의 결측치를 평균값으로 대체
df['나이'].fillna(df['나이'].mean())

 

결측치를 주변 값들을 기반으로 보간할 때는 interpolate() 함수를 사용한다. 이는 특히 시간 데이터를 다룰 때 유용하다. 그러나 이 함수는, 행의 순서에 따라 어느 정도 값이 정렬돼있고, 이 값에 따라 결측치를 추측 가능할 때 사용해야 한다. 그렇지 않으면 전혀 의미없는 값이 나올 수 있다.

 

결측치를 모두 일관된 방식으로 처리하려고 하면 안 된다. 특정 조건을 기반으로 결측치를 처리하면 좀 더 꼼꼼하게 처리할 수 있다.

# '직업'이 '학생'인 경우 '나이'를 20으로 채우기
df.loc[(df['직업'] == '학생') & (df['나이'].isna()), '나이'] = 20
# Series([], Name: 나이, dtype: float64)	# 결측치가 없어서 값이 나오지 x.
# 그러나 결측치가 있다면 그 값을 20으로 채워줄 것임을 의미.

df.loc[(df['직업'] == '학생') & (~df['나이'].isna()), '나이'] = 20	# 결측치가 아닌 값을 보기 위해 ~을 넣어서 값을 반전시킴.
# 0    25.0
  2    30.0
  Name: 나이, dtype: float64
  # '나이'를 기준으로 하고 있고(Name: 나이), '직업'은 '학생'인 경우, & '나이'가 결측값이 아닌 경우를 보는 것.

 

 apply() 함수를 사용하면 논리 규칙을 작성해놓고, 이 규칙에 따라서 결측치를 처리할 수 있다.

 

결측치의 문법보다는 결측치를 어떻게 처리할 지가 더 중요하다.


   이상치 탐지

이상치(Outlier)데이터의 일반적인 패턴에서 벗어난 값을 의미한다. 이상치를 탐지하는 방법에는 데이터의 기본 통계량을 확인하고 이상치를 의심할 수 있는 describe() 함수, 박스플롯(Box Plot)과 히스토그램 등을 사용해 데이터 분포를 시각화하는 방법, IQR(Interquartile Range)을 사용하는 방법이 있다. 각각의 예시는 아래와 같다.

# 기술 통계량 확인
df['나이'].describe()
# 박스플롯으로 이상치 시각화
plt.boxplot(df['나이'])
plt.title('나이의 박스플롯')
plt.show()
# IQR 계산
Q1 = df['나이'].quantile(0.25)
Q3 = df['나이'].quantile(0.75)
IQR = Q3 - Q1

# IQR을 이용한 이상치 탐지
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

outliers = df[(df['나이'] < lower_bound) | (df['나이'] > upper_bound)]
print(outliers)

 

우리는 어떤 이상치 기법도 절대적이지 않다는 것을 알아야 한다.

  이상치 처리

이상치 처리는 결측치 처리와 개념적으로는 거의 동일하다. 제거하거나, 특정 값으로 대체하거나, 그대로 유지할 수 있다. 데이터의 특성과 분석 목적에 따라 적절한 방법을 선택하여 처리해야 한다. 또, 이상치 처리가 제대로 되었는지 확인하려면, 이상치를 처리한 후에 다시 한 번 이상치 탐지를 진행해야 한다.

 

결측치를 어떻게 처리하느냐는 데이터의 통계적 특성에 영향을 주며, 그 결과는 이상치 처리에도 영향을 준다. 그래서 우리는 데이터 전처리를 할 때 각각의 단계에 대한 관계도 인지하고 있어야 한다. 즉, 데이터 전처리 방법들은 서로 간의 결과에 영향을 미칠 수 있으므로 주의해야 한다.


  정규화(Normalization)

데이터의 범위를 0과 1 사이로 변환하는 과정이다. Min-Max 정규화는 가장 일반적인 정규화 방법으로, 각 데이터의 최솟값을 0, 최댓값을 1로 변환한다.

  표준화(Standardization)

데이터를 평균이 0, 표준편차가 1이 되도록 변환하는 과정이다. Z-점수 표준화는 데이터에서 평균을 빼고 표준편차로 나누어, 모든 데이터가 표준 정규분포(평균 0, 표준편차 1)를 따르게 만든다.

  비선형 변환(Non-linear Transformation)

데이터의 비정상적인 분포를 정규 분포에 가깝게 만들기 위해 사용된다. 대표적인 방법으로 로그 변환, 제곱근 변환, 박스-콕스 변환 등이 있다. 로그 변환 후 데이터의 분포가 평탄해지며, 제곱근 변환 후 분포가 줄어들고, 박스-콕스 변환 후 데이터의 분포가 정규분포에 가까워지는 효과를 얻을 수 있다.

 

현재 인공지능에서 정규화와 표준화는 사실상 거의 일반적으로 코드에 항상 포함돼있는 경우가 많다고 한다. 또  전문가도, 특정 한 데이터만 연구한 사람도 데이터 전처리에서 실수하는 경우가 많기 때문에, 데이터 전처리는 아주 중요하다.


  인코딩(Encoding)

범주형 데이터(Categorical Data)를 수치형 데이터로 변환하는 과정이다. 많은 머신러닝 모델은 수치형 데이터만 처리할 수 있기 때문에, 범주형 데이터를 인코딩하는 것이 필수적이다. 여기에는 레이블 인코딩(Label Encoding), 원-핫 인코딩(One-Hot Encoding), 차원 축소 인코딩(Count or Frequency Encoding), 순서형 인코딩(Ordinal Encoding), 임베딩(Embedding)이 있다.

 

 범주형 데이터를 순서가 있는 숫자로 변환하는 레이블 인코딩을 사용할 때는 주의할 점이 있다. 이는 범주형 데이터에 순서가 있을 때 적합한데, 순서가 없는 데이터에 사용하면, 모델이 이 값을 크기로 인식해 잘못된 결과를 초래할 수 있다.

# 레이블 인코딩
label_encoder = LabelEncoder()
df['과일_인코딩'] = label_encoder.fit_transform(df['과일'])
print(df)

 

각 범주를 이진 벡터로 변환하는 원-핫 인코딩은 순서가 없을 때 사용하기 좋다는 장점이 있다.

# 원-핫 인코딩
df_one_hot = pd.get_dummies(df['과일'], prefix='과일')
print(df_one_hot)

 

각 범주를 데이터셋 내에서의 출현 빈도로 인코딩하는 차원 축소 인코딩은 고유성을 잃을 수 있다는 점에 주의해야 한다.

# 빈도 기반 인코딩
df['과일_빈도'] = df['과일'].map(df['과일'].value_counts())
print(df)

 

순서가 있는 범주형 데이터를 그 순서에 따라 숫자로 변환하는 순서형 인코딩은 순서가 중요한 경우에 적합한데, 직접 매핑을 통해 순서를 지정할 수 있다.

# 순서형 인코딩
order = {'낮음': 1, '중간': 2, '높음': 3}
df['등급_인코딩'] = df['등급'].map(order)
print(df)

 

범주형 데이터를 벡터 공간에 매핑하여 변환하는 임베딩은 고차원 범주형 데이터에 유용하다. 텍스트같은 것을 처리할 상황에 꼭 처했다면 임베딩을 활용하면 된다. 아직은 다루기 어려운 내용이라서 코드는 따로 배우지 않았다.


   강의 외부에서 추가로 알게된 내용

  • 표준편차 (Standard Deviation)

- 정의 : 데이터들이 평균에서 얼마나 떨어져 있는 지를 나타내는 값.

- 특징 1) 값들이 평균에 가까이 있으면 표준편차가 작다.

          2) 값들이 평균에서 멀리 떨어져 있으면 표준편차가 크다.

- 계산 방법 1) 평균을 구하고  2) 각 값에서 평균을 뺀 후 그 차이를 제곱하여  3) 제곱한 값을 모두 더한다.

                   4) 그 합을 데이터의 개수로 나누고  5) 그 값의 제곱근을 구한다.

- 예시 : 데이터(60, 70, 80, 90)의 표준편차 ≈ 11.18

  • 사분위값 (Quartiles)

- 정의 : 데이터를 크기 순으로 나열한 후, 4등분한 지점들의 값.

- 특징 1) 데이터를 4개의 구간으로 나눠서, 각 구간에서 중요한 지점의 값을 보여준다.

          2) 데이터 분포를 파악하는 데 유용하다.

- 종류 1) 1사분위값(Q1) : 하위 25%에 해당하는 값.

          2) 2사분위값(Q2) : 중간 50% 지점에 해당하는 값.

          3) 3사분위값(Q3) : 상위 25%를 남긴 75% 지점에 해당하는 값.

- 예시 : 데이터(130, 140, 150, ..., 220)의 사분위값

            Q1 ≈ 145cm, Q2 = 175cm, Q3 ≈ 205cm

 

* ≈ : '약' 또는 '대략'을 의미한다.