# 파이썬 머신러닝 판다스 데이터 분석 교재 실습 시작
1. 데이터 과학자가 판다스를 배우는 이유?
- 데이터과학은 데이터를 연구하는 분야이고, 데이터 자체가 가장 중요한 자원이다.
- 실제로 데이터 분석 업무의 80~90%는 데이터를 수집하고 정리하는 일이 차지한다고 볼 수 있다.
- 데이터과학자가 하는 가장 기초적이고 중요한 일은 데이터를 수집하고 분석이 가능한 형태로 정리하는 것이다.
- 판다스 라이브러리는 데이터를 수집하고 정리하는 데 최적화된 도구라고 할 수 있다.
* 데이터를 신뢰할 정도로 만든다? => 데이터 정리를 잘한다!
2. 판다스 자료구조
- 판다스는 시리즈(Series)와 데이터프레임(DataFrame)이라는 구조화된 데이터 형식을 제공한다.
- 이때, 시리즈는 1차원 배열이고, 데이터프레임은 2차원 배열이라는 점에서 차이가 있다.
- 판다스의 1차적인 목적은 서로 다른 여러 가지 유형의 데이터를 공통의 포맷으로 정리하는 것이다.
* 시리즈(1차원 배열)을 여러개 붙여놓으면 데이터프레임(2차원 배열)이 된다.
- 일단 외부에 있는 pandas 라이브러리 설치!
! pip install pandas # Jupyter
pip install pandas # Terminal
[ Series(시리즈) ]
- 인덱스(index) 는 데이터 값(value)과 일대일 대응이 된다.
=> 키(k)와 값(v)이 '{k:v}'의 현태로 짝을 이루는 파이썬 딕셔러니(dictionary)와 비슷한 구조를 갖는다.
- 딕셔너리 → 시리즈 변환 : pandas.Series(딕셔너리)
import pandas as pd
dict_data = {'a':1, 'b':2, 'c':3} # 딕셔너리
sr = pd.Series(dict_data) # 딕셔너리 dict_data 를 series 로 변환하는 명령문
print(sr)
print(type(sr))
: 이 경우, 이차원 배열이 아니라 key와 value로 구성된 1차원 배열이다. 여기서는 key가 index와 동일한데, 여기서는 a,b,c가 key이다.
import pandas as pd
list = ['2022-08-23', 3.14, 'abc', True]
sr = pd.Series(list)
print(sr)
print(type(sr))
: 이 경우, index 값으로 볼 수 있는 key값이 없기 때문에 0 1 2 3의 index가 나온다.
- Series 클래스의 index 속성을 이용하여 인덱스 배열을 따로 선택할 수 있다
=> 인덱스 배열 : Series객체.index
- 또한 데이터 값 배열만을 따로 선택하는 것도 가능하다
=> 데이터 값 배열 : Series객체.values
import pandas as pd
tuple = ('2022-08-23', 3.14, 'abc', True)
sr = pd.Series(tuple)
print(sr)
print(type(sr))
print(sr[2]) # 2의 인덱스 값을 갖는 abc 문자열이 출력된다.
- 원소의 위치를 나타내는 주소 역할을 하는 인덱스를 이용하여 시리즈의 원소를 선택한다.(하나도 가능, 여러개도 가능)
import pandas as pd
list = ['2022-08-23', 3.14, 'abc', True]
sr = pd.Series(list, index=['날짜', '숫자', '문자', '논리값'])
print(sr)
print(type(sr))
print(sr["문자"])
print()
print(sr[[0,2]])
print()
print(sr['숫자':'논리값'])
: 위의 코드블럭을 살펴보자. 3번째 코드에서 index에 이름을 지정해주는 것을 볼 수 있다. print(sr[[0.2]])에서 index0과 index2의 데이터 값인 날짜와 문자를 보여주고 있다는 것을 확인할 수 있다. 또한, 코드의 마지막줄에서 index의 이름으로도 슬라이싱이 가능하다는 것을 확인할 수 있다.
- index 값이 아니라 index의 이름으로도 인덱싱이나 슬라이싱이 가능하다.
- 슬라이싱은 콜론(:)을 사용해서 표현하지만, 연속적이지 않은 두가지 이상의 데이터값을 꺼낼 경우에는 그냥 해당 index를 콤마(,)로 구분할 수 있다.
[ 데이터프레임(DataFrame) ]
- 데이터프레임은 2차원 배열이다.
- 마이크로소프트 엑셀(Excel)과 관계형 데이터베이스(RDBMS) 등 컴퓨터 관련 다양한 분야에서 사용된다.
- 시리즈를 열벡터(vector), 데이터프레임은 2차원 벡터 또는 행렬(matrix)라고 한다.
- 데이터프레임은 행 인덱스(row index), 열 이름(column name 또는 column label)로 구분한다.
- 딕셔너리 → 데이터프레임 변환 : pandas.DataFrame(딕셔너리 객체)
import pandas as pd
dict = {"c0": [1,2,3], "c1":[4,5,6], "c2":[7,8,9],"c3":[10,11,12]}
df = pd.DataFrame(dict)
print(df)
print(type(df))
print()
: 이때 딕셔너리의 키(k)가 열 이름이 되고, 값(v)에 해당하는 각 리스트가 데이터프레임의 열이 된다. 행 인덱스에는 정수형 위치 인덱스가 자동으로 지정된다. 이는 따로 지정해주지 않았기 때문에 그렇다.
- 행 인덱스/열 이름 설정 : pandas.DataFrame(2차원 배열, index=행 인덱스 배열, columns=열 이름 배열)
import pandas as pd
df = pd.DataFrame([[15, '남', '덕영중'], [17, '여', '수리중'],
[19, '여자', '이미중']],
index = ['준서', '효린', '예은'],
columns=['나이', '성별', '학교'])
print(df)
print()
print(df.index)
print(df.columns)
print()
: 위의 코드블럭을 살펴보자. df의 3개의 리스트로 구성된 첫번째 리스트는 각 행열의 요소라고 할 수 있다. → 이때 2차원 배열이기 때문에 [] 로 한번 더 감싸야 한다. df의 두번째 index=['준서', '효린', '예은']는 각각의 행 인덱스의 이름을 지정해주는 코드이다. df의 세번째 columns=['나이', '성별', '학교']는 각각의 열 이름을 지정해주는 코드이다. print(df.index) 는 이 데이터의 index를 출력해준다. print(df.colunms)는 이 데이터의 columns를 출력해준다.
- csv 파일을 가져와서 가장 먼저 해야할 것은 바로 columns를 확인하는 것이다.
- columns를 변수로 가져와서 사용할 수 있다.
- df.index는 df.columns보다 사용빈도는 낮을 수도 있지만 알아두는 것이 좋다.
- 행 인덱스 변경 : DataFrame 객체.index = 새로운 행 인덱스 배열
- 열 이름 변경 : DataFrame 객체.columns = 새로운 열 이름 배열
import pandas as pd
df = pd.DataFrame([[15, '남', '덕영중'], [17, '여', '수리중'],
[19, '여자', '이미중']],
index = ['준서', '효린', '예은'],
columns=['나이', '성별', '학교'])
df.index=['학생1', '학생2', '학생3']
df.columns=['연령', '남녀', '소속']
print(df)
print()
: 위의 코드 블럭을 살펴보자. 해당 행 인덱스의 이름과 열 이름을 변경하고자 할 때 사용한다. 단, 변경보다도 지정하고 싶을 경우 많이 사용한다. 변수를 사용할 때 내가 편한 이름으로 변경해서 사용할 때 사용한다.
- 다른 방법도 있다.
- 행 인덱스 변경 : DataFrame 객체.rename(index={기존 인덱스:새 인덱스 ... })
- 열 이름 변경 : DataFrame 객체.rename(columns={기존 이름:새 이름 ... })
import pandas as pd
df = pd.DataFrame([[15, '남', '덕영중'], [17, '여', '수리중'],
[19, '여자', '이미중']],
index = ['준서', '효린', '예은'], # index 즉, 행 인덱스의 이름을 지정해준다.
columns=['나이', '성별', '학교']) # 열 이름을 지정해준다.
df.rename(columns={'연령':'나이', '남녀':'성별', '소속':'중학교명'}, inplace=True)
print(df)
print()
df.rename(index={'학생1':'재석', '학생2':'석진', '학생3':'종국'}, inplace=True)
print(df)
: 위의 코드 블럭을 살펴보자. 이것도 열 이름을 변경하는 코드이다. 열 이름을 한번에 바꾸고자 할 경우 사용한다. inplace = True는 원본 객체를 직접 변경하기 위해서 사용 False를 사용하면 새로운 객체가 생성되고 원본 객체는 변경되지 않는다. inplace를 설정해주지 않으면 안바뀐다!
- 행 삭제 : DataFrame 객체.drop(행 인덱스 또는 배열, axis=0)
- 열 삭제 : DataFrame 객체.drop(열 이름 또는 배열, axis=1)
import pandas as pd
exam_data = {
'수학':[90,80,70], '영어':[98,89,95],
'음악':[85,95,100], '체육':[100,90,90]
}
# 원본 데이터
df = pd.DataFrame(exam_data, index=['서준', '우현', '인아'])
print(df)
print()
# df2에 df 데이터 모두 복제
df2 = df[:]
print(id(df), id(df2)) # 깊은복사인지 얕은복사인지 확인한다. 주소값이 달라? ==> 얕은 복사 df2는 100퍼센트 사본데이터이다!
print()
df2.drop('우현', inplace=True) # '우현'의 데이터가 모두 날아감
print(df2)
print()
df3 = df[:]
df3.drop(['서준','인아'], axis=0, inplace=True) # '서준'과 '인아'데이터 삭제 axis=0은 행 기준으로 삭제함 1은 열 기준으로 삭제함
print(df3)
print()
df4 = df[:]
df4.drop(['서준','인아'], inplace=True)
print(df4)
print()
df4.drop(['음악'], axis=1, inplace=True) # '음악' 열을 삭제
print(df4)
: 행을 삭제할 때는 축(axis) 옵션으로 axis=0을 입력하거나, 별도로 입력하지 않는다. 축 옵션으로 axis=1을 입력하면 열을 삭제한다. 또한, 원본 객체를 직접 변경하기 위해서는 inplace = True 옵션을 추가한다. inplace=False 옵션으로 추가하게 되면 새로운 객체가 생성되고, 원 객체는 변경없이 그대로 유지된다.
- 행 선택
구분 | loc | iloc |
탐색 대상 | 인덱스 이름(index label) | 정수형 위치 인덱스(integer position) |
범위 지정 | 가능(범위의 끝 포함) 예) [ 'a' : 'c' ] → 'a', 'b', 'c' |
가능(범위의 끝 제외) 예 [ 3 : 7 ] → 3, 4, 5, 6 (*7제외) |
import pandas as pd
exam_data = {
'수학':[90,80,70, 80], '영어':[98,89,95,75],
'음악':[85,95,100,90], '체육':[100,90,90,55]
}
df = pd.DataFrame(exam_data, index=['재석', '석진', '우영', '지효'])
print(df)
print()
ld1 = df.loc['석진']
print(ld)
print()
ld2 = df.iloc[1]
print(ld)
print()
ld3 = df.loc[['석진', '우영']]
print(ld3)
print()
ld4 = df.iloc[[1,2]]
print(ld4)
print()
ld5 = df.loc['재석':'석진']
print(ld5)
print()
ld6 = df.iloc[1:3]
print(ld6)
: 1) loc와 iloc의 차이 → loc : 행 인덱스 이름을 기준, iloc : 행 인덱스 위치 번호를 기준
2) 연속적이지 않은 2개 이상의 데이터를 가져오려면 [] 두개로 [[]] 이렇게 감싸줘야 한다.
3) 비연속적인 데이터를 2개 이상 가져오는 것은 콤마(,)로 구분한다.
4) 연속적인 데이터는 [] 하나로 감싼다.
5) 연속적인 데이터의 범위를 설정하는 것은 콜론(:)으로 구분한다.
- 열 1개 선택(시리즈 생성) : DataFrame 객체["열 이름"] 또는 DataFrame 객체.열 이름
import pandas as pd
# 열을 선택해보자
zz = df['음악']
print(zz)
print()
z1 = df.음악
print(z1)
print()
: 가져온 빅데이터에서 열 이름이 띄어쓰기가 되어 있는 경우에는 []로 묶어서 가져온다. df.주소 시군구 ==> 띄어쓰기가 있어서 불가능하다. df.['주소 시군구'] 이렇게 설정해야 한다.
- 열 n개 선택(데이터프레임 생성) : DataFrame 객체[ [ 열1, 열2, ... , 열n ] ]
import pandas as pd
# 열을 선택해보자
zz = df['음악']
# 두개 이상의 데이터를 가져오는 것도 가능하다.
z2 = df[['음악', '체육']]
print(z2)
- 데이터프레임 슬라이싱 : DataFrame 객체.[ 시작 인덱스 : 끝 인덱스 : 슬라이싱 간격 ]
- 시작 인덱스는 포함하고 끝 인덱스는 포함하지 않는다.
- 시작 인덱스와 끝 인덱스에 아무것도 안넣으면 각각 맨 처음부터, 맨 마지막까지 포함하는 것이다.
import pandas as pd
zz = df['음악']
print(zz)
print()
z5 = df[::2]
print(z5)
print()
- 역순 인덱싱(정렬)
import pandas as pd
zz = df['음악']
print(zz)
print()
z6 = df[::-1]
print(z6)
print()
예제) 인덱스 2부터 인덱스 3까지 2의 간격으로 가져온다.
import pandas as pd
zz = df['음악']
print(zz)
print()
z7 = df[2:3:2]
print(z7)
print()
- 원소 선택하기 ( 특정 열과 특정 행의 데이터만 갖고 오기 )
1) 인덱스 이름 : DataFrame 객체.loc[행 인덱스, 열 이름]
2) 정수 위치 인덱스 : DataFrame 객체.iloc[행 번호, 열 번호]
import pandas as pd
zz = df['음악']
print(zz)
print()
# 인덱스의 이름으로 가져오자
z8 = df.loc[['재석', '석진'], ['음악', '수학']]
print(z8)
print()
# 행 인덱스 위치 번호로 가져오자
z9 = df.iloc[0:3,2:]
print(z9)
- 한개의 행에 특정 열을 가져올 수 있다 iloc 역시 사용 가능하다.
import pandas as pd
zz = df['음악']
print(zz)
print()
z10 = df.loc['지효',['음악','수학']]
print(z10)
- 열 추가 : DataFrame 객체[ '추가하려는 열 이름' ] = 데이터값
- 값을 하나만 지정해주면 해당 값을 기본값으로 해 데이터를 입력해준다.
import pandas as pd
zz = df['음악']
print(zz)
print()
df['화학']=80
print(df)
print()
# abc라는 열을 추가해서 화학과 국어의 데이터를 더해줄거야?
# df[abc] = df['화학']+df['국어']
df['abc'] = df['수학'] + df['화학']
print(df)
- 행 추가 : DataFrame.loc[ '새로운 행 이름' ] = 데이터 값(또는 배열)
import pandas as pd
zz = df['음악']
print(zz)
print()
df.loc['영어'] = 0
print(df)
- 원소 값 변경 : DataFrame 객체의 일부분 또는 원소를 선택 = 새로운 값
import pandas as pd
zz = df['음악']
print(zz)
print()
df.rename(index={'영어':'나나'}, inplace=True)
print(df)
df.loc['나나'] = [20, 30, 40, 50, 60, 70]
print(df)
df.drop('석진', inplace=True)
: 위의 코드 블럭을 살펴보자. 우선 df.rename의 코드로 인덱스 영어를 나나로 변경해준다. 그리고 난 뒤 loc의 코드로 인덱스 나나행에 리스트 데이터 값을 넣어준다. 그 후 석진의 데이터를 삭제한다.
- 특정 행과 특정 열에 해당되는 특정 데이터 하나를 변경하고자 할 경우
import pandas as pd
zz = df['음악']
print(zz)
print()
df.loc['재석']['체육'] =30
print(df)
df.iloc[0][3] = 20
print(df)
df.loc['재석', '체육'] = 50
print(df)
- 한가지 행에 두가지 열을 변경하자
import pandas as pd
zz = df['음악']
print(zz)
print()
df.loc['재석', ['음악', '체육']] = 100, 80
print(df)
df.drop('나나', inplace=True)
print(df)
- 행과 열의 위치 바꾸기(행 열 전환) : DataFrame 객체.transpose() 또는 DataFrame 객체.T
import pandas as pd
zz = df['음악']
print(zz)
print()
abc = df.transpose()
print(abc)
[ 인덱스 활용 ]
- 특정 열을 행 인덱스로 설정 : DataFrame 객체.set_index( [ '열 이름' ] 또는 '열 이름')
- set_index() 메소드를 사용하여 행 인덱스를 새로 지정하면 기존 행 인덱스는 삭제된다.
exam_data = {
'이름' : ['재석', '지효', '석진', '우영'],
'수학':[90,80,70, 80], '영어':[98,89,95,75],
'음악':[85,95,100,90], '체육':[100,90,90,55]
}
dfx = pd.DataFrame(exam_data)
print(dfx)
dfx.set_index('이름', inplace=True)
print(dfx)
: 위의 코드 블럭을 살펴보자. 여기서는 해당 인덱스는 0 1 2 3 이다.
1) 그런데 이름에 해당하는 열을 인덱스로 사용하고 싶다면? df.set_index('해당열이름', inplace=True/False)는 어떤 열 자체로 index를 설정한다.
2) index를 왜 지정할까? => 데이터를 찾을 때 index를 기준으로 찾아야 한다. 즉, 주소값을 지정해준다는 소리
- 여러개의 열을 행 인덱스로 설정하는 것도 가능하다.
exam_data = {
'이름' : ['재석', '지효', '석진', '우영'],
'수학':[90,80,70, 80], '영어':[98,89,95,75],
'음악':[85,95,100,90], '체육':[100,90,90,55]
}
dfx = pd.DataFrame(exam_data)
print(dfx)
dfx.set_index(['이름', '음악'],inplace=True)
print(dfx)
- 행 인덱스 재배열
- reindex() 메소드를 사용하면 데이터프레임의 행 인덱스를 새로운 배열로 재지정할 수 있다.
- 새로운 배열로 행 인덱스를 재지정 : DataFrame 객체.reindex( 새로운 인덱스 배열 )
exam_data = {
'이름' : ['재석', '지효', '석진', '우영'],
'수학':[90,80,70, 80], '영어':[98,89,95,75],
'음악':[85,95,100,90], '체육':[100,90,90,55]
}
dfx = pd.DataFrame(exam_data)
print(dfx)
print()
dfx.set_index(['이름'],inplace=True)
new_index=['재석', '지효', '석진', '우영', '호민', '길동']
rdfx = dfx.reindex(new_index, fill_value=0)
print(rdfx)
: 위의 코드블럭을 살펴보자. fill_value = 0은 비어있는 데이터 값들을 모두 0으로 집어넣어준다. 유의할 점은 데이터가 4,5,NaN,7,8로 되어 있는 것과 4,5,0,7,8로 되어 있는 것은 많은 차이가 난다. 평균값을 구하는 등의 값들이 수치가 많이 달라질 수 있다.
※ 평균을 많이 사용하는 이유는? => 해석하기 좋기 때문(기준점으로)
결측치가 생겨도 데이터 수가 많으면 평균치 같은 수치가 흔들리지 않는다.
NaN으로 그냥 해석하냐 vs 0으로 넣어서 해석하냐의 차이점은 그냥 그때그때 합리적 의사결정을 통해서 결정을 내리는 것이다.
- 인덱스 초기화(없애기)
- 정수형 위치 인덱스로 초기화 : DataFrame 객체.reset_index()
exam_data = {
'이름' : ['재석', '지효', '석진', '우영'],
'수학':[90,80,70, 80], '영어':[98,89,95,75],
'음악':[85,95,100,90], '체육':[100,90,90,55]
}
dfx = pd.DataFrame(exam_data)
print(dfx)
print()
dfx.set_index(['이름'],inplace=True)
print(dfx)
dfx = dfx.reset_index()
print(dfx)
- 행 인덱스를 기준으로 데이터프레임 정렬
- 행 인덱스 기준 정렬 : DataFrame 객체.sort_index()
exam_data = {
'이름' : ['재석', '지효', '석진', '우영'],
'수학':[90,80,70, 80], '영어':[98,89,95,75],
'음악':[85,95,100,90], '체육':[100,90,90,55]
}
dfx = pd.DataFrame(exam_data)
print(dfx)
print()
dfx.set_index(['이름'],inplace=True)
print(dfx)
# 가나다 순으로 정렬
dfx = dfx.sort_index(ascending=False)
print(dfx)
: ascending = False 옵션을 사용하여 내림차순으로 정렬한다.
ascending = True 옵션을 사용해서 오름차순으로 정렬한다.
- 특정 열의 데이터를 기준으로 데이터프레임을 정렬할 수 있다.
- 열 기준 정렬 : DataFrame 객체.sort_values()
exam_data = {
'이름' : ['재석', '지효', '석진', '우영'],
'수학':[90,80,70, 80], '영어':[98,89,95,75],
'음악':[85,95,100,90], '체육':[100,90,90,55]
}
dfx = pd.DataFrame(exam_data)
print(dfx)
print()
dfx = dfx.sort_values(by='음악', ascending=False)
print(dfx)
'대외활동 > ABC 지역주도형 청년 취업역량강화 ESG 지원산업' 카테고리의 다른 글
[ABC 220829 - 10일차] 웹기초 실습(혼자 해본 것) (0) | 2022.08.31 |
---|---|
[ABC 220829- 10일차] 웹 기초 (0) | 2022.08.30 |
[220824 ABC - 7일차] PYTHON 기초 (0) | 2022.08.25 |
[220823 ABC - 6일차] PYTHON 라이브러리 (0) | 2022.08.25 |
[220823 ABC - 6일차] PYTHON 기초 (0) | 2022.08.25 |