데이터프레임과 시리즈
데이터프레임이란?(Dataframe)
- 데이터 분석에서 가장 중요한 데이터 구조
- 관계형 데이터베이스의 테이블 또는 엑셀 시트와 같은 형태 (2차원 구조)
- 변수들의 집합 → 각 열을 변수라고 부름
시리즈란?(Serise)
- 하나의 정보에 대한 데이터들의 집합
- 데이터 프레임에서 하나의 열을 떼어낸 것.(1차원)
<선언 및 확인>
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import koreanize_matplotlib # 한국어를 사용하게 해줌
import seaborn as sns
import joblib
import warnings
warnings.filterwarnings(action='ignore') # 경고 메시지 무시
%config InlineBackend.figure_format='retina' # 고화질의 결과물 출력
#딕셔너리 생성
dict1 = {'Name': ['Gildong', 'Sarang', 'Jiemae', 'Yeoin'],
'Level': ['Gold', 'Bronze', 'Silver', 'Gold'],
'Score': [56000, 23000, 44000, 52000]}
df = pd.DataFrame(dict1)
# 확인
print(df.head()) #head()안에 숫자가 없으면 기본으로 5가 들어감
display(df)
<데이터 읽어오기>
# 데이터 읽어오기
path ='https://raw.githubusercontent.com/DA4BAM/dataset/master/Attrition_simple2.CSV'
# path = 'airquality_simple.csv'
data = pd.read_csv(path)
# 상위 5개 확인
print(data.head(5))
자주사용하는 메서드( 배열명.메서드() )
- 데이터명.head(): 상위 데이터 확인
- 데이터명.tail(): 하위 데이터 확인
- 데이터명.shape: 데이터프레임 크기
- 데이터명.values: 값 정보 확인(저장하면 2차원 numpy 배열이 됨)
- 데이터명.columns: 열 정보 확인
- 데이터명.columns.values : array 형태로 확
- 데이터명.dtypes: 열 자료형 확인
- 데이터명.info(): 열에 대한 상세한 정보 확인
- 데이터명.describe(): 기초통계정보 확인(count, mean, std, min, 25%, 50%, 75%, max)
- 데이터명.describe().T - 전치행렬로 보기 편해진다.
- 메이터명.corr() : 상관관계를 나타냄
- numeric_only = True을 하면 수치형만 분석해줌
- corr().style.background_gradient() 가독성을 높여줌
- 데이터명.isna() : 결측치 확인
- 데이터명.isna().sum() : NaN데이터가 있는지 확인 (값이 NaN인 데이터를 합쳐서 보여줌)
- 데이터명[데이터명.isnull().any(axis=1)] : 결측치가 있는 행만 확인
- 데이터명.copy() : 깊은복사 (원본을 헤치지 않을때 사용 -> 결과가 맘에들면 다시 원복)
- 데이터명.dropna() : NaN인 애들을 없앰 axis를 지정
- 데이터명.fillna() : Nan인 애들을 값을 지정해서 채움
- 시리즈명.mode() : 최빈값 확인, 시리즈의 형태로 (index 최빈값) 형태
- 시리즈명.fillna( 시리즈명.mode()[0] ) - 다음과 같은 형태를 활용해야 최빈값 지정 가능
- mode()와 mode()[0] 각각 출력해보길 권장
- 시리즈명.ffill() : 변수 NaN 값을 바로 앞의 값으로 채우기
- 시리즈명.bfill() : 변수 NaN 값을 바로 뒤의 값으로 채우기
- 데이터명.drop_duplicates() : 중복된 행을 제거해 줌 ★ ★
- inplace = True,
<단순 조회>
- 데이터명[ '열 이름' ] - 시리즈로 조회
- 데이터명[ [ '열 이름' ] ] - 데이터프레임으로 조회
DF.sort_values
<정렬해서 보기 / 중요!>
- 데이터명.sort_values(by = [ '열1'], ascending = [ True ] )
메소드로 특정 열을 기준으로 정렬한다.
- 데이터명.sort_values(by = [ '열1', '열2' ],ascending = [ True, False ])
다양한 값과 정렬방식 가능
- 데이터명.ascending 옵션을 설정해 오름차순, 내림차순을 설정할 수 있다.
- 데이터명.sort_values( [ '열1'], ascending = [ False ] ) by는 생략할 수 있다.
- ascending=True: 오름차순 정렬(기본값)
- ascending=False: 내림차순 정렬
reset_index
- 데이터명. reset_index(drop = True) - Index로 설정된 열을 DF내에서 삭제할 물어본다. True = 삭제, False = 유지
- 데이터명. reset_index(inplace = True) - 원본 객체를 변경 하는지 물어본다. True = 적용, False = 미적용
<기본 집계>
- 데이터명[ ' 이름' ].unique()
메소드로 고유값을 확인하며, 결괏값은 배열 형태가 된다.
- 데이터명[ ' 이름' ].value_counts()
메소드로 고유값과 그 개수를 확인하며, 결괏값은 시리즈 형태가 된다.
- .sum() 합 / .max() 최값 / .min() 최솟값 / .mean() 평균 / .median() 열 중앙값
- 데이터명.describe() / count, mean, std, min, 25%, 50%, 75%, max
LOC(isin / between)
<조건으로 조회 .loc / 매우중요!!!>
- df.loc[조건] 형태로 조건을 지정해 조건에 만족하는 데이터만 조회할 수 있다.
- 우선 조건이 제대로 판단이 되는지 확인한 후 그 조건을 대 괄호 안에 넣으면 된다.
- 데이터명.loc[ 데이터명 [ '열 이름' ] > 10 ] #열 값이 10보다 큰 행 조회
- 데이터명.loc[( 데이터명 [ '열 이름1' ] > 10) & ( 데이터명 [ '열 이름2' ] == 4) ]
# 열1 값이 10보다 크고 열2의 값이 4인 데이터 조회
- 데이터명.loc[( 데이터명 [ '열 이름1' ] > 10) | ( 데이터명 [ '열 이름2' ] == 4) ]
# 열1 값이 10보다 크거나 열2의 값이 4인 데이터 조회
- 데이터명.loc[( 데이터명 [ '열 이름1' ].isin( [ 1, 4 ] ) ] # isin( [ 데이터 값 ] )
안에 있는 데이터 값인 데이터 조회(↑ 같은 의미)
- 데이터명.loc[(배열명[ '열 이름1' ].between( 25, 32 ), inclusive = 'both' ]
# 값1 ~ 값2 범위 안의 데이터 조회 inclusive 생략시 기본값 'both' ( 값1 <= 데이터 <= 값2 ) 'left', 'right', neither' /
inclusive 생략시 기본값 'both' |
값1 <= 데이터 <= 값2 | 'left' | 값1 <= 데이터 < 값2 |
'right' | 값1 < 데이터 <= 값2 | 'neither' | 값1 < 데이터 < 값2 |
<조건에 만족하는 행의 일부열 조회 / 많이쓰임!>
- 데이터명.loc[배열명[ '열 이름' ] >= 10000, [ '열 이름1' ] ]
# 조건에 맞는 하나의 열 조회
- 데이터명.loc[배열명[ '열 이름' ] >= 10000, [ '열 이름1', '열 이름2', '열 이름3 ] ]
# 조건에 맞는 여 열 조회
- ex1) data.loc[data['MonthlyIncome'] >= 10000, ['Age', 'MaritalStatus', 'TotalWorkingYears']]
- ex2) data.loc[(data["Age"].between(50, 59)) & (data["MonthlyIncome" <10000),
['Age', 'MonthlyIncome', 'Gender', 'DistanceFromHome']]
<데이터프레임 집계>
- 데이터명[ '열 이름' ].sum()
- 데이터명[ '열 이름1', '열 이름2' ].mean()
- 데이터명.groupby( 데이터명 ['열 이름1'], as_index = True )[ '열 이름2' ].mean() ★ ★
# 열1을 기준으로한 열2의 평균(결과값)- DF.reset_index()를 통해 DF 구조를 맞춰줄 수 있음 ★ ★
- DF.columns.name=None : 열이름에 대한 이름을 제거합니다. ★
- as_index= 그 목록을 index로 쓸거야? 물어보는것 ★ ★
- [ '열 이름2' ].mean() = 시리즈로 조회 / [ ['열 이름2'] ].mean() = 데이터프레임으로 조회
- 데이터명.groupby( '열 이름1', as_index = True )[ ['열 이름2', '열 이름3', '열 이름4'] ].mean() #여러 열 집계
- 여러개의 열을 집계할 경우 [ ] 리스트로 묶어주어야 된다.
- 데이터명.groupby( '열 이름1', as_index = True )[ ['열 이름2'] ].agg( [ 'min', 'max', 'mean'] )
- agg()를 활용해 여러 함수로 한꺼번에 집계
<데이테프레임 변경>
- 열 이름 변경
DF.rename( columns = { 현재 열이름1 : 바꿀 열이름1, 현재열이름2 : 바꿀 열이름2 }, inplace = True)
# rename() 함수로 열 이름 변경
#inplace=True 변경할 colums를 저장 / False면 바꾼상태로 조회만 적용x
path = 'https://raw.githubusercontent.com/DA4BAM/dataset/master/Attrition_simple2.CSV'
data = pd.read_csv(path)
data.rename(columns={'DistanceFromHome' : 'Distance',
'EmployeeNumber' : 'EmpNo',
'JobSatisfaction' : 'JobSat',
'MonthlyIncome' : 'M_Income',
'PercentSalaryHike' : 'PctSalHike',
'TotalWorkingYears' : 'TotWY'}, inplace=True)
# 확인
data.head()
- 모든 열 이름 변경
DF.columns = [ 바꿀 이름1, 바꿀 이름2 ]
# 모든 열 이름 변경 / 열 수에 맞게 변경
data.columns = ['Attr','Age','Dist','EmpNo','Gen','JobSat','Marital','M_Income', 'OT', 'PctSalHike', 'TotWY']
# 확인
data.head()
<열 추가>
데이터명[ '새로운 열 이름' ] = 가공할 데이터
- 올해 급여 : MonthlyIncome(M_Income)
- 급여 인상율 : PercentSalaryHike(PctSalHike)
- 작년 급여 * ( 1 + PctSalHike / 100 ) = M_Income
- 작년 급여 = M_Income / (( 1 + PctSalHike / 100 )
# final_amt 열 추가
data['Income_LY'] = data['M_Income'] / (1+data['PctSalHike']/100 )
data['Income_LY'] = round(data['Income_LY'])
# 확인
data.head()
DF.drop
<열 삭제>
- 데이터명.drop( '열 이름', axis= n , inplace = T/F)
메소드를 사용해 열을 삭제합니다.- DF = DF.drop( '열 이름', axis= n ) - 이 방식은 새로운 DF를 만듦으로 inplace를 사용하면 안된다.
- DF.drop( columns = [ ], inplace = T ) - axis를 지정 안하고 columns를 지정해도 됨 (axis가 1일 경우)
- axis=0: 행을 의미 / 삭제(기본 값)
- axis=1: 열을 의미 / 삭제
- inplace=True
옵션을 지정해야 실제로 반영이 됩니다. (False : 삭제한 것 처럼 보여줘(조회!)) - 데이터명.dropna( axis= n , inplace = T) - 데이터 값이 NaN인 데이터를 삭제하고 적용
- axis = 0 이라면 행을 날림
- 시리즈를 사용해 특정 열만 NaN을 없앤다면
- DF.열이름 = DF.열이름.dropna(axis = n)으로 사용
- 조건에 맞을 경우에 그 행만 삭제하고 싶은 경우
- index_to_drop = df[df[ '열 이름' ] 조건 ex) > 4000 ].index
- df = df.drop(index_to_drop)
- 또는 df = df[df[' 열 이름 '] != 기준] 등으로 조건으로 저장
# 잘못 되었을 경우 되돌리기 위해 data를 복사합니다.
data2 = data.copy()
# 열 하나 삭제
data2.drop('Income_LY', axis=1, inplace=False) # 실제로는 삭제안됨
data2.drop('Income_LY', axis=1, inplace=True) # 실제로 삭제됨
# 확인
data2.head()
# 열 두 개 삭제
data2.drop(['JobSat2','Diff_Income'], axis=1, inplace=True)
# 확인
data2.head()
DF.fillna
- 데이터명.fillna( 채울 값 inplace = T/F)
- 시리즈를 사용해 특정 열의 NaN만 채운다면
- DF.열이름 = DF.열이름. fillna ( 채울 값 )으로 사용
- method='bfill' : 변수 NaN 값을 바로 뒤의 값으로 채우기
- method='ffill' : 변수 NaN 값을 바로 앞의 값으로 채우기
DF.ffill / DF.bfill
- 데이터명.ffill() / 데이터명.bfill()
- 시리즈의 경우
- DF[열이름] = DF[열이름].ffill() : 변수 NaN 값을 바로 앞의 값으로 채우기
- DF[열이름] =DF[열이름].dfill() : 변수 NaN 값을 바로 뒤의 값으로 채우기
DF.interpolate
- 시리즈의 경우
- DF[열이름] = DF[열이름].interpolate(method = 'linear' ) : 선형보간법으로 채우기 (중간값)
- DF[열이름] = DF[열이름].interpolate(method = ' nearest ' ) : 가까운 값으로 채워줌
pd.cut
<값 변경>
- 데이터명[ '열 이름' ] = 0 단순변경
- 데이터명.loc[ 데이터명[ '열 이름' ] < 조건문, '열 이름' ] = 0
- 데이터명[ '열 이름' ] = np.where( 데이터명[ '열 이름' ] > 40, 1, 데이터명[ '열 이름' ] )
# 조건이 맞으면 1, 아닐시 다시 그 데이터 입력
- 데이터명[ '열 이름' ] = 데이터명[ '열 이름' ] .map({ '요소1' : 1, '요소2' : 0}) / 범주형 데이터에 사용 가능
<숫자형 -> 범주형 변수로 변환>
- 새로운 범주 데이터명 = pd.cut( 데이터명[ '열 이름' ] , 3, labels = ['a','b','c'])
pd.cut(숫자형변수, 분할방식, 범주값)
- 내가 원하는 구간 자르기 : bins = []
- ex) pd.cut(data2['Age'], bins =[0, 40, 50, 100] , labels = ['young','junior','senior'])
pd.concat / pd.merge
<데이터프레임 결합>
- pd.concat() - 매핑 기준 : 인덱스(행), 칼럼이름(열) / 데이터프레임 구조에 맞게 함침
- pd.concat([ 합칠 데이터1, 데이터2, 데이터3], axis = 0/1 , join ="조인 종류")
join 생략시 outer join - 방향 axis = 0 - 세로(행)로 합치기(위, 아래로 붙여라) - 칼럼 이름 기준
- 방향 axis = 1 - 가로(열)로 합치기(옆으로 붙여라) - 행 인덱스 기준
- join = ‘outer’ : 모든 행과 열 합치기 (기본값)
- join = ‘inner’ : 같은 행과 열만 합치기
- pd.concat([ 합칠 데이터1, 데이터2, 데이터3], axis = 0/1 , join ="조인 종류")
- pd.merge() - 매핑 기준 : 특정 칼럼(key)의 값(열 값) 기준으로 결합 / 데이터 값 기준으로 합침
- pd.merge( DF1, DF2, how = 'inner', on = '요소(공통된 열 이름)') /
how 생락시 inner join, on 생략시 None으로 알아서 공통을 찾음 - 옆으로만 병합
- how = 'inner' : 같은 값만
- how = 'outer' : 모두
- how = 'left' : 왼쪽 df는 모두, 오른쪽 df는 같은 값만
- how = 'right' : 오른쪽 df는 모두, 왼쪽 df는 같은 값만
- pd.merge( DF1, DF2, how = 'inner', on = '요소(공통된 열 이름)') /
pd.get_dummies
- pd.get_dummies( DF, columns = [ ] , dtype = int) - 가변수화
- ★ drop_first=True - 가변수화한 첫 열을 없앤다. -> 다중공선성 문제를 없앤다.
pd.pivot
- 데이터명.pivot(index = , columns = , values = ) / 결합은 아니지만 데이터를 재구성 해줌
- 원하는 데이터의 열을 index, columns, values로 지정하여 새로운 DF으로 생성
pd.melt
- 데이터명.melt(id_vars = '', value_vars = '' )
- id_vars - 기준되는 열을 지정
- value_vars - 값과 같이 행으로 들어갈 열
- 두 값 모두 리스트로 여러개 지정 가능
<시계열 데이터>
- 행과 행에 시간의 순서(흐름)가 있고
- 행과 행의 시간간격이 동일한 데이터
<날짜 요소 뽑기>
- 날짜 타입으로 변환한 후 .dt.날짜요소로 추출 가능
구분 | air['Date'].dt | air['Date'].dt.isocalendar(). |
일 | day | X |
월 | month | Y |
연 | year | year |
주차 | x | week |
요일 | weekday : 0~6 | day : 1~7 |
< 시간에 따른 흐름 추출하기 : Time Lag >
- 데이터명[ '새로운 열' ] = 데이터명[ '열 이름' ].shift(n)
- 시계열 데이터에서 시간의 흐름 전후로 정보를 이동시킬 때 사용
shift()의 default 값은 1, shift(2) 2행 밀기, shift(-1) 뒷쪽으로 밀기 - 데이터명[ '새로운 열' ] = 데이터명[ '열 이름' ].rolling(n, min_periods = 1).mean()
- 시간의 흐름에 따라 일정 기간 동안 평균을 이동하면서 구하기
- min_periods =1 -> 데이터가 하나라도 존재하면 조회함. - 데이터명[ '새로운 열' ] = 데이터명[ '열 이름' ].diff(n) - 특정 시점 데이터, 이전시점 데이터와의 차이 구하기
MinMaxScaling
from sklearn.preprocessing import minmax_scale
minmax_scale(데이터) 를 통해 데이터를 스케일링 할 수 있다.
import 선언
# scikit-learn를 별칭(alias) sk로
import sklearn as sk
#Pandas를 사용할 수 있도록 별칭(alias)을 pd로
import pandas as pd
# 그래프를 그리기 위한 선언
# 필요하면 설치 !pip install seaborn
import seaborn as sns
import matplotlib.pyplot as plt
# split을 위한 선언
from sklearn.model_selection import train_test_split
# 스케일링을 위한 선언
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_valid = scaler.transform(X_valid)
# numpy 선언
import numpy as np
#라벨 인코딩
from sklearn.preprocessing import LabelEncoder
#원한 인코딩의 경우에는 그냥 .get_dummies()
df = pd.get_dummies(df, columns=['범주형 열'], drop_first=True)
# import
from sklearn.metrics import * # 모든 함수 로드
# 분류 모델 평가 지표
from sklearn.metrics import accuracy_score # 정확도
from sklearn.metrics import precision_score # 정밀도
from sklearn.metrics import recall_score # 재현율
from sklearn.metrics import f1_score # f1 score
from sklearn.metrics import confusion_matrix # 혼동행렬
from sklearn.metrics import accuracy_score # 모든 지표 한번에
# 회귀 모델 평가 지표
from sklearn.metrics import r2_score # R2 결정계수
from sklearn.metrics import mean_squared_error # MSE
from sklearn.metrics import mean_absolute_error # MAE
# 머신러닝 모델 정리
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier # 분류
from sklearn.tree import DecisionTreeRegressor # 회귀
from sklearn.ensemble import RandomForestClassifier # 분류
from sklearn.ensemble import RandomForestRegressor # 회귀
!pip install xgboost
from xgboost import XGBClassifier # 분류
from xgboost import XGBRegressor # 회귀
!pip install lightbgm
from lightgbm import LGBMClassifier # 분류
from lightgbm import LGBMegressor # 회귀
원핫 인코딩 및 라벨링
#원핫 인코딩 예시
oh_cols = ['Address1', 'Address2']
df_preset = pd.get_dummies(df_del, columns = oh_cols, drop_first = True)
#라벨링 예시
from sklearn.preprocessing import LabelEncoder
# 객체 생성
le = LabelEncoder()
# 인코딩 적용
df['범주형 열'] = le.fit_transform(df['범주형 열'])
x, y 분리
from sklearn.model_selection import train_test_split
x = df_preset.drop(columns = ['y컬럼명'])
y = df_preset['y컬럼명']
X_train, X_valid, y_train, y_valid = train_test_split(x, y, test_size = 0.2, random_state = 42)
머신러닝 예제
!pip install lightgbm
from lightgbm import LGBMClassifier
lgbm = LGBMClassifier(n_estimators=3, random_state=42)
lgbm.fit(X_train, y_train)
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
y_pred = lgbm.predict(X_valid)
cm = confusion_matrix(y_valid, y_pred)
sns.heatmap(cm, annot=True)
print(classification_report(y_valid, y_pred, zero_division=1))
딥러닝 예제
이진 분류
model = Sequential()
model.add(Dense(64, activation='relu', input_shape=(X_train.shape[1],)))
model.add(Dropout(0.2))
model.add(Dense(32, activation='relu'))
model.add(Dense(16, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
es = EarlyStopping(monitor='val_loss', patience=5)
checkpoint_path = 'best_model.keras'
mc = ModelCheckpoint(checkpoint_path, monitor='val_loss', verbose=1, save_best_only=True)
history = model.fit(X_train, y_train, epochs=30, batch_size=16,
validation_data = (X_valid, y_valid),
callbacks=[es, mc]
)
다중 분류
n = x_train.shape[1]
clear_session()
model = Sequential([Input(shape=(n, )),
Dense(64, activation='relu'),
Dropout(0.2),
Dense(32, activation='relu'),
Dropout(0.2),
Dense(16, activation='relu'),
Dropout(0.2),
Dense(2, activation='softmax')])
model.compile(optimizer= Adam(learning_rate = 0.001), loss='categorical_crossentropy', metrics=['accuracy'])
# EarlyStop
min_de = 0.001
pat = 5
es = EarlyStopping(monitor = 'val_loss', min_delta = min_de, patience = pat)
# MCP
cp_path = 'best_model.keras'
mcp = ModelCheckpoint(cp_path, monitor='val_loss', verbose = 1, save_best_only=True)
history = model.fit(x_train, y_train, epochs = 10, batch_size=10, validation_split=0.2, callbacks = [es, mcp]).history
history = model.fit(x_train, y_train, epochs = 10, batch_size=10, validation_split=0.2).history
'<프로그래밍> > [python]' 카테고리의 다른 글
[python] 머신러닝의 기초2 (1) | 2024.09.27 |
---|---|
[python] 머신러닝의 기초 (0) | 2024.09.26 |
[python] 데이터 시각화2(단변량 분석) (1) | 2024.09.26 |
[python] 데이터 시각화1(matplotlib 기초) (0) | 2024.09.10 |
[python] 데이터 구조와 분석 / numpy (3) | 2024.09.06 |