DTS: Outlier detection02

§ 결측치 찾기 이론

§ 결측치 찾기 실습

§ 변수 1개를 이용하여 이상값 찾기

§ 변수 2개를 이용하여 이상값 찾기

§ data 출처

이상값 찾기

  • 서로 겹치는 값이 있거나, 한 변수의 범주거나 연속일 경우

  • 수치형 데이터에 대한 상관행렬

    1
    2
    # 상관관계 확인
    covidtotals.corr(method = "pearson")
  • corr <|0.2| : 약한 상관관계

  • corr < |0.3~0.6| : 중간정도의 상관관계

  • 상관관계를 확인 할 수 있다.

crosstab

  • 총 사망자 분위수별 총 확진자 분위수의 크로스 탭 표시
    • case: 확진자수
    • deaths: 사망자 수
1
2
pd.crosstab(covidtotalsonly["total_cases_q"], 
covidtotalsonly["total_deaths_q"])

Outlier_crosstab

  • 매우 낮은 수로 사망 했지만, 확진이 중간 = 이상치
1
2
covidtotals.loc[(covidtotalsonly["total_cases_q"]== "very high")
& (covidtotalsonly["total_deaths_q"]== "medium")].T
1
2
3
4
5
6
7

fig, ax = plt.subplots()
sns.regplot(x = "total_cases_pm", y = "total_deaths_pm", data = covidtotals, ax = ax)
ax.set(xlabel = "Cases Per Million", ylabel = "Deaths Per Million", title = "Total Covid Cases and Deaths per Million by Country")
ax.ticklabel_format(axis = "x", useOffset=False, style = "plain")
plt.xticks(rotation=90)
plt.show()

Outlier_regplot

DTS: Missing Value detection(02)

§ 결측치 찾기 이론

§ 결측치 찾기 실습

§ 변수 1개를 이용하여 이상값 찾기

§ 변수 2개를 이용하여 이상값 찾기

Ref.01


data in Kaggle

note를 public으로 올려는 놨는데 검색이 될까 모르겠네요.

Missing Value : 결측치 확인

data Loading

1
2
3
import pandas as pd
covidtotals = pd.read_csv("../input/covid-data/covidtotals.csv")
covidtotals.head()

MissingValue_covidtotals

data info

1
covidtotals.info()

MissingValue_covid_info

data division

  • 인구통계 관련 column
  • Covid 관련 column
1
2
case_vars = ["location", "total_cases", "total_deaths", "total_cases_pm", "total_deaths_pm"]
demo_vars = ["population", "pop_density", "median_age", "gdp_per_capita", "hosp_beds"]

demo_vars column별로 결측치를 측정

1
covidtotals[demo_vars].isnull().sum(axis = 0) # column별로 결측치를 측정

MissingValue_covid_isnullsum

case_vars column별로 결측치를 측정

1
covidtotals[case_vars].isnull().sum(axis = 0) # column별로 결측치를 측정

MissingValue_covid_nullSum

  • case_vars 에는 결측치가 없지만, demo_vars에는 결측치가 있는 것을 확인 할 수 있다.
pop_density 12
median_age 24
gdp_per_capita 28
hosp_beds 46

위의 column들에 각각 수만큼의 결측치를 확인 할 수 있다.

행 방향으로 발생한 결측치 확인

1
2
demovars_misscnt = covidtotals[demo_vars].isnull().sum(axis = 1)
demovars_misscnt.value_counts()

0 156

1 24
2 12
3 10
4 8
dtype: int64

1
covidtotals[case_vars].isnull().sum(axis = 1).value_counts()

0 210
dtype: int64

인구통계 데이터가 3가지 이상 누락된 국가를 나열하기

1
2
3
["location"] + demo_vars
covidtotals.loc[demovars_misscnt >= 3, ["location"] + demo_vars].T

MissingValue_covid_Location

case에는 누락국가가 없지만, 그냥 한번 확인

1
2
casevars_misscnt = covidtotals[case_vars].isnull().sum(axis = 1)
casevars_misscnt.value_counts()

0 210
dtype: int64

1
covidtotals[covidtotals['location'] == "Hong Kong"]
1
2
3
4
5
6
temp = covidtotals.copy()
temp[case_vars].isnull().sum(axis = 0)
temp.total_cases_pm.fillna(0, inplace = True)
temp.total_deaths_pm.fillna(0, inplace = True)
temp[case_vars].isnull().sum(axis = 0)

MissingValue_covid_Del


이건 잘 모르겠다. 그냥 삭제 할 수 있다.

DTS: Missing Value detection(01)

§ 결측치 찾기 이론

§ 결측치 찾기 실습

§ 변수 1개를 이용하여 이상값 찾기

§ 변수 2개를 이용하여 이상값 찾기

Ref.01


Missing Value : 결측치

  1. 정의 :
    1. Missing Feature(누락 data) 를 처리 해주어야 ML이 잘 돌아 간다.
    2. Na, Nan 과 같은 값
  2. 종류 :
    1. Random : 패턴이 없는 무작위 값
    2. No Random : 패턴을 가진 결측치




Deletion

  • deletion해서 특성이 바뀌지 않는다면, 가장 좋은 방법
    • dropna()
    • axis = (0 : 행 제거, default),(1: 열제거)
    • subset = (특정 feature을 지정하여 해당 누락 data 제거)
  • Listwist(목록삭제)
    • 결측치가 있는 행 전부 삭제
  • pairwise(단일 값 삭제)

1
2
3
4
5
df = df.dropna() # 결측치 있는 행 전부 삭제
df = df.dropna(axis = 1) # 결측치 있는 열 전부 삭제

df = df.dropna(how = 'all') # 전체가 결측인 행 삭제
df = df.dropna(thresh = 2) # threshold 2, 결측치 2초과 삭제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
df = df.dropna(subset=['col1', 'col2', 'col3'])

# 특정열 모두가 결측치일 경우 해당 행 삭제
df = df.dropna(subset=['col1', 'col2', 'col3'], how = 'all')

# 특정열에 1개 초과의 결측치가 있을 경우 해당 행 삭제
df = df.dropna(subset=['col1', 'col2', 'col3'], thresh = 1 )

#바로 적용
df.dropna(inplace = True)
```

<br><br>

---

### Imputation
1. 결측치를 특정 값으로 대치
- mode : 최빈값
+ 번주형, 빈도가 제일 높은값으로 대치
- median : 중앙값
+ 연속형, 결측값을 제외한 중앙값으로 대치
- mean : 평균
+ 연속형, 결측값을 제외한 평균으로 대치
- similar case imputation : 조건부 대치
- Generalized imputation : 회귀분석을 이용한 대치
2. 사용함수
- fillna(), replace(), interpolate()

##### fillna() : 0 처리

```python
df.fillna(0)
df[].fillna() : 특정 column만 대치
1
2
3
4
5
# 0으로 대체하기
df['col'] = df['col'].fillna(0)

# 컬럼의 평균으로 대체하기
df['col'] = df['col'].fillna(df['col'].mean())
1
2
3
4
5
# 바로 위의 값으로 채우기
df.fillna(method = 'pad')

#바로 아래 값으로 채우기
df.fillna(method='bfill')
replace()
1
2
#  대체, 결측치가 있으면, -50으로 채운다.
df.replace(to_replace = np.nan, value = -50)
interpolate()
  • 만약, 값들이 선형적이라추정 후 간격으로 처리
1
df.interpolate(method = 'linear' , limit_direction = 'forward')
  1. prediction Model (예측모델)

    • 결측치가 pattern을 가진다고 가정하고 진행.
    • 결측값이 없는 컬럼들로 구성된 dataset으로 예측
    • 회기분석기술 혹은 SVM과같은 ML 통계기법이 있다.
  2. guid Line (Missiong Value : MV)

    • MV < 10% : 삭제 or 대치
    • 10% < MV < 50% : regression or model based imputation
    • 50%< MV : 해당 column 제거

DTS: Outlier detection01

§ 결측치 찾기 이론

§ 결측치 찾기 실습

§ 변수 1개를 이용하여 이상값 찾기

§ 변수 2개를 이용하여 이상값 찾기


이상값 찾기

  • 주관적이며 연구자 마다 다르고, 산업에 따라 차이가 있다.
  • 통계에서의 이상값
    • 정규 분포를 이루고 있지 않음 : 이상값이 존재
    • 왜도, 첨도가 발생.
  • 균등분포(Uniform distribution)
1. 변수 1개를 이용하여 이상값 찾기 
1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import statsmodels.api as sm # 검정 확인을 위한 그래프
import scipy.stats as scistat #샤피로 검정을 위한 Library

covidtotals = pd.read_csv("../input/covid-data/covidtotals.csv")
covidtotals.set_index("iso_code", inplace = True)

case_vars = ["location", "total_cases", "total_deaths", "total_cases_pm", "total_deaths_pm"]
demo_vars = ["population", "pop_density", "median_age", "gdp_per_capita", "hosp_beds"]

covidtotals.head()

covidtotals_Kg

  • 결측치와 마찬가지로 covidtotals data를 kaggle note에 불러와서 실행




백분위수(quantile)로 데이터 표시

  • 판다스 내부의 함수를 이용하여 확인한다.
1
2
3
4
5
covid_case_df = covidtotals.loc[:, case_vars]
covid_case_df.describe

covid_case_df.quantile(np.arange(0.0, 1.1, 0.1))
#Index이기 때문에 1.1로 표시

outlier_quantile



왜도(대칭 정도), 첨도(뾰족한 정도) 구하기

  • 역시 pandas 함수를 이용.


  • 들어가기 전에

Futrue_warring

pandas.DataFrame.skew

  • 위와 같은 Warring Error가 발생 하면, 구글링을 통해 처리 할 수 있어야 한다.


왜도 구하기

1
covid_case_df.skew(axis=0, numeric_only = True)

total_cases 10.804275

total_deaths 8.929816

total_cases_pm 4.396091

total_deaths_pm 4.674417

dtype: float64

  • -1~1사이에 있어야 대칭이다.
  • skewness < |3| : 기본적 허용
  • 대칭이 아닌 것을 알 수 있다.
    (

    = 정규분포가 아니다.

    )




첨도 구하기

  • 정규 분포의 첨도는 0이다.
    • 0보다 크면 더 뾰족하고
    • 0보다 작으면 뭉툭하다.
1
2
#첨도 구하기 
covid_case_df.kurtosis(axis=0, numeric_only = True)

total_cases 134.979577

total_deaths 95.737841

total_cases_pm 25.242790

total_deaths_pm 27.238232

dtype: float64


  • 5~10 정도 사이에 첨도가 있어야 하는데 정규분포를 이루고 있지 않다.
    • kurtosis < |7| : 기본적 허용
  • (

    = 정규분포가 아니다.

    )
    • 이산값이 있을 확률이 높다는 것을 알 수 있다.



정규성 검정 테스트

  1. 정규성 가정을 검토하는 방법
    1. Q-Q plot
      1. 그래프로 정규성 확인
        • 눈으로 보는 것이기 때문에 해석이 주관적.
    2. Shapiro-Wilk Test (샤피로-윌크 검정)
      • 귀무가설 : 표본의 모집단이 정규 분포를 이루고 있다. (H0: 정규분포를 따른다 p-value > 0.05)
      • 대립가설 : 표본의 모집단이 정규 분포를 이루고 있지 않다.
      • p value < 0.05 : 귀무가설을 충족하지 않아 대립가설로
    3. Kolnogorov-Smirnov test (콜모고로프-스미노프 검정)
      1. EDF(Empirical distribution fuction)에 기반한 적합도 검정방법
      • 자료의 평균/표준편차, Histogram을 통해 표준 정규분포와 비교하여 적합도 검정.
      • p value > 0.05 : 정규성 가정



Shapiro-Wilk Test

1
2
# 샤피로 검정
scistat.shapiro(covid_case_df['total_cases'])

ShapiroResult(statistic=0.19379639625549316, pvalue=3.753789128593843e-29)

  • 우리는 p value 를 가지고 유의성을 확인한다.
  • p value : 3.75e-29 이므로 정규분포를 이루지 않음.

covid_case_df[‘total_cases’] 안에 아래 column들을 하나씩 다 넣어 봐야 한다.

1
2
case_vars = ["location", "total_cases", "total_deaths", "total_cases_pm", "total_deaths_pm"]
demo_vars = ["population", "pop_density", "median_age", "gdp_per_capita", "hosp_beds"]
  • 함수를 짜면 너의 code가 될 것이라고 한다.



qqplot

  • 통계적 이상값 범위 : 1사분위 (25%), 3사분위(75%) 사이의 거리
    • 그 거리가 상하좌우 1.5배를 넘으면 이상값으로 여김
1
2
3
sm.qqplot(covid_case_df[["total_cases"]].sort_values(
["total_cases"]), line = 's')
plt.title("Total Class")

outlier_qqplot_1



1
2
3
4
5
6
7
8
thirdq = covid_case_df["total_cases"].quantile(0.75)
firstq = covid_case_df["total_cases"].quantile(0.25)

interquantile_range = 1.5 * (thirdq- firstq)
outlier_high = interquantile_range + thirdq
outliner_low = firstq - interquantile_range

print(outliner_low, outlier_high, sep = " <-------> ")

-14736.125 <——-> 25028.875



이상치를 제거한 data 가져오기

  1. 조건: outlier_high 보다 높은 이상치 or outlier_low 보다 낮은 이상치
1
2
remove_outlier_df = covid_case_df.loc[~(covid_case_df["total_cases"]>outlier_high)|(covid_case_df["total_cases"]<outliner_low)]
remove_outlier_df.info()

Outlier_removedDT




  • 이상치 data
1
2
remove_outlier_df = covid_case_df.loc[(covid_case_df["total_cases"]>outlier_high)|(covid_case_df["total_cases"]<outliner_low)]
remove_outlier_df.info()

Outlier_DT.png


outlier_qqplot_2

1
2
3
4
5
6
7
8
9
10
fig, ax = plt.subplots(figsize = (16, 6), ncols = 2)
ax[0].hist(covid_case_df["total_cases"]/1000, bins = 7)
ax[0].set_title("Total Covid Cases (thousands) for all")
ax[0].set_xlabel("Cases")
ax[0].set_ylabel("Number of Countries")
ax[1].hist(remove_outlier_df["total_cases"]/1000, bins = 7)
ax[1].set_title("Total Covid Cases (thousands) for removed outlier")
ax[1].set_xlabel("Cases")
ax[1].set_ylabel("Number of Countries")
plt.show()

img.png

  • 완벽하진 않지만, 먼 잔차들을 제거한 정규 분포를 이루는 듯한 그래프를 얻을 수 있었다.
  • 이를 train data에 EDA로 돌리고, ML을 진행 하면 더 좋은 score를 얻을 수도 있고, 아닐 수도 있다.
  • just Test