qcoding

[데이터 분석 시 유용한 기능 정리] - 필요부분 검색 본문

Python 데이터분석

[데이터 분석 시 유용한 기능 정리] - 필요부분 검색

Qcoding 2023. 12. 6. 14:22
반응형

* 참고자료 : https://github.com/rickiepark/handson-ml3/blob/main/02_end_to_end_machine_learning_project.ipynb

 

1) 데이터 분석 

1-1) 설정 - font 나 기타 설정 관련

-> 그래프 그릴 때 font설정하기

import matplotlib.pyplot as plt

plt.rc('font', size=14)
plt.rc('axes', labelsize=14, titlesize=14)
plt.rc('legend', fontsize=14)
plt.rc('xtick', labelsize=10)
plt.rc('ytick', labelsize=10)

import sys
# 코랩의 경우 나눔 폰트를 설치합니다.
if 'google.colab' in sys.modules:
    !sudo apt-get -qq -y install fonts-nanum
    import matplotlib.font_manager as fm
    font_files = fm.findSystemFonts(fontpaths=['/usr/share/fonts/truetype/nanum'])
    for fpath in font_files:
        fm.fontManager.addfont(fpath)

# 나눔 폰트를 사용합니다.
import matplotlib 

matplotlib.rc('font', family='NanumBarunGothic')
matplotlib.rcParams['axes.unicode_minus'] = False

 

 

1-2) Colab에서 실제파일이나 url에 있을 때 파일 불러오기 (tgz -> csv로 압출 풀어서 풀러오기)

-> 파일이나 url에 있을 경우 받아서 압출풀어서 dataframe으로 불러옴

from pathlib import Path
import pandas as pd
import tarfile
import urllib.request

def load_housing_data(): 
    tarball_path = Path("datasets/housing.tgz")  ### 이미 파일이 해당 경로에 있을경우 
    if not tarball_path.is_file(): ## 파일 없을때 
        Path("datasets").mkdir(parents=True, exist_ok=True) ## 경로에 폴더 추가함
        url = "https://github.com/ageron/data/raw/main/housing.tgz" ## url을 통해서
        urllib.request.urlretrieve(url, tarball_path) ## tgz 파일을 받아옴
        with tarfile.open(tarball_path) as housing_tarball: ## tgz 파일을 열어서 불러옴
            housing_tarball.extractall(path="datasets") ## datasets 폴더에 압축을 품 
    return pd.read_csv(Path("datasets/housing/housing.csv")) ### 해당 path에 csv 파일을 불러옴

housing = load_housing_data()

 

 

 

1-3) 필터링

-> null 값이 있는 row를 조회 시 사용함.

df.loc[df.isnull().any(axis=1)]

-> null 값이 있는 columns 조회시 사용함.

df.columns[df.isnull().any()]

 

 

-> value_counts bins 사용 -> 범위별로 데이터를 count 할 수 있음

df['total_bill'].value_counts(bins=5)

 

-> 동일한 데이터 타입의 컬럼만 선택하기

수치형 / 범주형의 데이터를 분류할 때 유용하게 사용할 수 있음

위의 데이터 형태를 가질 때 incldue안에는 포함해야 되는 데이터 타입을 쓰고

df.select_dtypes(include=['float','int']).columns

 

exclude에는 포함하지 말아야 될 데이터 타입을 써준다.

df.select_dtypes(exclude=['float','int']).columns

 

 

 

-> 특정 문자가 포함된 데이터 필터링 하기

특정 칼럼내에 특정 문자가 포함되어 있는 지 여부를 확인하여 필터링함.

df_len = len(df)

df_fil = df.loc[df['time'].str.contains('Di')] ### 특정 문자를 포함하여 필터링

df_fil_len = len(df_fil)

print(df_len, df_fil_len)

df_fil.head(5)

 

 

-> 결측값 채우기

보통 fillna를 이용하여 결측값을 채운다. interpolation을 사용해서 채우는 채울 수 있음.

### 수치형 - interpolation
df['age']=df['age'].interpolate(method='linear',limit_direction='forward')  ## linear
df['age']=df['age'].interpolate(method='nearest',limit_direction='forward')  ## nearest

### 범주형 - interpolation
df['deck']=df['deck'].interpolate(method='pad',limit_direction='forward') ## pad 는 fillna의 'ffill'과 동일함, 앞의 값으로 채움

 

 

-> map / apply 사용법

① map ( 단일 칼럼 )

### 1) custom 함수 사용
def chk_male(val):
  if val == "Male":
    return 1
  elif val =="Female":
    return 0

df['smoker_value_1'] = df['sex'].map(chk_male)
df['smoker_value_2'] = df['sex'].map({"Male":1 , "Female":0})

### 2) lambda 함수 사용
df['smoker_value_3'] = df['sex'].map(lambda val:1 if val=='Male' else 0)

 

② apply (단일 & 여러개 칼럼 사용가능)

#### 1) custom 함수 
def chk_male_smoker(row,weights_):
  if row['sex']=="Male" and row['smoker']=='Yes':
    return 1 * weights_
  else:
    return 0

weights_ = 2
df['male_smoker_value_1'] = df.apply(chk_male_smoker, args=(weights_,) ,axis=1) ########### 여기서 args = (,) comma 써줘야함!!!


#### 2) lambda 함수
df['male_smoker_value_2'] = df.apply(lambda row, weights_: 1 * weights_ if row['sex'] == 'Male' and row['smoker'] == 'Yes' else 0, args=(weights_,), axis=1)



### 3) return 2개 이상일 때 

def chk_male_smoker(row,weights_):
  if row['sex']=="Male" and row['smoker']=='Yes':
    return 1 * weights_ , 1
  else:
    return 0 , 0 

weights_ = 2
df[['male_smoker_value_3','male_smoker_value_4']] = df.apply(chk_male_smoker, args=(weights_,) ,axis=1, result_type='expand') ########### 여기서 args = (,) comma 써줘야함!!!

 

 

 

 

 

1-4) group by 사용시 2가지 방법

### transform을 활용하여 기존의 dataFrame에 필요한 항목을 추가하는 것 

import numpy as np

#### transform 활용하여 기존의 df에 이어붙임
df['ocean_proximity'].value_counts()

### ocean 등급에 따른 소유주의 나이 평균
# df['age_avg_by_ocean_proxi'] = df.groupby(['ocean_proximity'])['housing_median_age'].transform('mean')
df['age_avg_by_ocean_proxi'] = df.groupby(['ocean_proximity'])['housing_median_age'].transform(lambda x:np.mean(x))
df

위에서 lambda 함수를 사용가능함.

 

### group이라는 새로운 data frame을 만들고 기존 dataframe에 merge함

1) group dataframe 생성

### 새로운 dataFrame 생성
group = df.groupby(['ocean_proximity'], as_index=False).agg(
    # mean_avg = ('housing_median_age', lambda x:np.mean(x))
    mean_avg = ('housing_median_age', 'mean')
)
group

 

여기서도 lambda 함수 사용가능함.

2) 기존 dataframe에 merge

-> 위의 group에 있는 mean_avg 이름으로 합쳐

### group 된거 원래 dataFrame으로 merge
df_merge = df.merge(group, how='left', on=['ocean_proximity'])
df_merge

 

 

 

1-5)  분포가 많은 수치형 변수의 경우 몇개 형태의 범주형 데이터로 처리하는 법

-> qcut / cut을 사용해서 몇개의 범주로 바꿔줌.

## cut 은 내가 범위를 지정하고 그 범위에 맞게 그륩핑해

housing["income_cat"] = pd.cut(housing["median_income"],
                               bins=[0., 1.5, 3.0, 4.5, 6., np.inf],
                               labels=[1, 2, 3, 4, 5])
housing["income_cat"].value_counts().sort_index(ascending=False)
sns.histplot(x='income_cat', data=housing)

 

 

## qcut 은 범위는 알아서 정해지고, 각 label에 수량이 비슷하게 나눠짐

housing["income_cat"] = pd.qcut(housing["median_income"],5,labels=[1, 2, 3, 4, 5])
housing["income_cat"].value_counts().sort_index(ascending=False)
sns.histplot(x='income_cat', data=housing)

 

 

1-6) pivot table

-> pivot table을 사용할 때, values / index / columns에 여러개의 값을 넣을 수 있음 

aggfunc의 기본은 mean값으로 나타내는 데 aggfunc= count / mean/ max 등을 사용하여 값을 바꿀 수 있음.

margins= True를 하면 전체 ALL의 합계를 집계해줌.

df.pivot_table(values=['survived','fare'],
               index='sex',
               columns='pclass',
               aggfunc={'survived':np.mean, 'fare':np.sum},
               fill_value=0,
               margins=True)

 

1-7) 시간 데이터 사용할 때

-> 아래와 같이 year, month, day가 따로 있을 때 결합할 수 있음.

    이때 year / month / day가 다 있어야 에러가 안나고 합칠 수 있음.

## day가 없을 경우 임의로 day 값을 넣어줌
## df['day'] = 1
df['date'] = pd.to_datetime(df[['year','month','day']])
df['date_month'] = df.apply(lambda row:str(row['year'])+"-"+str(row['month']),axis=1)
df['date_fil'] = pd.to_datetime(df['date_month'])

위와 같이 apply를 써서 문자열 형태로 합칠 수 있음. 이 경우에 datetime을 사용하면 day값이 자동으로 1이 입력됨

 

2) 그래프 

2-1) 상관관계 그래프 (Scatter matrix) 빨리 그리기

-> Corr를 이용하여 상관관계 그래프를 빨리 그리는 법 / 우리가 원하는 label에 대한 값을 넣어줌 

corr_matrix = df.corr(numeric_only=True)
corr_matrix['median_house_value'].sort_values(ascending=False)

 

from pandas.plotting import scatter_matrix
import matplotlib.pyplot   as plt

scatter_matrix(df[corr_matrix['median_house_value'].sort_values(ascending=False).index[1:5]],figsize=(12,8))
plt.show()

 

 

2-2) 그래프 저장하기 png 파일 

--> save fig 함수를 이용하여 해당 위치 아래에 foler를 생성한 후 이미지 저장하기

def save_fig(fig_id, fig, tight_layout=True, fig_extension="png", resolution=300):
    IMAGES_PATH = Path("images/this_save_path") #### 여기에 save 할 위치 지정함
    IMAGES_PATH.mkdir(parents=True, exist_ok=True)

    path = IMAGES_PATH / f"{fig_id}.{fig_extension}"
    
    if tight_layout:
        fig.tight_layout()

    # Save the figure using the specified axis
    fig.savefig(path, format=fig_extension, dpi=resolution)

위의 함수 사용 시 아래와 같이 subplots의 여러개 여부와 관계없이 fig를 넘겨서 저장함.

from pathlib import Path
import matplotlib.pyplot as plt
from pandas.plotting import scatter_matrix


# Assuming df and corr_matrix are defined earlier in your code
fig, axes = plt.subplots(nrows=2,ncols=1)
fig.set_size_inches(6, 3)

# scatter_matrix(df[corr_matrix['median_house_value'].sort_values(ascending=False).index[1:5]], ax=ax)
sns.scatterplot(x='longitude', y='latitude', data=df , ax=axes[0])
sns.barplot(x=df.index,y='ocean_proximity', data=df, ax=axes[1])


# Save the figure using the custom function
save_fig('subplots', fig)

 

 

2-3) 상관관계 그래프 예쁘게 그리기

fig, ax =plt.subplots()

housing.plot(kind="scatter", x="longitude", y="latitude", grid=True,
             s=housing["population"] / 100, label="population",
             c="median_house_value", cmap="jet", colorbar=True,
             legend=True, figsize=(10, 7),ax=ax)
save_fig("housing_prices_scatterplot",fig)  # extra code
plt.show()

import seaborn as sns
from pathlib import Path
import matplotlib.pyplot as plt

# Assuming df is your DataFrame
fig, ax = plt.subplots(figsize=(10, 7))

# Seaborn scatter plot
sns.scatterplot(data=housing, x="longitude", y="latitude", hue="median_house_value",
                size=housing["population"] / 100, sizes=(20, 200), ax=ax)

# Additional settings
ax.set_title("Housing Prices Scatterplot")
ax.grid(True)
# ax.legend()

# Save the figure
save_fig("housing_prices_scatterplot", fig)

# Show the plot
plt.show()

 

2-4) 결측치 시각화하기

-> 결측값을 seaborn을 통해 시각화함. 아래의 그래프에서 하얀색의 부분이 결측값을 나타낸다.

import matplotlib.pyplot as plt
import seaborn as sns

fig, ax = plt.subplots()
fig.set_size_inches(11,3)
fig.patch.set_facecolor('xkcd:white')

### 결측값 시각화
sns.heatmap(df.isnull(),cbar=False)

 

 

3) 모델학습

3-1) 모델 학습 후 predict로 예측하기 전에 cross_val_score를 통해서 훈련 set으로 어느정도 확률인지 개선정도확인

--> cross_val_score를 사용하기 

from sklearn.model_selection import cross_val_score

### 모델 학습
forest_clf = RandomForestClassifier(n_estimators=100, random_state=42)
forest_clf.fit(X_train, y_train)

### y_test 예측
X_test = preprocess_pipeline.transform(test_data)
y_pred = forest_clf.predict(X_test)

#### y_pred는 정답이없으므로 현재 model의 개선 정도를 확인할 때에는
#### 
## 회귀 일때 
forest_scores = cross_val_score(forest_clf, X_train, y_train, cv=10)
forest_scores.mean()

### 분류 일때 
forest_scores=cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring="accuracy")
forest_scores.mean()

 

반응형
Comments