You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4241 lines
126 KiB
4241 lines
126 KiB
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "rQ8UhzFpgRra"
|
|
},
|
|
"source": [
|
|
"# 데이터 준비\n",
|
|
"\n",
|
|
"[원본 노트북 출처: *Data Science: Introduction to Machine Learning for Data Science Python and Machine Learning Studio by Lee Stott*](https://github.com/leestott/intro-Datascience/blob/master/Course%20Materials/4-Cleaning_and_Manipulating-Reference.ipynb)\n",
|
|
"\n",
|
|
"## `DataFrame` 정보 탐색\n",
|
|
"\n",
|
|
"> **학습 목표:** 이 절의 끝까지 학습하면 pandas의 DataFrame에 저장된 데이터에 대한 일반적인 정보를 찾는 데 익숙해질 것입니다.\n",
|
|
"\n",
|
|
"데이터를 pandas에 로드하면 대부분의 경우 `DataFrame` 형태로 저장됩니다. 하지만 `DataFrame`에 있는 데이터셋이 60,000개의 행과 400개의 열로 구성되어 있다면, 어디서부터 작업을 시작해야 할지 막막할 수 있습니다. 다행히도 pandas는 `DataFrame`의 전체적인 정보를 빠르게 확인할 수 있는 몇 가지 편리한 도구를 제공합니다. 이 도구들은 데이터의 처음 몇 행과 마지막 몇 행을 확인하는 기능도 포함하고 있습니다.\n",
|
|
"\n",
|
|
"이 기능을 탐색하기 위해 Python의 scikit-learn 라이브러리를 가져오고, 모든 데이터 과학자가 수백 번은 봤을 법한 상징적인 데이터셋을 사용할 것입니다. 이 데이터셋은 영국 생물학자 로널드 피셔(Ronald Fisher)가 1936년 논문 \"The use of multiple measurements in taxonomic problems\"에서 사용한 *Iris* 데이터셋입니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"id": "hB1RofhdgRrp",
|
|
"trusted": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import pandas as pd\n",
|
|
"from sklearn.datasets import load_iris\n",
|
|
"\n",
|
|
"iris = load_iris()\n",
|
|
"iris_df = pd.DataFrame(data=iris['data'], columns=iris['feature_names'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "AGA0A_Y8hMdz"
|
|
},
|
|
"source": [
|
|
"### `DataFrame.shape`\n",
|
|
"우리는 Iris 데이터셋을 변수 `iris_df`에 로드했습니다. 데이터를 분석하기 전에, 우리가 가진 데이터 포인트의 수와 데이터셋의 전체 크기를 아는 것이 유용할 것입니다. 우리가 다루고 있는 데이터의 양을 확인하는 것은 중요합니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "LOe5jQohhulf",
|
|
"outputId": "fb0577ac-3b4a-4623-cb41-20e1b264b3e9"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"(150, 4)"
|
|
]
|
|
},
|
|
"execution_count": 2,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"iris_df.shape"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "smE7AGzOhxk2"
|
|
},
|
|
"source": [
|
|
"우리는 150개의 행과 4개의 열로 구성된 데이터를 다루고 있습니다. 각 행은 하나의 데이터 포인트를 나타내며, 각 열은 데이터 프레임과 관련된 하나의 특징을 나타냅니다. 즉, 기본적으로 150개의 데이터 포인트가 각각 4개의 특징을 포함하고 있는 것입니다.\n",
|
|
"\n",
|
|
"`shape`는 여기서 데이터 프레임의 속성이며 함수가 아니기 때문에 괄호로 끝나지 않습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "d3AZKs0PinGP"
|
|
},
|
|
"source": [
|
|
"### `DataFrame.columns`\n",
|
|
"이제 데이터의 4개 열로 넘어가 보겠습니다. 각각의 열은 정확히 무엇을 나타낼까요? `columns` 속성은 데이터프레임의 열 이름을 알려줍니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "YPGh_ziji-CY",
|
|
"outputId": "74e7a43a-77cc-4c80-da56-7f50767c37a0"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"Index(['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)',\n",
|
|
" 'petal width (cm)'],\n",
|
|
" dtype='object')"
|
|
]
|
|
},
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"iris_df.columns"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "TsobcU_VjCC_"
|
|
},
|
|
"source": [
|
|
"우리가 볼 수 있듯이, 네(4) 개의 열이 있습니다. `columns` 속성은 열의 이름을 알려주며 기본적으로 그 외에는 아무것도 알려주지 않습니다. 이 속성은 데이터셋이 포함하는 특징을 식별하고자 할 때 중요성을 갖습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "2UTlvkjmgRrs"
|
|
},
|
|
"source": [
|
|
"### `DataFrame.info`\n",
|
|
"`shape` 속성이 제공하는 데이터 양과 `columns` 속성이 제공하는 특징 또는 열 이름은 데이터셋에 대해 일부 정보를 알려줍니다. 이제 데이터셋을 더 깊이 탐구하고 싶을 것입니다. `DataFrame.info()` 함수는 이에 매우 유용합니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "dHHRyG0_gRrt",
|
|
"outputId": "d8fb0c40-4f18-4e19-da48-c8db77d1d3a5",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"<class 'pandas.core.frame.DataFrame'>\n",
|
|
"RangeIndex: 150 entries, 0 to 149\n",
|
|
"Data columns (total 4 columns):\n",
|
|
" # Column Non-Null Count Dtype \n",
|
|
"--- ------ -------------- ----- \n",
|
|
" 0 sepal length (cm) 150 non-null float64\n",
|
|
" 1 sepal width (cm) 150 non-null float64\n",
|
|
" 2 petal length (cm) 150 non-null float64\n",
|
|
" 3 petal width (cm) 150 non-null float64\n",
|
|
"dtypes: float64(4)\n",
|
|
"memory usage: 4.8 KB\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"iris_df.info()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "1XgVMpvigRru"
|
|
},
|
|
"source": [
|
|
"여기서 몇 가지 관찰을 할 수 있습니다:\n",
|
|
"1. 각 열의 데이터 유형: 이 데이터셋에서는 모든 데이터가 64비트 부동소수점 숫자로 저장되어 있습니다.\n",
|
|
"2. Non-Null 값의 개수: null 값을 처리하는 것은 데이터 준비에서 중요한 단계입니다. 이는 나중에 노트북에서 처리될 예정입니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "IYlyxbpWFEF4"
|
|
},
|
|
"source": [
|
|
"### DataFrame.describe()\n",
|
|
"데이터셋에 많은 수치 데이터가 있다고 가정해봅시다. 평균, 중앙값, 사분위수 등과 같은 단변량 통계 계산은 각 열별로 개별적으로 수행할 수 있습니다. `DataFrame.describe()` 함수는 데이터셋의 수치 열에 대한 통계 요약을 제공합니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 297
|
|
},
|
|
"id": "tWV-CMstFIRA",
|
|
"outputId": "4fc49941-bc13-4b0c-a412-cb39e7d3f289"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>sepal length (cm)</th>\n",
|
|
" <th>sepal width (cm)</th>\n",
|
|
" <th>petal length (cm)</th>\n",
|
|
" <th>petal width (cm)</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>count</th>\n",
|
|
" <td>150.000000</td>\n",
|
|
" <td>150.000000</td>\n",
|
|
" <td>150.000000</td>\n",
|
|
" <td>150.000000</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>mean</th>\n",
|
|
" <td>5.843333</td>\n",
|
|
" <td>3.057333</td>\n",
|
|
" <td>3.758000</td>\n",
|
|
" <td>1.199333</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>std</th>\n",
|
|
" <td>0.828066</td>\n",
|
|
" <td>0.435866</td>\n",
|
|
" <td>1.765298</td>\n",
|
|
" <td>0.762238</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>min</th>\n",
|
|
" <td>4.300000</td>\n",
|
|
" <td>2.000000</td>\n",
|
|
" <td>1.000000</td>\n",
|
|
" <td>0.100000</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>25%</th>\n",
|
|
" <td>5.100000</td>\n",
|
|
" <td>2.800000</td>\n",
|
|
" <td>1.600000</td>\n",
|
|
" <td>0.300000</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>50%</th>\n",
|
|
" <td>5.800000</td>\n",
|
|
" <td>3.000000</td>\n",
|
|
" <td>4.350000</td>\n",
|
|
" <td>1.300000</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>75%</th>\n",
|
|
" <td>6.400000</td>\n",
|
|
" <td>3.300000</td>\n",
|
|
" <td>5.100000</td>\n",
|
|
" <td>1.800000</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>max</th>\n",
|
|
" <td>7.900000</td>\n",
|
|
" <td>4.400000</td>\n",
|
|
" <td>6.900000</td>\n",
|
|
" <td>2.500000</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)\n",
|
|
"count 150.000000 150.000000 150.000000 150.000000\n",
|
|
"mean 5.843333 3.057333 3.758000 1.199333\n",
|
|
"std 0.828066 0.435866 1.765298 0.762238\n",
|
|
"min 4.300000 2.000000 1.000000 0.100000\n",
|
|
"25% 5.100000 2.800000 1.600000 0.300000\n",
|
|
"50% 5.800000 3.000000 4.350000 1.300000\n",
|
|
"75% 6.400000 3.300000 5.100000 1.800000\n",
|
|
"max 7.900000 4.400000 6.900000 2.500000"
|
|
]
|
|
},
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"iris_df.describe()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "zjjtW5hPGMuM"
|
|
},
|
|
"source": [
|
|
"위의 출력은 각 열의 데이터 포인트 총 수, 평균, 표준 편차, 최소값, 하위 사분위수(25%), 중앙값(50%), 상위 사분위수(75%) 및 최대값을 보여줍니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "-lviAu99gRrv"
|
|
},
|
|
"source": [
|
|
"### `DataFrame.head`\n",
|
|
"위의 모든 함수와 속성을 통해 데이터셋에 대한 전반적인 개요를 얻었습니다. 데이터 포인트가 몇 개인지, 특징이 몇 개인지, 각 특징의 데이터 타입과 각 특징의 non-null 값 개수를 알게 되었습니다.\n",
|
|
"\n",
|
|
"이제 실제 데이터를 살펴볼 시간입니다. `DataFrame`의 첫 몇 행(첫 몇 데이터 포인트)이 어떻게 생겼는지 확인해봅시다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 204
|
|
},
|
|
"id": "DZMJZh0OgRrw",
|
|
"outputId": "d9393ee5-c106-4797-f815-218f17160e00",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>sepal length (cm)</th>\n",
|
|
" <th>sepal width (cm)</th>\n",
|
|
" <th>petal length (cm)</th>\n",
|
|
" <th>petal width (cm)</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>5.1</td>\n",
|
|
" <td>3.5</td>\n",
|
|
" <td>1.4</td>\n",
|
|
" <td>0.2</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>4.9</td>\n",
|
|
" <td>3.0</td>\n",
|
|
" <td>1.4</td>\n",
|
|
" <td>0.2</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>4.7</td>\n",
|
|
" <td>3.2</td>\n",
|
|
" <td>1.3</td>\n",
|
|
" <td>0.2</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>4.6</td>\n",
|
|
" <td>3.1</td>\n",
|
|
" <td>1.5</td>\n",
|
|
" <td>0.2</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>5.0</td>\n",
|
|
" <td>3.6</td>\n",
|
|
" <td>1.4</td>\n",
|
|
" <td>0.2</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)\n",
|
|
"0 5.1 3.5 1.4 0.2\n",
|
|
"1 4.9 3.0 1.4 0.2\n",
|
|
"2 4.7 3.2 1.3 0.2\n",
|
|
"3 4.6 3.1 1.5 0.2\n",
|
|
"4 5.0 3.6 1.4 0.2"
|
|
]
|
|
},
|
|
"execution_count": 6,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"iris_df.head()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "EBHEimZuEFQK"
|
|
},
|
|
"source": [
|
|
"여기 출력에서 우리는 데이터셋의 다섯(5) 개 항목을 볼 수 있습니다. 왼쪽의 인덱스를 보면, 이것들이 첫 다섯 행이라는 것을 알 수 있습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "oj7GkrTdgRry"
|
|
},
|
|
"source": [
|
|
"### 연습 문제:\n",
|
|
"\n",
|
|
"위의 예제에서 기본적으로 `DataFrame.head`는 `DataFrame`의 처음 다섯 행을 반환한다는 것이 분명합니다. 아래 코드 셀에서 다섯 행보다 더 많은 행을 표시하는 방법을 찾아낼 수 있나요?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"id": "EKRmRFFegRrz",
|
|
"trusted": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Hint: Consult the documentation by using iris_df.head?"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "BJ_cpZqNgRr1"
|
|
},
|
|
"source": [
|
|
"### `DataFrame.tail`\n",
|
|
"데이터를 보는 또 다른 방법은 시작이 아닌 끝에서부터 보는 것입니다. `DataFrame.head`의 반대는 `DataFrame.tail`로, 이는 `DataFrame`의 마지막 다섯 행을 반환합니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 0
|
|
},
|
|
"id": "heanjfGWgRr2",
|
|
"outputId": "6ae09a21-fe09-4110-b0d7-1a1fbf34d7f3",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>sepal length (cm)</th>\n",
|
|
" <th>sepal width (cm)</th>\n",
|
|
" <th>petal length (cm)</th>\n",
|
|
" <th>petal width (cm)</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>145</th>\n",
|
|
" <td>6.7</td>\n",
|
|
" <td>3.0</td>\n",
|
|
" <td>5.2</td>\n",
|
|
" <td>2.3</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>146</th>\n",
|
|
" <td>6.3</td>\n",
|
|
" <td>2.5</td>\n",
|
|
" <td>5.0</td>\n",
|
|
" <td>1.9</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>147</th>\n",
|
|
" <td>6.5</td>\n",
|
|
" <td>3.0</td>\n",
|
|
" <td>5.2</td>\n",
|
|
" <td>2.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>148</th>\n",
|
|
" <td>6.2</td>\n",
|
|
" <td>3.4</td>\n",
|
|
" <td>5.4</td>\n",
|
|
" <td>2.3</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>149</th>\n",
|
|
" <td>5.9</td>\n",
|
|
" <td>3.0</td>\n",
|
|
" <td>5.1</td>\n",
|
|
" <td>1.8</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)\n",
|
|
"145 6.7 3.0 5.2 2.3\n",
|
|
"146 6.3 2.5 5.0 1.9\n",
|
|
"147 6.5 3.0 5.2 2.0\n",
|
|
"148 6.2 3.4 5.4 2.3\n",
|
|
"149 5.9 3.0 5.1 1.8"
|
|
]
|
|
},
|
|
"execution_count": 8,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"iris_df.tail()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "31kBWfyLgRr3"
|
|
},
|
|
"source": [
|
|
"실제로, `DataFrame`의 처음 몇 행이나 마지막 몇 행을 쉽게 확인할 수 있는 기능은 특히 정렬된 데이터셋에서 이상값을 찾을 때 유용합니다.\n",
|
|
"\n",
|
|
"위에서 코드 예제를 통해 보여준 모든 함수와 속성은 데이터를 이해하고 파악하는 데 도움을 줍니다.\n",
|
|
"\n",
|
|
"> **핵심 요점:** `DataFrame`의 정보에 대한 메타데이터나 처음과 마지막 몇 개의 값을 보는 것만으로도, 다루고 있는 데이터의 크기, 형태, 그리고 내용을 즉각적으로 파악할 수 있습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "TvurZyLSDxq_"
|
|
},
|
|
"source": [
|
|
"### 누락된 데이터\n",
|
|
"누락된 데이터에 대해 알아봅시다. 누락된 데이터는 일부 열에 값이 저장되지 않은 경우 발생합니다.\n",
|
|
"\n",
|
|
"예를 들어, 어떤 사람이 자신의 체중에 대해 민감하여 설문조사에서 체중 항목을 작성하지 않는다고 가정해봅시다. 그러면 해당 사람의 체중 값은 누락되게 됩니다.\n",
|
|
"\n",
|
|
"대부분의 경우, 실제 데이터셋에서는 누락된 값이 발생합니다.\n",
|
|
"\n",
|
|
"**Pandas가 누락된 데이터를 처리하는 방법**\n",
|
|
"\n",
|
|
"Pandas는 누락된 값을 두 가지 방식으로 처리합니다. 첫 번째는 이전 섹션에서 본 적이 있는 `NaN`(Not a Number)입니다. 이는 실제로 IEEE 부동소수점 사양의 일부로, 누락된 부동소수점 값을 나타내는 데만 사용되는 특별한 값입니다.\n",
|
|
"\n",
|
|
"부동소수점 외의 누락된 값에 대해서는 pandas가 Python의 `None` 객체를 사용합니다. 두 가지 다른 종류의 값이 본질적으로 동일한 의미를 전달하는 것처럼 보일 수 있지만, 이러한 설계 선택에는 타당한 프로그래밍적 이유가 있으며, 실제로 이러한 접근 방식은 대부분의 경우에 대해 pandas가 적절한 절충안을 제공할 수 있도록 합니다. 그럼에도 불구하고, `None`과 `NaN` 모두 사용 방법과 관련하여 주의해야 할 제한 사항이 있다는 점을 기억해야 합니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "lOHqUlZFgRr5"
|
|
},
|
|
"source": [
|
|
"### `None`: 비-부동소수점 결측 데이터\n",
|
|
"`None`은 Python에서 비롯되었기 때문에 데이터 유형이 `'object'`가 아닌 NumPy 및 pandas 배열에서는 사용할 수 없습니다. NumPy 배열(및 pandas의 데이터 구조)은 한 가지 유형의 데이터만 포함할 수 있습니다. 이는 대규모 데이터 및 계산 작업에서 엄청난 성능을 제공하지만, 동시에 유연성을 제한하기도 합니다. 이러한 배열은 \"최소 공통 분모\"로 업캐스트해야 하며, 이는 배열 내 모든 것을 포함할 수 있는 데이터 유형을 의미합니다. 배열에 `None`이 포함되어 있다면, 이는 Python 객체를 사용하고 있다는 뜻입니다.\n",
|
|
"\n",
|
|
"이를 실제로 확인하려면 다음 예제 배열을 살펴보세요 (`dtype`를 주목하세요):\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "QIoNdY4ngRr7",
|
|
"outputId": "92779f18-62f4-4a03-eca2-e9a101604336",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"array([2, None, 6, 8], dtype=object)"
|
|
]
|
|
},
|
|
"execution_count": 9,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"import numpy as np\n",
|
|
"\n",
|
|
"example1 = np.array([2, None, 6, 8])\n",
|
|
"example1"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "pdlgPNbhgRr7"
|
|
},
|
|
"source": [
|
|
"업캐스트 데이터 타입의 현실은 두 가지 부작용을 동반합니다. 첫째, 연산이 컴파일된 NumPy 코드가 아닌 해석된 Python 코드 수준에서 수행됩니다. 기본적으로 이는 `None`이 포함된 `Series`나 `DataFrame`과 관련된 모든 연산이 더 느려진다는 것을 의미합니다. 이러한 성능 저하를 눈치채지 못할 수도 있지만, 대규모 데이터셋에서는 문제가 될 수 있습니다.\n",
|
|
"\n",
|
|
"두 번째 부작용은 첫 번째에서 비롯됩니다. `None`이 본질적으로 `Series`나 `DataFrame`을 일반 Python의 세계로 끌어들이기 때문에, `sum()`이나 `min()` 같은 NumPy/pandas 집계 함수를 `None` 값을 포함한 배열에 사용하면 일반적으로 오류가 발생합니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 292
|
|
},
|
|
"id": "gWbx-KB9gRr8",
|
|
"outputId": "ecba710a-22ec-41d5-a39c-11f67e645b50",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"ename": "TypeError",
|
|
"evalue": "ignored",
|
|
"output_type": "error",
|
|
"traceback": [
|
|
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
|
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
|
|
"\u001b[0;32m<ipython-input-10-ce9901ad18bd>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mexample1\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
|
|
"\u001b[0;32m/usr/local/lib/python3.7/dist-packages/numpy/core/_methods.py\u001b[0m in \u001b[0;36m_sum\u001b[0;34m(a, axis, dtype, out, keepdims, initial, where)\u001b[0m\n\u001b[1;32m 45\u001b[0m def _sum(a, axis=None, dtype=None, out=None, keepdims=False,\n\u001b[1;32m 46\u001b[0m initial=_NoValue, where=True):\n\u001b[0;32m---> 47\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mumr_sum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkeepdims\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minitial\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwhere\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 48\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m def _prod(a, axis=None, dtype=None, out=None, keepdims=False,\n",
|
|
"\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'NoneType'"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"example1.sum()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "LcEwO8UogRr9"
|
|
},
|
|
"source": [
|
|
"**핵심 요점**: 정수와 `None` 값 간의 덧셈(및 기타 연산)은 정의되지 않으므로 이를 포함하는 데이터셋에서 수행할 수 있는 작업이 제한될 수 있습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "pWvVHvETgRr9"
|
|
},
|
|
"source": [
|
|
"### `NaN`: 누락된 부동소수점 값\n",
|
|
"\n",
|
|
"`None`과는 달리, NumPy(따라서 pandas도)는 빠르고 벡터화된 연산 및 ufunc을 위해 `NaN`을 지원합니다. 문제는 `NaN`에 대해 수행된 모든 산술 연산은 항상 `NaN`을 반환한다는 점입니다. 예를 들어:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "rcFYfMG9gRr9",
|
|
"outputId": "699e81b7-5c11-4b46-df1d-06071768690f",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"nan"
|
|
]
|
|
},
|
|
"execution_count": 11,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"np.nan + 1"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "BW3zQD2-gRr-",
|
|
"outputId": "4525b6c4-495d-4f7b-a979-efce1dae9bd0",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"nan"
|
|
]
|
|
},
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"np.nan * 0"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "fU5IPRcCgRr-"
|
|
},
|
|
"source": [
|
|
"좋은 소식: `NaN`이 포함된 배열에서 실행되는 집계는 오류를 발생시키지 않습니다. 나쁜 소식: 결과가 일관되게 유용하지는 않습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "LCInVgSSgRr_",
|
|
"outputId": "fa06495a-0930-4867-87c5-6023031ea8b5",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"(nan, nan, nan)"
|
|
]
|
|
},
|
|
"execution_count": 13,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example2 = np.array([2, np.nan, 6, 8]) \n",
|
|
"example2.sum(), example2.min(), example2.max()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "nhlnNJT7gRr_"
|
|
},
|
|
"source": [
|
|
"### 운동:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"id": "yan3QRaOgRr_",
|
|
"trusted": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# What happens if you add np.nan and None together?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "_iDvIRC8gRsA"
|
|
},
|
|
"source": [
|
|
"기억하세요: `NaN`은 부동 소수점 값이 누락된 경우에만 사용됩니다. 정수, 문자열 또는 불리언에는 `NaN`에 해당하는 값이 없습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "kj6EKdsAgRsA"
|
|
},
|
|
"source": [
|
|
"### `NaN`과 `None`: pandas에서의 null 값\n",
|
|
"\n",
|
|
"`NaN`과 `None`이 약간 다르게 작동할 수는 있지만, pandas는 이 둘을 교환 가능하도록 처리하도록 설계되었습니다. 이를 이해하기 위해 정수로 구성된 `Series`를 살펴보세요:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 15,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "Nji-KGdNgRsA",
|
|
"outputId": "36aa14d2-8efa-4bfd-c0ed-682991288822",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"0 1\n",
|
|
"1 2\n",
|
|
"2 3\n",
|
|
"dtype: int64"
|
|
]
|
|
},
|
|
"execution_count": 15,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"int_series = pd.Series([1, 2, 3], dtype=int)\n",
|
|
"int_series"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "WklCzqb8gRsB"
|
|
},
|
|
"source": [
|
|
"### 운동:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 16,
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"id": "Cy-gqX5-gRsB",
|
|
"trusted": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Now set an element of int_series equal to None.\n",
|
|
"# How does that element show up in the Series?\n",
|
|
"# What is the dtype of the Series?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "WjMQwltNgRsB"
|
|
},
|
|
"source": [
|
|
"데이터의 동질성을 유지하기 위해 `Series`와 `DataFrame`에서 데이터 유형을 업캐스팅하는 과정에서 pandas는 결측값을 `None`과 `NaN` 사이에서 자유롭게 전환합니다. 이러한 설계 특징 때문에 pandas에서는 `None`과 `NaN`을 \"null\"의 두 가지 다른 형태로 생각하는 것이 유용할 수 있습니다. 실제로 pandas에서 결측값을 처리하기 위해 사용하는 핵심 메서드 중 일부는 이러한 아이디어를 이름에 반영하고 있습니다:\n",
|
|
"\n",
|
|
"- `isnull()`: 결측값을 나타내는 Boolean 마스크를 생성합니다\n",
|
|
"- `notnull()`: `isnull()`의 반대\n",
|
|
"- `dropna()`: 필터링된 데이터 버전을 반환합니다\n",
|
|
"- `fillna()`: 결측값을 채우거나 대체한 데이터 복사본을 반환합니다\n",
|
|
"\n",
|
|
"이 메서드들은 익숙해지고 숙달해야 할 중요한 기능이므로, 각각을 조금 더 깊이 살펴보겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "Yh5ifd9FgRsB"
|
|
},
|
|
"source": [
|
|
"### null 값 감지하기\n",
|
|
"\n",
|
|
"누락된 값의 중요성을 이해했으니, 이를 처리하기 전에 데이터셋에서 누락된 값을 감지해야 합니다. \n",
|
|
"`isnull()`과 `notnull()`은 null 데이터를 감지하기 위한 주요 메서드입니다. 두 메서드는 데이터에 대해 Boolean 마스크를 반환합니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 17,
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"id": "e-vFp5lvgRsC",
|
|
"trusted": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"example3 = pd.Series([0, np.nan, '', None])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 18,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "1XdaJJ7PgRsC",
|
|
"outputId": "92fc363a-1874-471f-846d-f4f9ce1f51d0",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"0 False\n",
|
|
"1 True\n",
|
|
"2 False\n",
|
|
"3 True\n",
|
|
"dtype: bool"
|
|
]
|
|
},
|
|
"execution_count": 18,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example3.isnull()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "PaSZ0SQygRsC"
|
|
},
|
|
"source": [
|
|
"출력 결과를 자세히 살펴보세요. 어떤 점이 놀랍게 느껴지나요? `0`은 산술적으로는 null이지만, 여전히 완벽한 정수이며 pandas는 이를 정수로 처리합니다. `''`는 조금 더 미묘합니다. Section 1에서 빈 문자열 값을 나타내기 위해 사용했지만, pandas 관점에서는 여전히 문자열 객체일 뿐 null을 나타내는 것은 아닙니다.\n",
|
|
"\n",
|
|
"이제 방향을 바꿔서 실무에서 사용할 방식으로 이러한 메서드를 사용해 보겠습니다. Boolean 마스크를 직접 ``Series`` 또는 ``DataFrame`` 인덱스로 사용할 수 있으며, 이는 누락된 값(또는 존재하는 값)을 분리하여 작업할 때 유용할 수 있습니다.\n",
|
|
"\n",
|
|
"누락된 값의 총 개수를 알고 싶다면, `isnull()` 메서드로 생성된 마스크에 대해 단순히 합계를 구하면 됩니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 19,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "JCcQVoPkHDUv",
|
|
"outputId": "001daa72-54f8-4bd5-842a-4df627a79d4d"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"2"
|
|
]
|
|
},
|
|
"execution_count": 19,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example3.isnull().sum()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "PlBqEo3mgRsC"
|
|
},
|
|
"source": [
|
|
"### 운동:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 20,
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"id": "ggDVf5uygRsD",
|
|
"trusted": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Try running example3[example3.notnull()].\n",
|
|
"# Before you do so, what do you expect to see?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "D_jWN7mHgRsD"
|
|
},
|
|
"source": [
|
|
"**핵심 요점**: `isnull()` 및 `notnull()` 메서드는 DataFrame에서 사용할 때 유사한 결과를 생성합니다. 이 메서드들은 결과와 해당 결과의 인덱스를 보여주며, 데이터를 처리하는 데 큰 도움이 됩니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "BvnoojWsgRr4"
|
|
},
|
|
"source": [
|
|
"### 누락된 데이터 처리하기\n",
|
|
"\n",
|
|
"> **학습 목표:** 이 절을 마치면 DataFrame에서 null 값을 대체하거나 제거하는 방법과 시기를 알게 됩니다.\n",
|
|
"\n",
|
|
"머신러닝 모델은 스스로 누락된 데이터를 처리할 수 없습니다. 따라서 데이터를 모델에 전달하기 전에 이러한 누락된 값을 처리해야 합니다.\n",
|
|
"\n",
|
|
"누락된 데이터를 처리하는 방식은 미묘한 트레이드오프를 포함하며, 최종 분석 및 실제 결과에 영향을 미칠 수 있습니다.\n",
|
|
"\n",
|
|
"누락된 데이터를 처리하는 주요 방법은 다음 두 가지입니다:\n",
|
|
"\n",
|
|
"1. 누락된 값을 포함한 행을 삭제하기\n",
|
|
"2. 누락된 값을 다른 값으로 대체하기\n",
|
|
"\n",
|
|
"이 두 가지 방법과 각각의 장단점에 대해 자세히 논의해 보겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "3VaYC1TvgRsD"
|
|
},
|
|
"source": [
|
|
"### null 값 제거하기\n",
|
|
"\n",
|
|
"모델에 전달하는 데이터의 양은 성능에 직접적인 영향을 미칩니다. null 값을 제거한다는 것은 데이터 포인트의 수를 줄이고, 따라서 데이터셋의 크기를 줄이는 것을 의미합니다. 따라서 데이터셋이 상당히 클 경우 null 값이 있는 행을 제거하는 것이 권장됩니다.\n",
|
|
"\n",
|
|
"또 다른 경우로는 특정 행이나 열에 많은 누락된 값이 있을 때입니다. 이 경우 대부분의 데이터가 누락되어 있어 분석에 큰 가치를 더하지 못하기 때문에 해당 행이나 열을 제거할 수 있습니다.\n",
|
|
"\n",
|
|
"누락된 값을 식별하는 것을 넘어, pandas는 `Series`와 `DataFrame`에서 null 값을 제거하는 편리한 방법을 제공합니다. 이를 실제로 확인하기 위해 `example3`로 돌아가 보겠습니다. `DataFrame.dropna()` 함수는 null 값이 있는 행을 제거하는 데 도움을 줍니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 21,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "7uIvS097gRsD",
|
|
"outputId": "c13fc117-4ca1-4145-a0aa-42ac89e6e218",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"0 0\n",
|
|
"2 \n",
|
|
"dtype: object"
|
|
]
|
|
},
|
|
"execution_count": 21,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example3 = example3.dropna()\n",
|
|
"example3"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "hil2cr64gRsD"
|
|
},
|
|
"source": [
|
|
"`example3[example3.notnull()]`의 출력과 비슷하게 보여야 합니다. 여기서 차이점은 마스크된 값만 인덱싱하는 대신, `dropna`가 `Series` `example3`에서 누락된 값을 제거했다는 점입니다.\n",
|
|
"\n",
|
|
"DataFrame은 두 개의 차원을 가지므로 데이터를 제거하는 데 더 많은 옵션을 제공합니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 22,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 142
|
|
},
|
|
"id": "an-l74sPgRsE",
|
|
"outputId": "340876a0-63ad-40f6-bd54-6240cdae50ab",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>7</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>5.0</td>\n",
|
|
" <td>8</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>6.0</td>\n",
|
|
" <td>9</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2\n",
|
|
"0 1.0 NaN 7\n",
|
|
"1 2.0 5.0 8\n",
|
|
"2 NaN 6.0 9"
|
|
]
|
|
},
|
|
"execution_count": 22,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example4 = pd.DataFrame([[1, np.nan, 7], \n",
|
|
" [2, 5, 8], \n",
|
|
" [np.nan, 6, 9]])\n",
|
|
"example4"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "66wwdHZrgRsE"
|
|
},
|
|
"source": [
|
|
"(팬더가 `NaN`을 처리하기 위해 두 개의 열을 부동소수점으로 업캐스트한 것을 눈치채셨나요?)\n",
|
|
"\n",
|
|
"`DataFrame`에서 단일 값을 삭제할 수는 없으므로 전체 행이나 열을 삭제해야 합니다. 수행하려는 작업에 따라 둘 중 하나를 선택할 수 있으며, 팬더는 두 가지 옵션을 제공합니다. 데이터 과학에서는 일반적으로 열이 변수(variable)를 나타내고 행이 관측값(observation)을 나타내기 때문에 데이터를 삭제할 때 행을 삭제하는 경우가 더 많습니다. `dropna()`의 기본 설정은 null 값을 포함하는 모든 행을 삭제하는 것입니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 23,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 80
|
|
},
|
|
"id": "jAVU24RXgRsE",
|
|
"outputId": "0b5e5aee-7187-4d3f-b583-a44136ae5f80",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>5.0</td>\n",
|
|
" <td>8</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2\n",
|
|
"1 2.0 5.0 8"
|
|
]
|
|
},
|
|
"execution_count": 23,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example4.dropna()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "TrQRBuTDgRsE"
|
|
},
|
|
"source": [
|
|
"필요한 경우 열에서 NA 값을 제거할 수 있습니다. 이를 위해 `axis=1`을 사용하십시오:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 24,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 142
|
|
},
|
|
"id": "GrBhxu9GgRsE",
|
|
"outputId": "ff4001f3-2e61-4509-d60e-0093d1068437",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>2</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>7</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>8</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>9</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 2\n",
|
|
"0 7\n",
|
|
"1 8\n",
|
|
"2 9"
|
|
]
|
|
},
|
|
"execution_count": 24,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example4.dropna(axis='columns')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "KWXiKTfMgRsF"
|
|
},
|
|
"source": [
|
|
"이 방법은 특히 작은 데이터셋에서 유지하고 싶은 많은 데이터를 삭제할 수 있다는 점을 유의하세요. 만약 여러 개의 null 값이 포함된 행이나 열, 또는 모든 값이 null인 행이나 열만 삭제하고 싶다면 어떻게 해야 할까요? `dropna`에서 `how`와 `thresh` 매개변수를 설정하여 이를 지정할 수 있습니다.\n",
|
|
"\n",
|
|
"기본적으로 `how='any'`로 설정되어 있습니다(직접 확인하거나 메서드의 다른 매개변수를 보고 싶다면 코드 셀에서 `example4.dropna?`를 실행해 보세요). 대신 `how='all'`을 지정하여 모든 값이 null인 행이나 열만 삭제하도록 설정할 수도 있습니다. 다음 연습에서 이를 확인하기 위해 예제 `DataFrame`을 확장해 보겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 25,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 142
|
|
},
|
|
"id": "Bcf_JWTsgRsF",
|
|
"outputId": "72e0b1b8-52fa-4923-98ce-b6fbed6e44b1",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" <th>3</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>7</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>5.0</td>\n",
|
|
" <td>8</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>6.0</td>\n",
|
|
" <td>9</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2 3\n",
|
|
"0 1.0 NaN 7 NaN\n",
|
|
"1 2.0 5.0 8 NaN\n",
|
|
"2 NaN 6.0 9 NaN"
|
|
]
|
|
},
|
|
"execution_count": 25,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example4[3] = np.nan\n",
|
|
"example4"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "pNZer7q9JPNC"
|
|
},
|
|
"source": [
|
|
"> 주요 요점:\n",
|
|
"1. 데이터셋이 충분히 클 경우에만 null 값을 제거하는 것이 좋은 선택입니다.\n",
|
|
"2. 대부분의 데이터가 누락된 전체 행이나 열은 삭제할 수 있습니다.\n",
|
|
"3. `DataFrame.dropna(axis=)` 메서드는 null 값을 제거하는 데 유용합니다. `axis` 인자는 행을 삭제할지 열을 삭제할지를 나타냅니다.\n",
|
|
"4. `how` 인자도 사용할 수 있습니다. 기본값은 `any`로 설정되어 있어, null 값이 하나라도 포함된 행/열만 삭제합니다. 이를 `all`로 설정하면 모든 값이 null인 행/열만 삭제하도록 지정할 수 있습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "oXXSfQFHgRsF"
|
|
},
|
|
"source": [
|
|
"### 운동:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 22,
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"id": "ExUwQRxpgRsF",
|
|
"trusted": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# How might you go about dropping just column 3?\n",
|
|
"# Hint: remember that you will need to supply both the axis parameter and the how parameter.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "38kwAihWgRsG"
|
|
},
|
|
"source": [
|
|
"`thresh` 매개변수는 더 세밀한 제어를 제공합니다. 행이나 열이 유지되기 위해 필요한 *null이 아닌* 값의 개수를 설정합니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 27,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 80
|
|
},
|
|
"id": "M9dCNMaagRsG",
|
|
"outputId": "8093713a-54d2-4e54-c73f-4eea315cb6f2",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" <th>3</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>5.0</td>\n",
|
|
" <td>8</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2 3\n",
|
|
"1 2.0 5.0 8 NaN"
|
|
]
|
|
},
|
|
"execution_count": 27,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example4.dropna(axis='rows', thresh=3)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "fmSFnzZegRsG"
|
|
},
|
|
"source": [
|
|
"여기서 첫 번째와 마지막 행은 삭제되었습니다. 왜냐하면 해당 행들은 두 개의 비어 있지 않은 값만 포함하고 있기 때문입니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "mCcxLGyUgRsG"
|
|
},
|
|
"source": [
|
|
"### 누락된 값 채우기\n",
|
|
"\n",
|
|
"때로는 누락된 값을 유효할 수 있는 값으로 채우는 것이 합리적일 때가 있습니다. 누락된 값을 채우는 몇 가지 기술이 있습니다. 첫 번째는 도메인 지식(데이터셋이 기반하고 있는 주제에 대한 지식)을 사용하여 누락된 값을 대략적으로 추정하는 방법입니다.\n",
|
|
"\n",
|
|
"`isnull`을 사용하여 직접 누락된 값을 채울 수도 있지만, 채워야 할 값이 많을 경우 이는 번거로울 수 있습니다. 데이터 과학에서 매우 흔한 작업이기 때문에 pandas는 `fillna`를 제공합니다. 이 함수는 누락된 값을 사용자가 선택한 값으로 대체한 `Series` 또는 `DataFrame`의 복사본을 반환합니다. 실제로 어떻게 작동하는지 보기 위해 또 다른 예제 `Series`를 만들어 보겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "CE8S7louLezV"
|
|
},
|
|
"source": [
|
|
"### 범주형 데이터(비숫자)\n",
|
|
"먼저 비숫자 데이터를 살펴보겠습니다. 데이터셋에는 범주형 데이터가 포함된 열이 있습니다. 예: 성별, 참 또는 거짓 등.\n",
|
|
"\n",
|
|
"이러한 경우 대부분에서, 누락된 값을 해당 열의 `최빈값(mode)`으로 대체합니다. 예를 들어, 데이터 포인트가 100개 있고, 그중 90개가 참(True), 8개가 거짓(False), 2개가 미기입 상태라면, 전체 열을 고려하여 누락된 2개를 참(True)으로 채울 수 있습니다.\n",
|
|
"\n",
|
|
"여기에서도 도메인 지식을 활용할 수 있습니다. 최빈값으로 채우는 예를 살펴보겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 28,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 204
|
|
},
|
|
"id": "MY5faq4yLdpQ",
|
|
"outputId": "19ab472e-1eed-4de8-f8a7-db2a3af3cb1a"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>1</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>3</td>\n",
|
|
" <td>4</td>\n",
|
|
" <td>None</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>5</td>\n",
|
|
" <td>6</td>\n",
|
|
" <td>False</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>7</td>\n",
|
|
" <td>8</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>9</td>\n",
|
|
" <td>10</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2\n",
|
|
"0 1 2 True\n",
|
|
"1 3 4 None\n",
|
|
"2 5 6 False\n",
|
|
"3 7 8 True\n",
|
|
"4 9 10 True"
|
|
]
|
|
},
|
|
"execution_count": 28,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"fill_with_mode = pd.DataFrame([[1,2,\"True\"],\n",
|
|
" [3,4,None],\n",
|
|
" [5,6,\"False\"],\n",
|
|
" [7,8,\"True\"],\n",
|
|
" [9,10,\"True\"]])\n",
|
|
"\n",
|
|
"fill_with_mode"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "MLAoMQOfNPlA"
|
|
},
|
|
"source": [
|
|
"이제 `None` 값을 모드로 채우기 전에 먼저 모드를 찾아봅시다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 29,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "WKy-9Y2tN5jv",
|
|
"outputId": "8da9fa16-e08c-447e-dea1-d4b1db2feebf"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"True 3\n",
|
|
"False 1\n",
|
|
"Name: 2, dtype: int64"
|
|
]
|
|
},
|
|
"execution_count": 29,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"fill_with_mode[2].value_counts()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "6iNz_zG_OKrx"
|
|
},
|
|
"source": [
|
|
"그래서, 우리는 None을 True로 대체할 것입니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 30,
|
|
"metadata": {
|
|
"id": "TxPKteRvNPOs"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"fill_with_mode[2].fillna('True',inplace=True)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 31,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 204
|
|
},
|
|
"id": "tvas7c9_OPWE",
|
|
"outputId": "ec3c8e44-d644-475e-9e22-c65101965850"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>1</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>3</td>\n",
|
|
" <td>4</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>5</td>\n",
|
|
" <td>6</td>\n",
|
|
" <td>False</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>7</td>\n",
|
|
" <td>8</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>9</td>\n",
|
|
" <td>10</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2\n",
|
|
"0 1 2 True\n",
|
|
"1 3 4 True\n",
|
|
"2 5 6 False\n",
|
|
"3 7 8 True\n",
|
|
"4 9 10 True"
|
|
]
|
|
},
|
|
"execution_count": 31,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"fill_with_mode"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "SktitLxxOR16"
|
|
},
|
|
"source": [
|
|
"우리가 볼 수 있듯이, null 값이 대체되었습니다. 말할 필요도 없이, 우리는 `'True'` 대신에 어떤 것이든 쓸 수 있었고 그것이 대체되었을 것입니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "heYe1I0dOmQ_"
|
|
},
|
|
"source": [
|
|
"### 숫자 데이터\n",
|
|
"이제 숫자 데이터로 넘어가 보겠습니다. 여기서는 누락된 값을 대체하는 두 가지 일반적인 방법이 있습니다:\n",
|
|
"\n",
|
|
"1. 행의 중앙값으로 대체하기 \n",
|
|
"2. 행의 평균값으로 대체하기 \n",
|
|
"\n",
|
|
"데이터가 이상치로 인해 왜곡된 경우에는 중앙값으로 대체합니다. 이는 중앙값이 이상치에 강건하기 때문입니다.\n",
|
|
"\n",
|
|
"데이터가 정규화된 경우에는 평균값을 사용할 수 있습니다. 이 경우 평균값과 중앙값이 거의 비슷하기 때문입니다.\n",
|
|
"\n",
|
|
"먼저, 정규 분포를 따르는 열을 선택하고 해당 열의 평균값으로 누락된 값을 채워 보겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 32,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 204
|
|
},
|
|
"id": "09HM_2feOj5Y",
|
|
"outputId": "7e309013-9acb-411c-9b06-4de795bbeeff"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>-2.0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>-1.0</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>3</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>4</td>\n",
|
|
" <td>5</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>6</td>\n",
|
|
" <td>7</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>8</td>\n",
|
|
" <td>9</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2\n",
|
|
"0 -2.0 0 1\n",
|
|
"1 -1.0 2 3\n",
|
|
"2 NaN 4 5\n",
|
|
"3 1.0 6 7\n",
|
|
"4 2.0 8 9"
|
|
]
|
|
},
|
|
"execution_count": 32,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"fill_with_mean = pd.DataFrame([[-2,0,1],\n",
|
|
" [-1,2,3],\n",
|
|
" [np.nan,4,5],\n",
|
|
" [1,6,7],\n",
|
|
" [2,8,9]])\n",
|
|
"\n",
|
|
"fill_with_mean"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "ka7-wNfzSxbx"
|
|
},
|
|
"source": [
|
|
"열의 평균은\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 33,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "XYtYEf5BSxFL",
|
|
"outputId": "68a78d18-f0e5-4a9a-a959-2c3676a57c70"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"0.0"
|
|
]
|
|
},
|
|
"execution_count": 33,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"np.mean(fill_with_mean[0])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "oBSRGxKRS39K"
|
|
},
|
|
"source": [
|
|
"평균으로 채우기\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 34,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 204
|
|
},
|
|
"id": "FzncQLmuS5jh",
|
|
"outputId": "00f74fff-01f4-4024-c261-796f50f01d2e"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>-2.0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>-1.0</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>3</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>0.0</td>\n",
|
|
" <td>4</td>\n",
|
|
" <td>5</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>6</td>\n",
|
|
" <td>7</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>8</td>\n",
|
|
" <td>9</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2\n",
|
|
"0 -2.0 0 1\n",
|
|
"1 -1.0 2 3\n",
|
|
"2 0.0 4 5\n",
|
|
"3 1.0 6 7\n",
|
|
"4 2.0 8 9"
|
|
]
|
|
},
|
|
"execution_count": 34,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"fill_with_mean[0].fillna(np.mean(fill_with_mean[0]),inplace=True)\n",
|
|
"fill_with_mean"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "CwpVFCrPTC5z"
|
|
},
|
|
"source": [
|
|
"우리가 볼 수 있듯이, 누락된 값이 평균으로 대체되었습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "jIvF13a1i00Z"
|
|
},
|
|
"source": [
|
|
"이제 다른 데이터프레임을 시도해 보겠습니다. 이번에는 None 값을 해당 열의 중앙값으로 대체하겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 35,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 204
|
|
},
|
|
"id": "DA59Bqo3jBYZ",
|
|
"outputId": "85dae6ec-7394-4c36-fda0-e04769ec4a32"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>-2</td>\n",
|
|
" <td>0.0</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>-1</td>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>3</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>0</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>5</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>1</td>\n",
|
|
" <td>6.0</td>\n",
|
|
" <td>7</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>2</td>\n",
|
|
" <td>8.0</td>\n",
|
|
" <td>9</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2\n",
|
|
"0 -2 0.0 1\n",
|
|
"1 -1 2.0 3\n",
|
|
"2 0 NaN 5\n",
|
|
"3 1 6.0 7\n",
|
|
"4 2 8.0 9"
|
|
]
|
|
},
|
|
"execution_count": 35,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"fill_with_median = pd.DataFrame([[-2,0,1],\n",
|
|
" [-1,2,3],\n",
|
|
" [0,np.nan,5],\n",
|
|
" [1,6,7],\n",
|
|
" [2,8,9]])\n",
|
|
"\n",
|
|
"fill_with_median"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "mM1GpXYmjHnc"
|
|
},
|
|
"source": [
|
|
"두 번째 열의 중앙값은\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 36,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "uiDy5v3xjHHX",
|
|
"outputId": "564b6b74-2004-4486-90d4-b39330a64b88"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"4.0"
|
|
]
|
|
},
|
|
"execution_count": 36,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"fill_with_median[1].median()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "z9PLF75Jj_1s"
|
|
},
|
|
"source": [
|
|
"중앙값으로 채우기\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 37,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 204
|
|
},
|
|
"id": "lFKbOxCMkBbg",
|
|
"outputId": "a8bd18fb-2765-47d4-e5fe-e965f57ed1f4"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>-2</td>\n",
|
|
" <td>0.0</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>-1</td>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>3</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>0</td>\n",
|
|
" <td>4.0</td>\n",
|
|
" <td>5</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>1</td>\n",
|
|
" <td>6.0</td>\n",
|
|
" <td>7</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>2</td>\n",
|
|
" <td>8.0</td>\n",
|
|
" <td>9</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2\n",
|
|
"0 -2 0.0 1\n",
|
|
"1 -1 2.0 3\n",
|
|
"2 0 4.0 5\n",
|
|
"3 1 6.0 7\n",
|
|
"4 2 8.0 9"
|
|
]
|
|
},
|
|
"execution_count": 37,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"fill_with_median[1].fillna(fill_with_median[1].median(),inplace=True)\n",
|
|
"fill_with_median"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "8JtQ53GSkKWC"
|
|
},
|
|
"source": [
|
|
"우리가 볼 수 있듯이, NaN 값이 해당 열의 중앙값으로 대체되었습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 38,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "0ybtWLDdgRsG",
|
|
"outputId": "b8c238ef-6024-4ee2-be2b-aa1f0fcac61d",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"a 1.0\n",
|
|
"b NaN\n",
|
|
"c 2.0\n",
|
|
"d NaN\n",
|
|
"e 3.0\n",
|
|
"dtype: float64"
|
|
]
|
|
},
|
|
"execution_count": 38,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example5 = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))\n",
|
|
"example5"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "yrsigxRggRsH"
|
|
},
|
|
"source": [
|
|
"모든 null 항목을 단일 값, 예를 들어 `0`으로 채울 수 있습니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 39,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "KXMIPsQdgRsH",
|
|
"outputId": "aeedfa0a-a421-4c2f-cb0d-183ce8f0c91d",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"a 1.0\n",
|
|
"b 0.0\n",
|
|
"c 2.0\n",
|
|
"d 0.0\n",
|
|
"e 3.0\n",
|
|
"dtype: float64"
|
|
]
|
|
},
|
|
"execution_count": 39,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example5.fillna(0)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "RRlI5f_hkfKe"
|
|
},
|
|
"source": [
|
|
"> 주요 요점:\n",
|
|
"1. 누락된 값을 채우는 작업은 데이터가 적거나 누락된 데이터를 채우는 전략이 있을 때 수행해야 합니다.\n",
|
|
"2. 도메인 지식을 활용하여 누락된 값을 근사적으로 채울 수 있습니다.\n",
|
|
"3. 범주형 데이터의 경우, 대부분 누락된 값은 해당 열의 최빈값으로 대체됩니다.\n",
|
|
"4. 숫자형 데이터의 경우, 누락된 값은 일반적으로 평균(정규화된 데이터셋의 경우) 또는 열의 중앙값으로 채워집니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "FI9MmqFJgRsH"
|
|
},
|
|
"source": [
|
|
"### 운동:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 40,
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"id": "af-ezpXdgRsH",
|
|
"trusted": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# What happens if you try to fill null values with a string, like ''?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "kq3hw1kLgRsI"
|
|
},
|
|
"source": [
|
|
"널 값을 **앞으로 채우기**로 채울 수 있습니다. 이는 마지막 유효 값을 사용하여 널 값을 채우는 것입니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 41,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "vO3BuNrggRsI",
|
|
"outputId": "e2bc591b-0b48-4e88-ee65-754f2737c196",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"a 1.0\n",
|
|
"b 1.0\n",
|
|
"c 2.0\n",
|
|
"d 2.0\n",
|
|
"e 3.0\n",
|
|
"dtype: float64"
|
|
]
|
|
},
|
|
"execution_count": 41,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example5.fillna(method='ffill')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "nDXeYuHzgRsI"
|
|
},
|
|
"source": [
|
|
"다음 유효 값을 뒤로 전파하여 null을 채우기 위해 **백필**할 수도 있습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 42,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "4M5onHcEgRsI",
|
|
"outputId": "8f32b185-40dd-4a9f-bd85-54d6b6a414fe",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"a 1.0\n",
|
|
"b 2.0\n",
|
|
"c 2.0\n",
|
|
"d 3.0\n",
|
|
"e 3.0\n",
|
|
"dtype: float64"
|
|
]
|
|
},
|
|
"execution_count": 42,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example5.fillna(method='bfill')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"id": "MbBzTom5gRsI"
|
|
},
|
|
"source": [
|
|
"데이터프레임에서도 동일하게 작동하지만, null 값을 채울 축(`axis`)을 지정할 수도 있습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 43,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 142
|
|
},
|
|
"id": "aRpIvo4ZgRsI",
|
|
"outputId": "905a980a-a808-4eca-d0ba-224bd7d85955",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" <th>3</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>7</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>5.0</td>\n",
|
|
" <td>8</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>6.0</td>\n",
|
|
" <td>9</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2 3\n",
|
|
"0 1.0 NaN 7 NaN\n",
|
|
"1 2.0 5.0 8 NaN\n",
|
|
"2 NaN 6.0 9 NaN"
|
|
]
|
|
},
|
|
"execution_count": 43,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example4"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 44,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 142
|
|
},
|
|
"id": "VM1qtACAgRsI",
|
|
"outputId": "71f2ad28-9b4e-4ff4-f5c3-e731eb489ade",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" <th>3</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>7.0</td>\n",
|
|
" <td>7.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>5.0</td>\n",
|
|
" <td>8.0</td>\n",
|
|
" <td>8.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>6.0</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2 3\n",
|
|
"0 1.0 1.0 7.0 7.0\n",
|
|
"1 2.0 5.0 8.0 8.0\n",
|
|
"2 NaN 6.0 9.0 9.0"
|
|
]
|
|
},
|
|
"execution_count": 44,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example4.fillna(method='ffill', axis=1)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "ZeMc-I1EgRsI"
|
|
},
|
|
"source": [
|
|
"이전 값이 전진 채우기에 사용할 수 없을 때, null 값이 그대로 유지된다는 점을 유의하세요.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "eeAoOU0RgRsJ"
|
|
},
|
|
"source": [
|
|
"### 운동:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 45,
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"id": "e8S-CjW8gRsJ",
|
|
"trusted": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# What output does example4.fillna(method='bfill', axis=1) produce?\n",
|
|
"# What about example4.fillna(method='ffill') or example4.fillna(method='bfill')?\n",
|
|
"# Can you think of a longer code snippet to write that can fill all of the null values in example4?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "YHgy0lIrgRsJ"
|
|
},
|
|
"source": [
|
|
"당신은 `fillna`를 사용하는 방법에 대해 창의적일 수 있습니다. 예를 들어, 다시 `example4`를 살펴보지만 이번에는 누락된 값을 `DataFrame`의 모든 값의 평균으로 채워봅시다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 46,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 142
|
|
},
|
|
"id": "OtYVErEygRsJ",
|
|
"outputId": "708b1e67-45ca-44bf-a5ee-8b2de09ece73",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>0</th>\n",
|
|
" <th>1</th>\n",
|
|
" <th>2</th>\n",
|
|
" <th>3</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>5.5</td>\n",
|
|
" <td>7</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>5.0</td>\n",
|
|
" <td>8</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>1.5</td>\n",
|
|
" <td>6.0</td>\n",
|
|
" <td>9</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" 0 1 2 3\n",
|
|
"0 1.0 5.5 7 NaN\n",
|
|
"1 2.0 5.0 8 NaN\n",
|
|
"2 1.5 6.0 9 NaN"
|
|
]
|
|
},
|
|
"execution_count": 46,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example4.fillna(example4.mean())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "zpMvCkLSgRsJ"
|
|
},
|
|
"source": [
|
|
"3열이 여전히 값이 없는 상태임을 주목하세요: 기본 방향은 행 단위로 값을 채우는 것입니다.\n",
|
|
"\n",
|
|
"> **핵심 요점:** 데이터셋에서 누락된 값을 처리하는 방법은 여러 가지가 있습니다. 누락된 값을 제거하거나, 대체하거나, 대체 방법을 선택하는 전략은 해당 데이터의 특성에 따라 결정되어야 합니다. 데이터셋을 더 많이 다루고 상호작용할수록 누락된 값을 처리하는 방법에 대한 감각이 더욱 발전할 것입니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "bauDnESIl9FH"
|
|
},
|
|
"source": [
|
|
"### 범주형 데이터 인코딩\n",
|
|
"\n",
|
|
"머신러닝 모델은 숫자와 모든 형태의 숫자 데이터만 처리할 수 있습니다. 모델은 'Yes'와 'No'의 차이를 이해할 수 없지만, 0과 1은 구분할 수 있습니다. 따라서 누락된 값을 채운 후, 모델이 이해할 수 있도록 범주형 데이터를 숫자 형태로 인코딩해야 합니다.\n",
|
|
"\n",
|
|
"인코딩은 두 가지 방법으로 수행할 수 있습니다. 다음에서 이를 논의하겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "uDq9SxB7mu5i"
|
|
},
|
|
"source": [
|
|
"**레이블 인코딩**\n",
|
|
"\n",
|
|
"레이블 인코딩은 기본적으로 각 카테고리를 숫자로 변환하는 것입니다. 예를 들어, 항공사 승객 데이터셋이 있고, 해당 데이터셋에 ['비즈니스 클래스', '이코노미 클래스', '퍼스트 클래스'] 중 하나의 클래스를 포함하는 열이 있다고 가정해봅시다. 이 열에 레이블 인코딩을 적용하면 [0, 1, 2]로 변환됩니다. 코드로 예제를 살펴보겠습니다. 앞으로의 노트북에서 `scikit-learn`을 학습할 예정이므로 여기서는 사용하지 않겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 47,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 235
|
|
},
|
|
"id": "1vGz7uZyoWHL",
|
|
"outputId": "9e252855-d193-4103-a54d-028ea7787b34"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>ID</th>\n",
|
|
" <th>class</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>10</td>\n",
|
|
" <td>business class</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>20</td>\n",
|
|
" <td>first class</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>30</td>\n",
|
|
" <td>economy class</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>40</td>\n",
|
|
" <td>economy class</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>50</td>\n",
|
|
" <td>economy class</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5</th>\n",
|
|
" <td>60</td>\n",
|
|
" <td>business class</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" ID class\n",
|
|
"0 10 business class\n",
|
|
"1 20 first class\n",
|
|
"2 30 economy class\n",
|
|
"3 40 economy class\n",
|
|
"4 50 economy class\n",
|
|
"5 60 business class"
|
|
]
|
|
},
|
|
"execution_count": 47,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"label = pd.DataFrame([\n",
|
|
" [10,'business class'],\n",
|
|
" [20,'first class'],\n",
|
|
" [30, 'economy class'],\n",
|
|
" [40, 'economy class'],\n",
|
|
" [50, 'economy class'],\n",
|
|
" [60, 'business class']\n",
|
|
"],columns=['ID','class'])\n",
|
|
"label"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "IDHnkwTYov-h"
|
|
},
|
|
"source": [
|
|
"1열에 레이블 인코딩을 수행하려면 각 클래스에서 숫자로의 매핑을 먼저 설명한 후 교체해야 합니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 48,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 235
|
|
},
|
|
"id": "ZC5URJG3o1ES",
|
|
"outputId": "aab0f1e7-e0f3-4c14-8459-9f9168c85437"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>ID</th>\n",
|
|
" <th>class</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>10</td>\n",
|
|
" <td>0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>20</td>\n",
|
|
" <td>2</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>30</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>40</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>50</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5</th>\n",
|
|
" <td>60</td>\n",
|
|
" <td>0</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" ID class\n",
|
|
"0 10 0\n",
|
|
"1 20 2\n",
|
|
"2 30 1\n",
|
|
"3 40 1\n",
|
|
"4 50 1\n",
|
|
"5 60 0"
|
|
]
|
|
},
|
|
"execution_count": 48,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"class_labels = {'business class':0,'economy class':1,'first class':2}\n",
|
|
"label['class'] = label['class'].replace(class_labels)\n",
|
|
"label"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "ftnF-TyapOPt"
|
|
},
|
|
"source": [
|
|
"우리가 볼 수 있듯이, 출력은 우리가 예상했던 것과 일치합니다. 그렇다면 라벨 인코딩은 언제 사용해야 할까요? 라벨 인코딩은 다음과 같은 경우에 사용됩니다:\n",
|
|
"1. 카테고리의 수가 많을 때\n",
|
|
"2. 카테고리가 순서대로 정렬되어 있을 때\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "eQPAPVwsqWT7"
|
|
},
|
|
"source": [
|
|
"**원핫 인코딩**\n",
|
|
"\n",
|
|
"원핫 인코딩은 또 다른 유형의 인코딩 방식입니다. 이 인코딩 방식에서는 열의 각 카테고리가 별도의 열로 추가되며, 각 데이터 포인트는 해당 카테고리를 포함하는지 여부에 따라 0 또는 1을 받게 됩니다. 따라서 서로 다른 카테고리가 n개 있다면, 데이터프레임에 n개의 열이 추가됩니다.\n",
|
|
"\n",
|
|
"예를 들어, 같은 비행기 클래스 예제를 사용해 보겠습니다. 카테고리는 ['business class', 'economy class', 'first class']였습니다. 원핫 인코딩을 수행하면, 데이터셋에 다음 세 개의 열이 추가됩니다: ['class_business class', 'class_economy class', 'class_first class'].\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 49,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 235
|
|
},
|
|
"id": "ZM0eVh0ArKUL",
|
|
"outputId": "83238a76-b3a5-418d-c0b6-605b02b6891b"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>ID</th>\n",
|
|
" <th>class</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>10</td>\n",
|
|
" <td>business class</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>20</td>\n",
|
|
" <td>first class</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>30</td>\n",
|
|
" <td>economy class</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>40</td>\n",
|
|
" <td>economy class</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>50</td>\n",
|
|
" <td>economy class</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5</th>\n",
|
|
" <td>60</td>\n",
|
|
" <td>business class</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" ID class\n",
|
|
"0 10 business class\n",
|
|
"1 20 first class\n",
|
|
"2 30 economy class\n",
|
|
"3 40 economy class\n",
|
|
"4 50 economy class\n",
|
|
"5 60 business class"
|
|
]
|
|
},
|
|
"execution_count": 49,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"one_hot = pd.DataFrame([\n",
|
|
" [10,'business class'],\n",
|
|
" [20,'first class'],\n",
|
|
" [30, 'economy class'],\n",
|
|
" [40, 'economy class'],\n",
|
|
" [50, 'economy class'],\n",
|
|
" [60, 'business class']\n",
|
|
"],columns=['ID','class'])\n",
|
|
"one_hot"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "aVnZ7paDrWmb"
|
|
},
|
|
"source": [
|
|
"1열에 대해 원-핫 인코딩을 수행합시다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 50,
|
|
"metadata": {
|
|
"id": "RUPxf7egrYKr"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"one_hot_data = pd.get_dummies(one_hot,columns=['class'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 51,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 235
|
|
},
|
|
"id": "TM37pHsFr4ge",
|
|
"outputId": "7be15f53-79b2-447a-979c-822658339a9e"
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>ID</th>\n",
|
|
" <th>class_business class</th>\n",
|
|
" <th>class_economy class</th>\n",
|
|
" <th>class_first class</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>10</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>20</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>30</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>40</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>50</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5</th>\n",
|
|
" <td>60</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" ID class_business class class_economy class class_first class\n",
|
|
"0 10 1 0 0\n",
|
|
"1 20 0 0 1\n",
|
|
"2 30 0 1 0\n",
|
|
"3 40 0 1 0\n",
|
|
"4 50 0 1 0\n",
|
|
"5 60 1 0 0"
|
|
]
|
|
},
|
|
"execution_count": 51,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"one_hot_data"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "_zXRLOjXujdA"
|
|
},
|
|
"source": [
|
|
"각각의 원-핫 인코딩된 열은 0 또는 1을 포함하며, 이는 해당 데이터 포인트에 그 카테고리가 존재하는지를 나타냅니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "bDnC4NQOu0qr"
|
|
},
|
|
"source": [
|
|
"원-핫 인코딩은 다음과 같은 경우에 사용됩니다:\n",
|
|
"\n",
|
|
"1. 카테고리 수와 데이터셋 크기가 작을 때.\n",
|
|
"2. 카테고리가 특정한 순서를 따르지 않을 때.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "XnUmci_4uvyu"
|
|
},
|
|
"source": [
|
|
"> 주요 요점:\n",
|
|
"1. 인코딩은 비숫자 데이터를 숫자 데이터로 변환하기 위해 수행됩니다.\n",
|
|
"2. 인코딩에는 라벨 인코딩과 원핫 인코딩 두 가지 유형이 있으며, 데이터셋의 요구에 따라 수행할 수 있습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "K8UXOJYRgRsJ"
|
|
},
|
|
"source": [
|
|
"## 중복 데이터 제거하기\n",
|
|
"\n",
|
|
"> **학습 목표:** 이 절을 마치면 DataFrame에서 중복 값을 식별하고 제거하는 데 익숙해질 것입니다.\n",
|
|
"\n",
|
|
"누락된 데이터 외에도 실제 데이터셋에서 중복된 데이터를 자주 접하게 됩니다. 다행히도 pandas는 중복 항목을 감지하고 제거하는 간단한 방법을 제공합니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "qrEG-Wa0gRsJ"
|
|
},
|
|
"source": [
|
|
"### 중복 항목 식별: `duplicated`\n",
|
|
"\n",
|
|
"pandas의 `duplicated` 메서드를 사용하면 중복 값을 쉽게 확인할 수 있습니다. 이 메서드는 `DataFrame`에서 이전 항목과 중복인지 여부를 나타내는 Boolean 마스크를 반환합니다. 이를 직접 확인하기 위해 또 다른 예제 `DataFrame`을 만들어 보겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 52,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 204
|
|
},
|
|
"id": "ZLu6FEnZgRsJ",
|
|
"outputId": "376512d1-d842-4db1-aea3-71052aeeecaf",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>letters</th>\n",
|
|
" <th>numbers</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>A</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>B</td>\n",
|
|
" <td>2</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>A</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>B</td>\n",
|
|
" <td>3</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>B</td>\n",
|
|
" <td>3</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" letters numbers\n",
|
|
"0 A 1\n",
|
|
"1 B 2\n",
|
|
"2 A 1\n",
|
|
"3 B 3\n",
|
|
"4 B 3"
|
|
]
|
|
},
|
|
"execution_count": 52,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example6 = pd.DataFrame({'letters': ['A','B'] * 2 + ['B'],\n",
|
|
" 'numbers': [1, 2, 1, 3, 3]})\n",
|
|
"example6"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 53,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/"
|
|
},
|
|
"id": "cIduB5oBgRsK",
|
|
"outputId": "3da27b3d-4d69-4e1d-bb52-0af21bae87f2",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"0 False\n",
|
|
"1 False\n",
|
|
"2 True\n",
|
|
"3 False\n",
|
|
"4 True\n",
|
|
"dtype: bool"
|
|
]
|
|
},
|
|
"execution_count": 53,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example6.duplicated()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "0eDRJD4SgRsK"
|
|
},
|
|
"source": [
|
|
"### 중복 제거: `drop_duplicates`\n",
|
|
"`drop_duplicates`는 `duplicated` 값이 모두 `False`인 데이터의 복사본을 반환합니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 54,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 142
|
|
},
|
|
"id": "w_YPpqIqgRsK",
|
|
"outputId": "ac66bd2f-8671-4744-87f5-8b8d96553dea",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>letters</th>\n",
|
|
" <th>numbers</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>A</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>B</td>\n",
|
|
" <td>2</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>B</td>\n",
|
|
" <td>3</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" letters numbers\n",
|
|
"0 A 1\n",
|
|
"1 B 2\n",
|
|
"3 B 3"
|
|
]
|
|
},
|
|
"execution_count": 54,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example6.drop_duplicates()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "69AqoCZAgRsK"
|
|
},
|
|
"source": [
|
|
"`duplicated`와 `drop_duplicates`는 기본적으로 모든 열을 고려하지만, `DataFrame`에서 특정 열의 부분 집합만을 검사하도록 지정할 수 있습니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 55,
|
|
"metadata": {
|
|
"colab": {
|
|
"base_uri": "https://localhost:8080/",
|
|
"height": 111
|
|
},
|
|
"id": "BILjDs67gRsK",
|
|
"outputId": "ef6dcc08-db8b-4352-c44e-5aa9e2bec0d3",
|
|
"trusted": false
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>letters</th>\n",
|
|
" <th>numbers</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>A</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>B</td>\n",
|
|
" <td>2</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" letters numbers\n",
|
|
"0 A 1\n",
|
|
"1 B 2"
|
|
]
|
|
},
|
|
"execution_count": 55,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"example6.drop_duplicates(['letters'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "GvX4og1EgRsL"
|
|
},
|
|
"source": [
|
|
"> **요점:** 중복 데이터를 제거하는 것은 거의 모든 데이터 과학 프로젝트에서 필수적인 부분입니다. 중복 데이터는 분석 결과를 변경하고 부정확한 결과를 초래할 수 있습니다!\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 실제 데이터 품질 점검\n",
|
|
"\n",
|
|
"> **학습 목표:** 이 섹션을 마치면, 실제 데이터에서 발생하는 일반적인 품질 문제를 감지하고 수정하는 데 익숙해질 것입니다. 여기에는 불일치하는 범주형 값, 비정상적인 숫자 값(이상치), 그리고 변형된 중복 엔티티가 포함됩니다.\n",
|
|
"\n",
|
|
"누락된 값과 정확히 동일한 중복은 흔한 문제지만, 실제 데이터셋에는 더 미묘한 문제가 포함되어 있는 경우가 많습니다:\n",
|
|
"\n",
|
|
"1. **불일치하는 범주형 값**: 동일한 범주가 다르게 표기된 경우 (예: \"USA\", \"U.S.A\", \"United States\")\n",
|
|
"2. **비정상적인 숫자 값**: 데이터 입력 오류를 나타내는 극단적인 이상치 (예: 나이 = 999)\n",
|
|
"3. **유사 중복 행**: 약간의 변형으로 동일한 엔티티를 나타내는 기록\n",
|
|
"\n",
|
|
"이러한 문제를 감지하고 처리하는 기술을 살펴보겠습니다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### \"더러운\" 샘플 데이터셋 생성하기\n",
|
|
"\n",
|
|
"먼저, 실제 데이터에서 흔히 접하는 문제 유형을 포함한 샘플 데이터셋을 만들어 보겠습니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import pandas as pd\n",
|
|
"import numpy as np\n",
|
|
"\n",
|
|
"# Create a sample dataset with quality issues\n",
|
|
"dirty_data = pd.DataFrame({\n",
|
|
" 'customer_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],\n",
|
|
" 'name': ['John Smith', 'Jane Doe', 'John Smith', 'Bob Johnson', \n",
|
|
" 'Alice Williams', 'Charlie Brown', 'John Smith', 'Eva Martinez',\n",
|
|
" 'Bob Johnson', 'Diana Prince', 'Frank Castle', 'Alice Williams'],\n",
|
|
" 'age': [25, 32, 25, 45, 28, 199, 25, 31, 45, 27, -5, 28],\n",
|
|
" 'country': ['USA', 'UK', 'U.S.A', 'Canada', 'USA', 'United Kingdom',\n",
|
|
" 'United States', 'Mexico', 'canada', 'USA', 'UK', 'usa'],\n",
|
|
" 'purchase_amount': [100.50, 250.00, 105.00, 320.00, 180.00, 90.00,\n",
|
|
" 102.00, 275.00, 325.00, 195.00, 410.00, 185.00]\n",
|
|
"})\n",
|
|
"\n",
|
|
"print(\"Sample 'Dirty' Dataset:\")\n",
|
|
"print(dirty_data)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 1. 일관되지 않은 범주형 값 감지\n",
|
|
"\n",
|
|
"`country` 열에 동일한 국가에 대해 여러 표현이 있는 것을 확인할 수 있습니다. 이러한 불일치를 찾아봅시다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Check unique values in the country column\n",
|
|
"print(\"Unique country values:\")\n",
|
|
"print(dirty_data['country'].unique())\n",
|
|
"print(f\"\\nTotal unique values: {dirty_data['country'].nunique()}\")\n",
|
|
"\n",
|
|
"# Count occurrences of each variation\n",
|
|
"print(\"\\nValue counts:\")\n",
|
|
"print(dirty_data['country'].value_counts())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### 범주형 값 표준화\n",
|
|
"\n",
|
|
"이 값을 표준화하기 위해 매핑을 생성할 수 있습니다. 간단한 방법은 소문자로 변환하고 매핑 딕셔너리를 만드는 것입니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Create a standardization mapping\n",
|
|
"country_mapping = {\n",
|
|
" 'usa': 'USA',\n",
|
|
" 'u.s.a': 'USA',\n",
|
|
" 'united states': 'USA',\n",
|
|
" 'uk': 'UK',\n",
|
|
" 'united kingdom': 'UK',\n",
|
|
" 'canada': 'Canada',\n",
|
|
" 'mexico': 'Mexico'\n",
|
|
"}\n",
|
|
"\n",
|
|
"# Standardize the country column\n",
|
|
"dirty_data['country_clean'] = dirty_data['country'].str.lower().map(country_mapping)\n",
|
|
"\n",
|
|
"print(\"Before standardization:\")\n",
|
|
"print(dirty_data['country'].value_counts())\n",
|
|
"print(\"\\nAfter standardization:\")\n",
|
|
"print(dirty_data[['country_clean']].value_counts())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"**대안: 퍼지 매칭 사용**\n",
|
|
"\n",
|
|
"더 복잡한 경우에는 `rapidfuzz` 라이브러리를 사용하여 유사한 문자열을 자동으로 감지하는 퍼지 문자열 매칭을 사용할 수 있습니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"try:\n",
|
|
" from rapidfuzz import process, fuzz\n",
|
|
"except ImportError:\n",
|
|
" print(\"rapidfuzz is not installed. Please install it with 'pip install rapidfuzz' to use fuzzy matching.\")\n",
|
|
" process = None\n",
|
|
" fuzz = None\n",
|
|
"\n",
|
|
"# Get unique countries\n",
|
|
"unique_countries = dirty_data['country'].unique()\n",
|
|
"\n",
|
|
"# For each country, find similar matches\n",
|
|
"if process is not None and fuzz is not None:\n",
|
|
" print(\"Finding similar country names (similarity > 70%):\")\n",
|
|
" for country in unique_countries:\n",
|
|
" matches = process.extract(country, unique_countries, scorer=fuzz.ratio, limit=3)\n",
|
|
" # Filter matches with similarity > 70 and not identical\n",
|
|
" similar = [m for m in matches if m[1] > 70 and m[0] != country]\n",
|
|
" if similar:\n",
|
|
" print(f\"\\n'{country}' is similar to:\")\n",
|
|
" for match, score, _ in similar:\n",
|
|
" print(f\" - '{match}' (similarity: {score}%)\")\n",
|
|
"else:\n",
|
|
" print(\"Skipping fuzzy matching because rapidfuzz is not available.\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 2. 비정상적인 숫자 값(이상치) 감지\n",
|
|
"\n",
|
|
"`age` 열을 살펴보면 199과 -5 같은 의심스러운 값들이 있습니다. 통계적 방법을 사용하여 이러한 이상치를 감지해 봅시다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Display basic statistics\n",
|
|
"print(\"Age column statistics:\")\n",
|
|
"print(dirty_data['age'].describe())\n",
|
|
"\n",
|
|
"# Identify impossible values using domain knowledge\n",
|
|
"print(\"\\nRows with impossible age values (< 0 or > 120):\")\n",
|
|
"impossible_ages = dirty_data[(dirty_data['age'] < 0) | (dirty_data['age'] > 120)]\n",
|
|
"print(impossible_ages[['customer_id', 'name', 'age']])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### IQR(사분위 범위) 방법 사용\n",
|
|
"\n",
|
|
"IQR 방법은 극단적인 값에 덜 민감한 이상치 탐지에 적합한 강력한 통계 기법입니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Calculate IQR for age (excluding impossible values)\n",
|
|
"valid_ages = dirty_data[(dirty_data['age'] >= 0) & (dirty_data['age'] <= 120)]['age']\n",
|
|
"\n",
|
|
"Q1 = valid_ages.quantile(0.25)\n",
|
|
"Q3 = valid_ages.quantile(0.75)\n",
|
|
"IQR = Q3 - Q1\n",
|
|
"\n",
|
|
"# Define outlier bounds\n",
|
|
"lower_bound = Q1 - 1.5 * IQR\n",
|
|
"upper_bound = Q3 + 1.5 * IQR\n",
|
|
"\n",
|
|
"print(f\"IQR-based outlier bounds for age: [{lower_bound:.2f}, {upper_bound:.2f}]\")\n",
|
|
"\n",
|
|
"# Identify outliers\n",
|
|
"age_outliers = dirty_data[(dirty_data['age'] < lower_bound) | (dirty_data['age'] > upper_bound)]\n",
|
|
"print(f\"\\nRows with age outliers:\")\n",
|
|
"print(age_outliers[['customer_id', 'name', 'age']])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Z-Score 방법 사용\n",
|
|
"\n",
|
|
"Z-Score 방법은 평균에서 표준편차를 기준으로 이상치를 식별합니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"try:\n",
|
|
" from scipy import stats\n",
|
|
"except ImportError:\n",
|
|
" print(\"scipy is required for Z-score calculation. Please install it with 'pip install scipy' and rerun this cell.\")\n",
|
|
"else:\n",
|
|
" # Calculate Z-scores for age, handling NaN values\n",
|
|
" age_nonan = dirty_data['age'].dropna()\n",
|
|
" zscores = np.abs(stats.zscore(age_nonan))\n",
|
|
" dirty_data['age_zscore'] = np.nan\n",
|
|
" dirty_data.loc[age_nonan.index, 'age_zscore'] = zscores\n",
|
|
"\n",
|
|
" # Typically, Z-score > 3 indicates an outlier\n",
|
|
" print(\"Rows with age Z-score > 3:\")\n",
|
|
" zscore_outliers = dirty_data[dirty_data['age_zscore'] > 3]\n",
|
|
" print(zscore_outliers[['customer_id', 'name', 'age', 'age_zscore']])\n",
|
|
"\n",
|
|
" # Clean up the temporary column\n",
|
|
" dirty_data = dirty_data.drop('age_zscore', axis=1)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### 이상치 처리\n",
|
|
"\n",
|
|
"이상치를 감지한 후에는 여러 가지 방법으로 처리할 수 있습니다:\n",
|
|
"1. **제거**: 오류인 경우 이상치가 포함된 행을 삭제\n",
|
|
"2. **캡**: 경계값으로 대체\n",
|
|
"3. **NaN으로 대체**: 누락된 데이터로 간주하고 대체 기법을 사용\n",
|
|
"4. **유지**: 정당한 극단값인 경우 그대로 유지\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Create a cleaned version by replacing impossible ages with NaN\n",
|
|
"dirty_data['age_clean'] = dirty_data['age'].apply(\n",
|
|
" lambda x: np.nan if (x < 0 or x > 120) else x\n",
|
|
")\n",
|
|
"\n",
|
|
"print(\"Age column before and after cleaning:\")\n",
|
|
"print(dirty_data[['customer_id', 'name', 'age', 'age_clean']])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 3. 유사한 행 감지\n",
|
|
"\n",
|
|
"우리 데이터셋에는 \"John Smith\"에 대한 여러 항목이 약간 다른 값으로 포함되어 있는 것을 볼 수 있습니다. 이름의 유사성을 기준으로 잠재적인 중복 항목을 식별해 봅시다.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# First, let's look at exact name matches (ignoring extra whitespace)\n",
|
|
"dirty_data['name_normalized'] = dirty_data['name'].str.strip().str.lower()\n",
|
|
"\n",
|
|
"print(\"Checking for duplicate names:\")\n",
|
|
"duplicate_names = dirty_data[dirty_data.duplicated(['name_normalized'], keep=False)]\n",
|
|
"print(duplicate_names.sort_values('name_normalized')[['customer_id', 'name', 'age', 'country']])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### 퍼지 매칭을 사용한 유사 항목 찾기\n",
|
|
"\n",
|
|
"더 정교한 중복 탐지를 위해 퍼지 매칭을 사용하여 유사한 이름을 찾을 수 있습니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"try:\n",
|
|
" from rapidfuzz import process, fuzz\n",
|
|
"\n",
|
|
" # Function to find potential duplicates\n",
|
|
" def find_near_duplicates(df, column, threshold=90):\n",
|
|
" \"\"\"\n",
|
|
" Find near-duplicate entries in a column using fuzzy matching.\n",
|
|
" \n",
|
|
" Parameters:\n",
|
|
" - df: DataFrame\n",
|
|
" - column: Column name to check for duplicates\n",
|
|
" - threshold: Similarity threshold (0-100)\n",
|
|
" \n",
|
|
" Returns: List of potential duplicate groups\n",
|
|
" \"\"\"\n",
|
|
" values = df[column].unique()\n",
|
|
" duplicate_groups = []\n",
|
|
" checked = set()\n",
|
|
" \n",
|
|
" for value in values:\n",
|
|
" if value in checked:\n",
|
|
" continue\n",
|
|
" \n",
|
|
" # Find similar values\n",
|
|
" matches = process.extract(value, values, scorer=fuzz.ratio, limit=len(values))\n",
|
|
" similar = [m[0] for m in matches if m[1] >= threshold]\n",
|
|
" \n",
|
|
" if len(similar) > 1:\n",
|
|
" duplicate_groups.append(similar)\n",
|
|
" checked.update(similar)\n",
|
|
" \n",
|
|
" return duplicate_groups\n",
|
|
"\n",
|
|
" # Find near-duplicate names\n",
|
|
" duplicate_groups = find_near_duplicates(dirty_data, 'name', threshold=90)\n",
|
|
"\n",
|
|
" print(\"Potential duplicate groups:\")\n",
|
|
" for i, group in enumerate(duplicate_groups, 1):\n",
|
|
" print(f\"\\nGroup {i}:\")\n",
|
|
" for name in group:\n",
|
|
" matching_rows = dirty_data[dirty_data['name'] == name]\n",
|
|
" print(f\" '{name}': {len(matching_rows)} occurrence(s)\")\n",
|
|
" for _, row in matching_rows.iterrows():\n",
|
|
" print(f\" - Customer {row['customer_id']}: age={row['age']}, country={row['country']}\")\n",
|
|
"except ImportError:\n",
|
|
" print(\"rapidfuzz is not installed. Skipping fuzzy matching for near-duplicates.\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### 중복 처리\n",
|
|
"\n",
|
|
"중복을 확인한 후에는 이를 어떻게 처리할지 결정해야 합니다:\n",
|
|
"1. **첫 번째 항목 유지**: `drop_duplicates(keep='first')` 사용\n",
|
|
"2. **마지막 항목 유지**: `drop_duplicates(keep='last')` 사용\n",
|
|
"3. **정보 집계**: 중복된 행의 정보를 결합\n",
|
|
"4. **수동 검토**: 사람이 직접 검토하도록 표시\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Example: Remove duplicates based on normalized name, keeping first occurrence\n",
|
|
"cleaned_data = dirty_data.drop_duplicates(subset=['name_normalized'], keep='first')\n",
|
|
"\n",
|
|
"print(f\"Original dataset: {len(dirty_data)} rows\")\n",
|
|
"print(f\"After removing name duplicates: {len(cleaned_data)} rows\")\n",
|
|
"print(f\"Removed: {len(dirty_data) - len(cleaned_data)} duplicate rows\")\n",
|
|
"\n",
|
|
"print(\"\\nCleaned dataset:\")\n",
|
|
"print(cleaned_data[['customer_id', 'name', 'age', 'country_clean']])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 요약: 완전한 데이터 정리 파이프라인\n",
|
|
"\n",
|
|
"이제 모든 것을 종합하여 포괄적인 정리 파이프라인을 만들어 봅시다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def clean_dataset(df):\n",
|
|
" \"\"\"\n",
|
|
" Comprehensive data cleaning function.\n",
|
|
" \"\"\"\n",
|
|
" # Create a copy to avoid modifying the original\n",
|
|
" cleaned = df.copy()\n",
|
|
" \n",
|
|
" # 1. Standardize categorical values (country)\n",
|
|
" country_mapping = {\n",
|
|
" 'usa': 'USA', 'u.s.a': 'USA', 'united states': 'USA',\n",
|
|
" 'uk': 'UK', 'united kingdom': 'UK',\n",
|
|
" 'canada': 'Canada', 'mexico': 'Mexico'\n",
|
|
" }\n",
|
|
" cleaned['country'] = cleaned['country'].str.lower().map(country_mapping)\n",
|
|
" \n",
|
|
" # 2. Clean abnormal age values\n",
|
|
" cleaned['age'] = cleaned['age'].apply(\n",
|
|
" lambda x: np.nan if (x < 0 or x > 120) else x\n",
|
|
" )\n",
|
|
" \n",
|
|
" # 3. Remove near-duplicate names (normalize whitespace)\n",
|
|
" cleaned['name'] = cleaned['name'].str.strip()\n",
|
|
" cleaned = cleaned.drop_duplicates(subset=['name'], keep='first')\n",
|
|
" \n",
|
|
" return cleaned\n",
|
|
"\n",
|
|
"# Apply the cleaning pipeline\n",
|
|
"final_cleaned_data = clean_dataset(dirty_data)\n",
|
|
"\n",
|
|
"print(\"Before cleaning:\")\n",
|
|
"print(f\" Rows: {len(dirty_data)}\")\n",
|
|
"print(f\" Unique countries: {dirty_data['country'].nunique()}\")\n",
|
|
"print(f\" Invalid ages: {((dirty_data['age'] < 0) | (dirty_data['age'] > 120)).sum()}\")\n",
|
|
"\n",
|
|
"print(\"\\nAfter cleaning:\")\n",
|
|
"print(f\" Rows: {len(final_cleaned_data)}\")\n",
|
|
"print(f\" Unique countries: {final_cleaned_data['country'].nunique()}\")\n",
|
|
"print(f\" Invalid ages: {((final_cleaned_data['age'] < 0) | (final_cleaned_data['age'] > 120)).sum()}\")\n",
|
|
"\n",
|
|
"print(\"\\nCleaned dataset:\")\n",
|
|
"print(final_cleaned_data[['customer_id', 'name', 'age', 'country', 'purchase_amount']])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 🎯 도전 과제\n",
|
|
"\n",
|
|
"이제 여러분의 차례입니다! 아래는 여러 품질 문제가 있는 새로운 데이터 행입니다. 여러분은 다음을 수행할 수 있나요?\n",
|
|
"\n",
|
|
"1. 이 행에서 모든 문제를 식별하기\n",
|
|
"2. 각 문제를 정리하는 코드를 작성하기\n",
|
|
"3. 정리된 행을 데이터셋에 추가하기\n",
|
|
"\n",
|
|
"다음은 문제가 있는 데이터입니다:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# New problematic row\n",
|
|
"new_row = pd.DataFrame({\n",
|
|
" 'customer_id': [13],\n",
|
|
" 'name': [' Diana Prince '], # Extra whitespace\n",
|
|
" 'age': [250], # Impossible age\n",
|
|
" 'country': ['U.S.A.'], # Inconsistent format\n",
|
|
" 'purchase_amount': [150.00]\n",
|
|
"})\n",
|
|
"\n",
|
|
"print(\"New row to clean:\")\n",
|
|
"print(new_row)\n",
|
|
"\n",
|
|
"# TODO: Your code here to clean this row\n",
|
|
"# Hints:\n",
|
|
"# 1. Strip whitespace from the name\n",
|
|
"# 2. Check if the name is a duplicate (Diana Prince already exists)\n",
|
|
"# 3. Handle the impossible age value\n",
|
|
"# 4. Standardize the country name\n",
|
|
"\n",
|
|
"# Example solution (uncomment and modify as needed):\n",
|
|
"# new_row_cleaned = new_row.copy()\n",
|
|
"# new_row_cleaned['name'] = new_row_cleaned['name'].str.strip()\n",
|
|
"# new_row_cleaned['age'] = np.nan # Invalid age\n",
|
|
"# new_row_cleaned['country'] = 'USA' # Standardized\n",
|
|
"# print(\"\\nCleaned row:\")\n",
|
|
"# print(new_row_cleaned)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### 주요 요점\n",
|
|
"\n",
|
|
"1. **일관되지 않은 카테고리**는 실제 데이터에서 흔히 발생합니다. 고유 값을 확인하고 매핑 또는 퍼지 매칭을 사용하여 표준화하세요.\n",
|
|
"\n",
|
|
"2. **이상치**는 분석에 큰 영향을 미칠 수 있습니다. 도메인 지식과 통계적 방법(IQR, Z-점수)을 결합하여 이상치를 감지하세요.\n",
|
|
"\n",
|
|
"3. **유사 중복 데이터**는 정확히 중복된 데이터보다 감지하기 어렵습니다. 퍼지 매칭을 사용하고 데이터를 정규화(소문자 변환, 공백 제거)하여 이를 식별하는 것을 고려하세요.\n",
|
|
"\n",
|
|
"4. **데이터 정제는 반복적**입니다. 여러 기술을 적용하고 결과를 검토한 후에 최종적으로 정제된 데이터를 확정해야 할 수도 있습니다.\n",
|
|
"\n",
|
|
"5. **결정을 문서화하세요**. 어떤 정제 단계를 적용했는지와 그 이유를 기록하세요. 이는 재현성과 투명성을 위해 중요합니다.\n",
|
|
"\n",
|
|
"> **최고의 실천 방법:** 항상 원본 \"더러운\" 데이터를 복사해 두세요. 소스 데이터 파일을 덮어쓰지 말고 `data_cleaned.csv`와 같은 명확한 이름 규칙을 사용하여 정제된 버전을 만드세요.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**면책 조항**: \n이 문서는 AI 번역 서비스 [Co-op Translator](https://github.com/Azure/co-op-translator)를 사용하여 번역되었습니다. 정확성을 위해 최선을 다하고 있으나, 자동 번역에는 오류나 부정확성이 포함될 수 있습니다. 원본 문서의 원어 버전을 권위 있는 자료로 간주해야 합니다. 중요한 정보의 경우, 전문적인 인간 번역을 권장합니다. 이 번역 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 당사는 책임을 지지 않습니다.\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"anaconda-cloud": {},
|
|
"colab": {
|
|
"name": "notebook.ipynb",
|
|
"provenance": []
|
|
},
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.5.4"
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "6301339d1c9a301b00639c635dc9b731",
|
|
"translation_date": "2025-10-03T19:32:10+00:00",
|
|
"source_file": "2-Working-With-Data/08-data-preparation/notebook.ipynb",
|
|
"language_code": "ko"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 0
|
|
} |