본문 바로가기
Python/데이터 분석

[Python] 데이터 전처리

by Mr.Han 2024. 9. 1.

* 개인적인 스터디를 위한 블로그이기 때문에 생략된 부분이 많은 점 참고 부탁드립니다.

 

Series & DataFrame


1. Series

구분 내용 코드 예시
정의 Pandas에서 사용하는 일종의 리스트  
생성 Dictionary → Series import pandas as pd

dic = {'a':1, 'b':2, 'c':3}
dic_series = pd.Series(dic)

print(type(dic_series))
print(dic_series)
  List → Series
- 인덱스 미설정시 자동으로 0부터
ls = [1, 2, 3]
ls_series1 = pd.Series(ls)
ls_series2 = pd.Series(ls, index=['a', 'b', 'c']}

print(type(ls_series1))
print(ls_series1)

print(type(ls_series2))
print(ls_series2)
속성 확인 - 시리즈의 값 : 시리즈명.values
- 인덱스 : 시리즈명.index
- 값의 타입 : 시리즈명.dtypes
print(ls_series2.values)
print(ls_series2.index)
print(ls_series2.dtypes)

 

2. DataFrame

구분 내용 코드 예시
정의 시리즈를 이어붙여 표 형태로 만든 것  
생성 Dictionary → DataFrame
- 열 단위로 값을 입력할 때 딕셔너리 사용
- 값의 길이가 모두 같아야 함.
dic = {'Name':['John', 'Merry', 'Chris']
       , 'Number':[1, 2, 3]
       , 'Month':['Feb', 'Oct', 'Nov']}

df = pd.DataFrame(dic)
df
  List → DataFrame
- 행 단위로 값을 입력할 때 리스트 사용
- 각 리스트의 길이가 같아야 함.
ls = [['John', 1, 'Feb']
      , ['Merry', 2, 'Oct']
      , ['Chris', 3, 'Nov']]

df = pd.DataFrame(ls, columns=['Name', 'Number', 'Month'])
df
    type(df)
  Series → DataFrame name_series = pd.Series(['John', 'Merry', 'Chris'])
number_series = pd.Series([1, 2, 3])
month_series = pd.Series(['Feb', 'Oct', 'Nov'])

df = pd.DataFrame({'Name':name_series,
'Number':number_series, 'Month':month_series})
df
속성 확인 - 데이터프레임의 값 : 데이터프레임명.values
- 인덱스 : 데이터프레임명.index
- 값의 타입 : 데이터프레임명.dtypes
- 컬럼 : 데이터프레임명.columns
print(df.values, end='\n\n')
print(df.index, end='\n\n')
print(df.dtypes, end='\n\n')
print(df.columns)

 


데이터 불러오기, 저장하기


1. csv 파일

구분 내용 코드 예시
불러오기 데이터변수 = pd.read_csv(파일경로)
- index_col : 인덱스로 사용할 컬럼
- usecols : 사용할 컬럼

* 내용에 한글 포함되어 있다면,
encoding='utf-8' 혹은 'cp949' 
csv_file_path = './data/titanic_train.csv' # 파일 경로

csv_data1 = pd.read_csv(csv_file_path,
    index_col='PassengerId',
    usecols=['PassengerId', 'Survived', 'Pclass', 'Age'])
# index_col = 0 가능
csv_data1.head()
저장 데이터변수 = pd.to_csv(파일경로) csv_file_path1 = './data/csv_test.csv'

csv_data1.to_csv(csv_file_path1)
pd.read_csv(csv_file_path1).head()

 

2. 엑셀 파일

구분 내용 코드 예시
불러오기 데이터변수 = pd.read_excel(파일경로,
    sheet_name=시트이름)
- header : 컬럼 이름으로 사용할 행
- index_col : 인덱스로 사용할 컬럼
- usecols : 사용할 컬럼
!pip install openpyxl

excel_file_path = './data/titanic_train.xlsx'
excel_data = pd.read_excel(excel_file_path,
                                              sheet_name='시트1')

excel_data.head()
    excel_data1 = pd.read_excel(excel_file_path,                                  sheet_name='시트1', header=1, index_col='PassengerId',
    usecols=['PassengerId', 'Survived', 'Pclass', 'Age'])
excel_data1.head()
저장하기 데이터변수.to_csv(파일경로,
    sheet_name=시트이름)
excel_file_path1 = './data/excel_test.xlsx'
excel_data1.to_excel(excel_file_path1, sheet_name='sheet1')

pd.read_excel(excel_file_path1, sheet_name='sheet1').head()

 


데이터 가공


1. 조회

구분 내용 코드 예시
행 조회 한 개
- 데이터프레임명[인덱스:인덱스+1]
여러 개
- 데이터프레임명[시작인덱스:끝인덱스+1]
df[3:4]
df[3:6]
df[:10]
열 조회 한 개
- 데이터프레임명[컬럼명]
- 데이터프레임명.컬럼명

여러 개
- 데이터프레임명[[컬럼명1, 컬럼명2, …]]
df['Survived'] # Series 형태로 출력
df.Survived # Series

df['Survived'].to_frame() # 데이터프레임 형태로 출력
df[['Survived']] # 데이터프레임

df[['Survived', 'Pclass', 'Name']] # 데이터프레임
loc 레이블 값을 사용하여 조회
- 데이터프레임명.loc[행조건, 열조건]
- 열만 조회할 때는 행조건에 : 를 입력
df.loc[3, ] # 3 행
df.loc[:, 'Name'] # 'Name' 열
df.loc[3, 'Name']

df.loc[3:5, ['Age', 'Pclass']] # 3~5행
df.loc[[1, 3, 5], ['Age', 'Pclass']]
  특정 열을 인덱스로 설정했다면 df1 = df.set_index('Name') # Name 열을 인덱스로 설정

df1.loc[['Heikkinen, Miss. Laina', 'Allen, Mr. William Henry', ]]
iloc 위치 인덱스를 사용하여 조회
- 데이터프레임명.iloc[행인덱스조건,
    열인덱스조건]
df.iloc[3, ]
df.iloc[3:7, ]
df.iloc[[1, 3, 5], ]
df.iloc[3:7, 2:4]

 

2. 조건

구분 내용 코드 예시
정렬 데이터프레임명.sort_values(정렬기준컬럼)
- 내림차순 : ascending=False
df.sort_values('Age', ascending=False)
df.sort_values(['Age', 'Fare'], ascending=[False, True])
조건 데이터프레임명[조건식]
데이터프레임명.query('조건식')
df[(df['Pclass'] == 1) & (df['Age'] >= 30)]
df[(df['Pclass'] == 1) | (df['Age'] >= 30)]

df.query('Pclass == 1 and Age >= 30')
df.query('Pclass == 1 or Age >= 30')
  .isin(리스트)
- 리스트 안의 값을 가지는 행 추출
df[df['PassengerId'].isin([3, 100, 500])]
df.query('PassengerId in [3, 100, 500]')
df.query('PassengerId in @passengerid_sample')
# 변수명 앞에 @ 붙임.
df.query('PassengerId.isin([3, 100, 500])')

 

3. 인덱스. 행, 열

구분 내용 코드 예시
인덱스 확인 df.index

print(list(df.index))
  변경
인덱스 몇 개를 바꿀 때
- 데이터명.rename({인덱스1:바꿀인덱스1,
    인덱스2:바꿀인덱스2, …})
인덱스 전체를 바꿀 때
- 데이터명.index = 바꿀인덱스리스트
df1.rename({0:'row1', 1:'row2'})
# 변경하려면 변수에 저장해야 함.
df1 = df1.rename({0:'row1', 1:'row2'})

df1.index = [i+1 for i in range(len(df1))]
  열 → 인덱스
- 데이터명.set_index(컬럼명)
df1 = df1.set_index(['PassengerId'])
  인덱스 → 열

변환 후 열 남기고 싶으면,
- 데이터명.reset_index()
변환 후 열 삭제하고 싶으면,
- 데이터명.reset_index(drop=True)
df1 = df1.reset_index()

df1 = df1.reset_index(drop=True)
행 추가
- pd.concat([기존테이블명, 붙일테이블명])
행 제거
- 데이터명.drop(인덱스명, axis=0)
행 중복 제거
- 데이터명.drop_duplicates()
df3 = pd.concat([df1, df2])

# 인덱스 891 부터 끝까지 drop
df3 = df3.drop([i for i in range(891, len(df3))], axis=0)
# axis=0은 행

df3 = df3.drop_duplicates()
행 이동 데이터명[컬럼명].shift(이동할 행의 수) df2['Temp shift1'] = df2['Temp'].shift(1)
# 전일 대비 증감률
df2['pct change'] = (df2['Temp shift1'] - df2['Temp'])/df['Temp'] 
열 추가
- 데이터명[추가할 컬럼명] = 추가할 값
열 제거
- 데이터명.drop(제거할 컬럼명, axis=1)

열 이름 변경
열 이름 하나를 바꿀 때
- 데이터명.rename({열이름1:바꿀이름1,
    열이름2:바꿀이름2, ...}, axis=1)
열 이름 전체를 바꿀 때
- 데이터명.columns = 열이름리스트
df1['age_simplified'] = df1['Age']//10 * 10 # 10대, 20대 단위
df1['given_name'] = [i[0] for i in df1['Name'].str.split(',')]
# 이름이 첫번째 부분만
df1['string_add'] = df1['Sex'] + df1['given_name']

df1 = df1.drop('given_name', axis=1)

df1 = df1.rename({'PassengerId':'Id'}, axis=1)
# axis=1은 열
df1.columns = [i for i in range(12)]

 

4. 결측값

구분 내용 코드 예시
확인 isna() : 결측값을 True로 반환
notna() : 결측값을 False로 반환
# 컬럼별로 결측값이 몇 개인지
df.isna().sum()
# 결측값 있는 행만 확인
df[df['Age'].isna()]

# 컬럼별로 결측값 아닌 데이터가 몇 개인지
df.notna().sum()
제거 데이터명.dropna(axis=0, how='any',
    subset=None)
- axis: {0: index / 1: columns}
- how: {'any': 존재하면 제거 / 'all': 모두 결측치면 제거}
- subset: 행/열의 이름을 지정 
df.dropna(axis=1)
df.dropna(how='all')
df.dropna(subset=['Cabin', 'Age'])
대치 데이터 전체의 결측값을 특정 값으로 변경
- 데이터명.fillna(대치할값)

특정 컬럼의 결측값을 특정 값으로 변경
- 데이터명[컬럼명].fillna(대치할값)

결측값을 바로 위의 값과 동일하게 변경
- 데이터명.fillna(method='ffill')

결측값을 바로 아래의 값과 동일하게 변경
- 데이터명.fillna(method='bfill')
df.fillna(-1)

df['Age'] = df['Age'].fillna(-1)
df['Age'] = df['Age'].fillna(round(df['Age'].mean()))
# 특정 컬럼의 평균값으로 대치

df.fillna(method='ffill')
df.fillna(method='bfill')

 

5. 타입

구분 내용 코드 예시
확인 .dtypes : 컬럼의 타입을 시리즈로 반환

특정 타입을 가진 컬람만 추출
- 데이터명.select_dtypes(타입)
df.dtypes

df.select_types(int)
df.select_types('object')
변환 데이터명[컬럼명].astype(타입)
- 결측치가 있으면 정수로 반환할 수 없음.
    (fillna() → 변환 → replace())
df['PassengerId'].astype(str)
df1['Age'].fillna(-1).astype(int).replace(-1, np.nan)

 

6. 날짜

구분 내용 코드 예시
문자형 변경 날짜 계산을 위해 문자형 → 날짜형
pd.to_datetime(컬럼, format='날짜형식')
- %Y : 0을 채운 4자리 연도
- %y : 0을 채운 2자리 연도
- %m : 0을 채운 월
- %d : 0을 채운 일
- %H : 0을 채운 시간
- %M : 0을 채운 분
- %S : 0을 채운 초
pd.to_datetime(df['Date'], format='%Y-%m-%d')
날짜형 형식 변경 데이터명[컬럼명].dt.strftime(날짜형식) df['Date1'].dt.strftime('%Y-%m')
df['Date1'].dt.strftime('%m-%d %H:%M')
dt 연산자 dt.날짜형식
- year, month, day : 연도, 월, 일
- dayofweek : 요일 (0-월요일, 6-일요일)
- day_name() : 요일을 문자열로 
df['year'] = df['Date1'].dt.year
df['month'] = df['Date1'].dt.month
df['day'] = df['Date1'].dt.day
df['dayofweek'] = df['Date1'].dt.dayofweek
df['dayname'] = df['Date1'].dt.day_name()
계산 - day 연산 : pd.Timedelta(day=숫자)
- month 연산 : DateOffset(months=숫자)
- year 연산 : DateOffset(years=숫자)
df['plus day1'] = df['Date1'] + pd.Timedelta(days=1)
df['plus day7'] = df['Date1'] + pd.Timedelta(days=7)
df['minus day7'] = df['Date1'] - pd.Timedelta(days=7)

from pandas.tseries.offsets import DateOffset
df['plus month1'] = df['Date1'] + DateOffset(months=1)
df['minus month3'] = df['Date1'] - DateOffset(months=3)
df['plus year1'] = df['Date1'] + DateOffset(years=1)
df['minus year3'] = df['Date1'] - DateOffset(years=3)
날짜 구간 데이터 pd.date_range(start=시작일자, end=종료일자,      periods=기간수, freq=주기)
- freq='D' : 일별
- W : 주별
- M : 월별 말일
- MS : 월별 시작일
- A : 연도별 말일
- AS : 연도별 시작일
pd.date_range(start='2020-01-01', periods=30, freq='D')
pd.date_range(start='2020-01-01', end='2023-06-30', freq='M')
기간 이동 계산 데이터명[컬럼명].rolling().집계함수
- mean, sum, min, max 가능
# 7일 이동평균
df1['ma7'] = df['Temp'].rolling(7).mean()
# 30일 이동평균
df1['ma30'] = df['Temp'].rolling(30).mean()
# 7일 합계
df['Temp'].rolling(7).sum()

 

7. 고급 기능

구분 내용 코드 예시
apply 함수 사용자 정의 함수를 데이터에 적용하고 싶을 때 사용
- .apply(함수, axis=0/1)
# 사용자 정의 함수
def pclass_sibsp(x):
    if x['Pclass'] == 1 and x['SibSp'] == 1:
        return 1
    else:
        return 0

df1['pclass_sibsp_filter'] = df1.apply(pclass_sibsp, axis=1)
# 함수에 열 이름을 참조 했기 때문에 axis=1
  간단한 함수는 lambda로 구현 가능 df1['pclass_sibsp_lambda'] = df1.apply(lambda x:
    1 if x['Pclass'] == 1 and x['SibSp'] == 1 else 0, axis=1)
    import numpy as np

def adult(x):
    if x >= 19:
        return 1
    elif x < 19:
        return 0
    else:
        return np.nan

df1['adult_yn'] = df1['Age'].apply(adult)
map 함수 - 값을 특정 값으로 치환하고 싶을 때 사용
- 데이터명[컬럼명].map(매핑 딕셔너리)
gender_map = {'male':'남자', 'female':'여자'}
df1['Sex_kr'] = df1['Sex'].map(gender_map)
문자열 함수 - .str.contains(문자열) : 문자열을 포함하고 있는지 유무
- .str.replace(기존문자열, 대체문자열) : 문자열 대치
- .str.split(문자열, expand=True/False,
    n=개수)
: 특정 문자열을 기준으로 쪼개기
- .str.lower() : 소문자로 바꾸기
- .str.upper() : 대문자로 바꾸기
df2['Name'].str.contains('Mrs') # True/False로 반환
df2[df2['Name'].str.contains('Mrs')]
# 데이터 추출: 대괄호에 넣으면 조건식이 됨.

df2['Name'].str.replace(',', '')

df2['Name'].str.split(' ')
df2['Name'].str.split(' ', expand=True, n=1)
# n은 ' '를 기준으로 몇개로 쪼갤 것인지 결정

df2['Name'].str.lower()
df2['Name'].str.upper()

 

8. 데이터 결합

구분 내용 코드 예시
join 두 개의 데이터를 특정 컬럼 기준으로 합침.
- pd.merge(데이터1, 데이터2, on=기준컬럼,
    how=결합방법)


두 데이터의 기준 컬럼명이 다른 경우
- pd.merge(데이터1, 데이터2,
    left_on=데이터1 기준컬럼,
    right_on=데이터2 기준컬럼,
    how=결합방법)
pd.merge(customer, orders, on='id', how='inner')

pd.merge(customer, orders, left_on='id', right_on='customer_id',      how='inner')
# 기준 컬럼 두 개가 모두 출력됨.

 

'Python > 데이터 분석' 카테고리의 다른 글

[Python] 데이터 집계  (0) 2024.09.02