Python 프로그래밍 및 Pandas 활용 실습(3)-1

2024. 1. 4. 17:12TIL

DataFrame기초 - DataFrame생성(Create)
'''
DataFrame은 2차원 구조로 2개 이상의 Series로 구성
axis = 0 : index 방향
axis = 1 : columns 방향
'''

import pandas as pd
member = {
    'Attack': [111, 222, 333],
    'Defence': [444, 555, 666],
    'Luck': [777, 888, 999]
}
member_df = pd.DataFrame(member)

member_df['Attack']
type(member_df['Attack']) #Series

'''
columns
-데이터가 제공되면 그것으로 columns로 설정
-제공되지 않으면 default는 RangeIndex(0, 1, 2...n)로 설정
'''
# 리스트로 동일한 데이터 프레임을 만든다면 1
data = [[111, 222, 333], [444, 555, 666], [777, 888, 999]]
columns = ['Attack', 'Defence', 'Luck']
member_df = pd.DataFrame(data=data, columns=['Attack', 'Defence', 'Luck'])
# 앞서 데이터 프레임과 다른 모습

# 리스트로 동일한 데이터 프레임을 만든다면 2
data = [[111, 444, 777], [222, 555, 888], [333, 666, 999]]
columns = ['Attack', 'Defence', 'Luck']
member_df = pd.DataFrame(data=data, columns=['Attack', 'Defence', 'Luck'])
# 미리보기
member_df.columns, member_df.index

'''
index
-데이터가 제공되면 그것으로 index로 설정
-제공되지 않으면 default는 RangeIndex(0, 1, 2...n)로 설정
'''
# 리스트로 동일한 데이터 프레임을 만든다면 2
data = [[111, 444, 777], [222, 555, 888], [333, 666, 999]]
columns = ['Attack', 'Defence', 'Luck']
index = ['Spencer', 'Tommy', 'Uriel']
member_df = pd.DataFrame(data=data, columns=columns, index=index)

# 권장하는 방식
member_df['Attack']
# 가능은 하나 추천하지 않는 방식(dot)을 이용한 접근 방식 - 문제가 발생할 수 있음.
member_df.Attack
#왜냐하면 아래와 같은 문제 때문
df1=pd.DataFrame([[1,2,3],[4,5,6]], columns=['shape', 'info', 'index'])
df1['shape']
df1.shape #.shape은 행렬 크기를 나타내기 때문에 위와 다름
df1.info
df1.index #.info, .index도 마찬가지

 

DataFrame기초 - [복습] CSV로 DataFrame생성
rich_df = pd.read_csv('TopRichestInWorld.csv')
# 단일 열 접근 -> Series
type(rich_df['Name'])
# 다중 열 접근 -> DataFrame
type(rich_df[['Name', 'Age']])

 

DataFrame기초 - DataFrame속성(Attrs)
import pandas as pd
member = {
    'Attack' : [111, 222, 333],
    'Defence' : [444, 555, 666],
    'Luck' : [777, 888, 999]
}
member_df = pd.DataFrame(member)

#.shape: 행렬 구조
#.info: 데이터 정보
#.info(): 각 컬럼별 데이터 수,데이터 타입
#.size: 행렬 크기
#.values: 행들의 값 
#.dtypes: 열들의 타입
#.index: 데이터프레임의 인덱스
#.columns: 열들의 이름
#.axes: 인덱스와 열의 정보

 

DataFrame기초 - DataFrame메소드(Methods)
import pandas as pd
member = {
    'Attack' : [111, 222, 333],
    'Defence' : [444, 555, 666],
    'Luck' : [777, 888, 999]
}
member_df =pd.DataFrame(member)

member_df.sum() #각 열들의 합(시리즈)
member_df.sum().sum() #각 열들의 합의 합(단일값)
member_df.sum(axis=0) #각 열들의 합
member_df.sum(axis='index') #각 열들의 합
member_df.sum(axis=1) #각 행들의 합
member_df.sum(axis='columns') #각 행들의 합

member_df.max(axis=0) #각 열들의 최댓값
member_df.min(axis=1) #각 행들의 최솟값
member_df.mean(axis=0) #각 열들의 평균
member_df.median(axis=1) #각 행들의 중앙값
member_df.prod(axis=1) #각 행들의 곱셈 연산

 

 집계함수 목록

min 최소값
max 최대값
sum 합계
mean 평균
median 중앙값
count 비결측치의 개수
value_counts 각 값의 빈도
describe 요약 통계량
mode 최빈값
std 표준편차
var 분산
prod 모든 요소의 곱
quantile 분위수
cumsum 누적 합
cumprod 누적 곱
cummax 누적 최대값
cummin 누적 최소값

 

DataFrame기초 - 정보와 요약(info, describe)
import pandas as pd
movie_df = pd.read_csv('imdb_top_1000.csv')

#필요한 열만 가져오기
cols = ['Series_Title', 'Released_Year', 'Certificate', 'Genre', 
		'IMDB_Rating', 'Meta_score', 'Director', 'No_of_Votes', 'Gross']
movie_df = pd.read_csv('imdb_top_1000.csv', usecols=cols)

# 순서 바꿔서 열 지정하기
cols = ['Released_Year', 'Genre', 'Series_Title', 'Director', 'Meta_score',
		'IMDB_Rating', 'No_of_Votes', 'Certificate', 'Gross']
movie_df = movie_df[cols]

#.info(): 간략한 요약 출력(index dtype, columns, non-nulll values, memry usage)
movie_df.info()

#.describe(): 집계 함수의 요약
movie_df.describe()
# 반올림 처리를 한다면
movie_df.describe().round() #round(0)과 동일
# 유효숫자 1자리 = 소수점 2자리에서 반올림 처리
movie_df.describe().round(1)

 

DataFrame기초 - 형변환과 결측치 처리(fillna, astype)
# Gross의 타입을 보면 숫자형 타입이 아닌 object임을 알 수 있다.
movie_df.info()

'''
숫자형 데이터로 변환 가능한 형태로 처리
데이터 분석에 유용한 형태로 가공하는 작업 : 데이터 전처리
comma(,)부터 .str.replace() 로 삭제
'''

#.str.replace() - 1단계 : 포맷 변경하기
# 1단계 comma(,) 삭제하기
movie_df['Gross'] = movie_df['Gross'].str.replace(',','')

#.fillna() - 2단계 : 결측치 대체하기
# NaN으로 나오고 있는 결측치는 0으로 대체
# movie_df['Gross'].fillna(0, inplace=True)
movie_df['Gross'] = movie_df['Gross'].fillna(0)

# .astype() - 3단계 : dtype 변환하기
# 정수형 dtype인 int64로 변환
# .astype('변환형')
movie_df['Gross'] = movie_df['Gross'].astype('int64')

# .describe()로 요약하면
movie_df.describe().round()

 

DataFrame기초 - 집계함수와 인자(percentiles=, numeric_only=, quantile, include=)
# 필요하다면 퍼센트 범위를 지정할 수도 있다.
# [20%, 40%, 60%, 80%] -> [.2, .4, .6, .8]
movie_df.describe(percentiles=[.2,.4,.6,.8]).round(1)
# 빈 리스트를 넣어도 50%는 남는다
#왜냐하면 50%는 사실은 median(중앙값)이고, 
#이 때문에 percentiles처리에 오류가 있다는 오해가 종종 있다.
movie_df.describe(percentiles=[]).round(1)

# max, min, mean 등을 DataFrame에서 바로 사용하면 때때로 경고(Warning)이 발생한다.
# 숫자형 데이터만 있는 건 아니기 때문임으로 숫자만 처리하도록 지정하는 것.
movie_df.max() #Warning
movie_df.max(numeric_only=True)

# quantile : 분위수 - 오름차순/내림차순 되있을 때 이를 나누는 지점
# percentiles : 백분위수, 100개 영역 지점이 존재. 퍼센트
# quartiles : 4분위수, 4구역 지점이 존재
# 만일 50% 지점을 확인한다면 0.5
movie_df.quantile(q=.5,numeric_only=True).round(1)
# 50% 지점 == median(중앙값)
movie_df.median(numeric_only=True).round(1)

#include= : 데이터 유형 제한
'''
count: 해당 열의 비어 있지 않은(non-null) 값의 개수
unique: 해당 열에서 고유한(unique) 값의 개수
top: 해당 열에서 가장 빈도가 높은 값(top value)
freq: top 값의 빈도수
'''
# 문자열 타입에 대한 요약 정보
movie_df.describe(include=['O']) 
movie_df.describe(include=['object'])
# 숫자형 타입에 대한 요약 정보
movie_df.describe(include=['number'])
movie_df.describe(include=['float64'])
movie_df.describe(include=['int64'])
# 문자열, int형에 대한 요약 정보
movie_df.describe(include=['O','int'])
# 모든(all) 타입에 대한 요약 정보
movie_df.describe(include='all').round(1)
'''
표현할 수 없는 항목은 NaN으로 나온다.
문자열 데이터는 mean, std, min등을 표현할 수 없고
숫자형 데이터는 unique, top, freq를 표현할 수 있을 것 같은데, 크게 의미가 없습니다.
-unique: 숫자형 데이터는 고유한(unique) 값의 개수를 가질 수 없으므로 NaN으로 처리
-top: 숫자형 데이터는 가장 빈도가 높은(top) 값이라는 개념이 적용되지 않으므로 NaN으로 처리
-freq: 숫자형 데이터는 각 값의 빈도수를 측정할 수 없으므로 NaN으로 처리
'''

 

DataFrame기초 - 정렬(nlargest, nsmallest, sort_values, by=)
import pandas as pd
cols = ['Released_Year', 'Genre', 'Series_Title', 'Director', 'Meta_score', 
		'IMDB_Rating', 'No_of_Votes', 'Certificate', 'Gross']
movie_df = pd.read_csv('imdb_top_1000.csv')
movie_df = movie_df[cols]

#.nlargest()
movie_df.nlargest(n=5, columns=['IMDB_Rating']) #IMDB_Rating열 값 큰 순서로 정렬
movie_df.sort_values(by='IMDB_Rating', ascending=False).head(5) #위와 동일
#.nsmallest()
# 1차 정렬 IMDB_Rating
movie_df.nsmallest(n=5, columns=['IMDB_Rating'])
# 1차 정렬 IMDB_Rating, 2차 정렬 Meta_score
movie_df.nsmallest(n=5, columns=['IMDB_Rating','Meta_score'])

'''
keep= 중복된 값이 있는 경우
-first : 첫 번째 등장하는 값들을 우선. (default)
-last : 마지막으로 등장하는 값들을 우선.
-all : 중복된 값을 제거하지 않고 모든 값들을 선택. 이 경우 n보다 더 많은 항목들이 선택될 수 있다.
'''
# IMDB_Rating 최고 7개, 동점의 경우 먼저 등장하는 것부터 우선배치
movie_df.nlargest(n=7, columns=['IMDB_Rating'])
# IMDB_Rating 최고 7개, 동점의 경우 끝에있는 것부터 우선배치
movie_df.nlargest(n=7, columns=['IMDB_Rating'],keep='last')
# IMDB_Rating 최고 7개, 동점의 경우 8개가 넘더라도 추가
movie_df.nlargest(n=7, columns=['IMDB_Rating'],keep='all')

'''
.sort_values()
-Series.sort_values보다 DataFrame.sort_values인자가 'by' 하나 더 있다.
-Series는 단일 열이 였지만, DataFrame은 다중 열이기에 어떤 열을 정렬할 지, 
정렬하려는 열 정보가 필요
'''
movie_df.sort_values(by=['IMDB_Rating','Meta_score'],ascending=False)

 

DataFrame기초 - 인덱스 제어(set_index, reset_index, drop=)
import pandas as pd
cols = ['Released_Year', 'Genre', 'Series_Title', 'Director', 
		'Meta_score', 'IMDB_Rating', 'No_of_Votes', 'Certificate', 'Gross']
movie_df = pd.read_csv('imdb_top_1000.csv')
movie_df = movie_df[cols]

# 영화 제목을 인덱스로 설정
movie_df.set_index('Series_Title')
'''
비파괴적 처리기 때문에 저장은 안되었다.
인덱스 열로 지정되면서 사용된 열이 삭제되었다. (마치 move처럼)
.set_index도 inplace= 인자를 제공한다.
'''
# 영화 제목을 인덱스로 설정, drop=False라서 Series_Title이 여전히 열에 있다.
movie_df.set_index('Series_Title',drop=False)
# 영화 제목을 인덱스로 설정, drop=True라서 Series_Title가 열에서 없어졌다.
movie_df.set_index('Series_Title',drop=True)

# 열 변경 후 저장 -> 열 이름 변경
movie_df= movie_df.set_index('Series_Title')
movie_df.index.name = 'Title'
# 인덱스 초기화
movie_df.reset_index() # 직접 속성에 접근해서 변경한 Series_Title -> Title은 유지
# 기존 인덱스를 데이터 열로 삽입되지않고 삭제됩니다.
# 인덱스는 기본 정수형 인덱스로 재설정됩니다.
movie_df.reset_index(drop=True)

# 가져올 열과 인덱스 열을 지정하기
movie_df = pd.read_csv('imdb_top_1000.csv',usecols=cols,index_col='Series_Title')

 

DataFrame기초 - 행렬삭제(drop, errors=)
import pandas as pd
movie_df = pd.read_csv('imdb_top_1000.csv')

#.drop() - 1. 열 삭제(columns=)
movie_df.drop(columns=['Poster_Link', 'Overview'], inplace=True)

#.drop() - 2. 행 삭제(by label)
# index label이 1인 것을 삭제
movie_df.drop(labels=1, inplace=True)

#.drop() - 3. 행 삭제(by labels, list-like)
# 삭제할 index label을 리스트로 전달
movie_df.drop([5, 7, 9], inplace=True)

#.drop() - 4. 열 삭제(axis=1 필요)
movie_df.drop(['Star1','Star2','Star3','Star4'],axis=1,inplace=True)
# 이미 삭제한 데이터라 에러 발생
movie_df.drop([2,3,4],inplace=True)
# 이미 삭제한 데이터지만 에러가 발생안 함
movie_df.drop([2,3,4],inplace=True,errors='ignore')

# del을 이용한 열 삭제
# Runtime을 삭제를 한다고 할 때
del movie_df['Runtime']
# 이미 삭제된, 없는 열을 삭제 시도하면 에러 발생
del movie_df['Runtime']

 

DataFrame기초 - 열 조회와 추가(get, insert, array-like vs Series)
import pandas as pd
cols = ['Series_Title', 'Released_Year', 'Meta_score', 'IMDB_Rating', 'Overview']
# 가져올 열 지정하기
movie_df = pd.read_csv('imdb_top_1000.csv', usecols=cols)

# 단일 열 조회를 하면 Series가 return된다.
movie_df['Series_Title']
# 다중 열 조회를 하면 DataFrame
movie_df[['Series_Title','IMDB_Rating']]
# 없는 열을 조회하면 Error
movie_df['AAA']

#좀 더 안전하게 가져올 땐, 파이썬 Dictionary처럼 .get()를 이용
movie_df.get('Series_Title')
movie_df.get([['Series_Title','IMDB_Rating']])
movie_df.get('AAA') #None
'''
에러 발생을 제어할 건지
.get()함수로 안전하게 조회할 건지 결정
[ ] 로 접근하는 건 address access고 .get()조회하는 건 return value(값 반환)이라서
전자는 접근 후 수정이 되고, 후자는 수정이 되지 않는다.
'''

'''
열 추가 - 1. 일련화 된 값
-내가 본 영화를 체크하는 란을 만들자.
-리스트의 .append()처럼 위치는 지정할 수 없다. (뒤에 붙음)
'''
# 마치 dict형에서 값 추가하듯
movie_df['Watched'] = False

'''
열 추가 - 2. .insert()를 이용한 일련화된 값
-나만의 평점을 추가해본다고 하자
-.insert()를 이용하면 위치도 지정할 수 있다.
'''
# Watched 앞에 넣어보자 ->  추가된 후 최종 위치 -> 0 1 2 3 4 [5] 6위치
movie_df.insert(loc=5, column='My_score', value=None)

'''
열 추가 - 3. 다양한 값 추가(Series or array-like)
-value인자 설명을 보면 Series or array-like
-Series와 array-like가 개수만 맞다면 추가 가능
'''
# 예시 watched 생성
watched = [True,False] * 500
# 처음 배운 [] 방식으로 추가하기
movie_df['Watched'] = watched

# 임의 시리즈 생성
import random
my_score = [random.randint(0, 10) for x in range(1000)]
my_score_series = pd.Series(my_score)
# IMDB_Rating 앞에 추가해보자.
movie_df.insert(loc=2, column='My_score', value=my_score_series)

# 만일 데이터 개수가 안 맞는다면
# 테스트 1000개 <-999개  : 에러발생
movie_df['new_Watched'] = watched
# 테스트 1000개 <-999개  : 일치된 인덱스에 맞춰 값 추가, 일치되지 않은 행은 NaN
movie_df.insert(loc=2, column='New_My_score', value=my_score_series) 
movie_df['new_new_Score'] = my_score_series

 

DataFrame기초 - 결측치 제어(dropna, how=, subset=)
import pandas as pd
cols = ['Released_Year', 'Genre', 'Series_Title', 'Director', 
		'Meta_score', 'IMDB_Rating', 'No_of_Votes', 'Certificate', 'Gross']
# 가져올 열 지정하기
movie_df = pd.read_csv('imdb_top_1000.csv')
movie_df = movie_df[cols]

# 모든 row x col의 공간. 즉 row의 cell에 NaN이 있으면 1개라도 있으면 row 삭제
movie_df.dropna()
# default : axis=0 -> row를 삭제
# 만일 default : axis=1이면? -> col을 삭제
movie_df.dropna(axis=1)

'''
how= : NA발견시 제거되는 방식 설정
-NA 발견시 행 또는 열이 데이터프레임에서 제거되는 방식을 결정
-'any' : 만약 NA 값이 하나라도 존재한다면, 해당 행 또는 열을 제거, default
-'all' : 만약 모든 값이 NA인 경우에 해당하는 행 또는 열을 제거
'''
# 연습용 데이터
data = {
    'A' : [1, 2, None, 4],
    'B' : [None, None, None, 8],
    'C' : [9, None, None, None],
    'D' : [None, None, None, None]
}

data_df = pd.DataFrame(data)
# D열 삭제
data_df.dropna(how='all',axis=1)

#subset= : 특정열의 NA만 확인
# Certificate 열의 NA여부만 확인하고 dropna()를 실행하면
movie_df.dropna(subset='Certificate') #Certificate가 NaN인 경우 row가 삭제
movie_df.dropna(subset=['Certificate', 'Gross'])

 

DataFrame기초 - 결측치 제어(fillna, method=, limit=)
# 연습용 데이터
data = {
    'A' : [1, 2, None, 4],
    'B' : [None, None, None, 8],
    'C' : [9, None, None, None],
    'D' : [None, None, None, None]
}

data_df = pd.DataFrame(data)

# value=를 이용하여 결측치 대체
data_df.fillna(value=0)
# method='ffill' -> NA를 이전 행 같은 열의 관찰 값으로 대체
data_df.fillna(method='ffill')
# method='bfill' -> NA를 다음 행 같은 열의 관찰 값으로 대체
data_df.fillna(method='bfill')

# method='ffill' -> NA를 같은 행 이전 열의 관찰 값으로 대체
data_df.fillna(method='ffill',axis=1)
# method='bfill' -> NA를 다음 행 같은 열의 관찰 값으로 대체
data_df.fillna(method='bfill',axis=1)

#limit= -> 연속되어 결측치를 나올 경우, 결측치 대체 횟수 지정
# limit=2로 제한
data_df.fillna(method='ffill',limit=2)
# value=로 결측치 대체값을 지정하고 limit=으로 최대 횟수 제한
data_df.fillna(value=-9,limit=2)