(10주차) 5월6일
판다스
-
(1/8) 부분 데이터 꺼내기: 판다스를 왜 써야할까?
-
(2/8) pandas 개발동기
-
(3/8) 열의 이름 부여
-
(4/8) 행의 이름 부여, 자료형, len, shape, for문의 반복변수, pd.Series
-
(5/8) 첫번째 칼럼을 선택, 여러개의 칼럼을 선택
-
(6/8) 첫번째 행의 선택, 여러개의 행을 선택
-
(7/8) query (1)
-
(8/8) query (2), 판다스공부 3단계
import numpy as np
import pandas as pd
-
예제1: 기본인덱싱
a='asdf'
a[2]
a[-1]
-
예제2: 슬라이싱
a='asdf'
a[1:3]
a[-2:]
-
예제3: 스트라이딩
a='asdfg'
a[::2]
-
예제4: 불가능한것
a='asdf'
a[[1,2]] # 정수인덱스를 리스트화 시켜서 인덱싱하는 것은 불가능
a='asdf'
a[[True,True,False,False]]
-
예제1: 인덱스의 리스트 (혹은 ndarray)를 전달
a=np.arange(55,61)
a
a[[1,2,-1]]
a[np.array([1,2,-1])]
-
예제2: bool로 이루어진 리스트 (혹은 ndarray)를 전달
a=np.arange(55,61)
a
a[[True,True,False,False,False,False]]
a[np.array([True,True,False,False,False,False])]
a[a<58]
-
예제1
a = np.arange(4*3).reshape(4,3)
a
a[0:2,1]
-
예제2: 차원을 유지하면서 인덱싱을 하고 싶으면?
a = np.arange(4*3).reshape(4,3)
a[0:2,[1]]
-
예제1: (key,value)
d={'att':65, 'rep':45, 'mid':30, 'fin':100}
d
d['att'] # key를 넣으면 value가 리턴
-
예제2: numpy와 비교
np.random.seed(43052)
att = np.random.choice(np.arange(10,21)*5,200)
rep = np.random.choice(np.arange(5,21)*5,200)
mid = np.random.choice(np.arange(0,21)*5,200)
fin = np.random.choice(np.arange(0,21)*5,200)
key = ['202212'+str(s) for s in np.random.choice(np.arange(300,501),200,replace=False)]
test_dic = {key[i] : {'att':att[i], 'rep':rep[i], 'mid':mid[i], 'fin':fin[i]} for i in range(200)}
test_ndarray = np.array([key,att,rep,mid,fin],dtype=np.int64).T
del(att);del(rep);del(mid);del(fin);del(key)
학번 '202212460'에 해당하는 학생의 출석점수를 알고 싶다면?
(풀이1)
test_dic['202212460']['att']
(풀이2)
test_ndarray[test_ndarray[:,0] == 202212460, 1] ## 이게 무슨코드야 도데체!
(풀이2)가 (풀이1)에 비하여 불편한 점
- test_ndarray의 첫칼럼은 student id 이고 두번째 칼럼은 att라는 사실을 암기하고 있어야 한다.
- student id가 아니고 만약에 학생이름을 써서 데이터를 정리한다면 모든 자료형은 문자형이 되어야 한다.
- 작성한 코드의 가독성이 없다. (위치로 접근하기 때문)
-
요약: hash 스타일로 정보를 추출하는 것이 유용할 때가 있다. 그리고 보통 hash 스타일로 정보를 뽑는 것이 유리하다. (사실 numpy는 정보추출을 위해 개발된 자료형이 아니라 행렬 및 벡터의 수학연산을 지원하기 위해 개발된 자료형이다)
-
소망: 정보를 추출할때는 hash 스타일도 유용하다는 것은 이해함 $\to$ 하지만 나는 가끔 넘파이스타일로 정보를 뽑고 싶은걸? 그리고 딕셔너리 형태가 아니고 엑셀처럼(행렬처럼) 데이터를 보고 싶은걸? $\to$ pandas의 개발
np.random.seed(43052)
att = np.random.choice(np.arange(10,21)*5,20)
rep = np.random.choice(np.arange(5,21)*5,20)
mid = np.random.choice(np.arange(0,21)*5,20)
fin = np.random.choice(np.arange(0,21)*5,20)
key = ['202212'+str(s) for s in np.random.choice(np.arange(300,501),20,replace=False)]
test_dic = {key[i] : {'att':att[i], 'rep':rep[i], 'mid':mid[i], 'fin':fin[i]} for i in range(20)}
test_dic
- 테이블형태로 보고 싶다.
(방법1) -- 행렬이기는 하지만 방법 2,3,4,5 에 비하여 우리가 원하는 만큼 가독성을 주는 형태는 아님..
test_ndarray = np.array([key,att,rep,mid,fin],dtype=np.int64).T
test_ndarray
(방법2)
pd.DataFrame(test_dic).T
(방법3)
test_dic2 = {'att':{key[i]:att[i] for i in range(20)},
'rep':{key[i]:rep[i] for i in range(20)},
'mid':{key[i]:mid[i] for i in range(20)},
'fin':{key[i]:fin[i] for i in range(20)}}
pd.DataFrame(test_dic2)
(방법4)
df = pd.DataFrame({'att':att, 'rep':rep, 'mid':mid, 'fin':fin},index=key)
df
(방법5)
df = pd.DataFrame({'att':att, 'rep':rep, 'mid':mid, 'fin':fin})
df
df=df.set_index([key])
df
-
예제1: 출석점수를 출력
test_dic2['att']
df['att']
-
예제2: 학번 202212380'의 출석점수 출력
test_dic2['att']['202212380']
df['att']['202212380']
-
예제1: 첫번째 학생의 기말고사 성적을 출력하고 싶다.
test_ndarray[0,-1]
df.iloc[0,-1]
- 벼락치기: df에서 iloc이라는 특수기능을 이용하면 넘파이 인덱싱처럼 원소출력이 가능하다.
-
예제2: 홀수번째 학생의 점수를 뽑고 싶다.
test_ndarray[::2]
df.iloc[::2]
-
예제3: 맨 끝에서 3명의 점수를 출력하고 싶다.
test_ndarray[-3:]
df.iloc[-3:]
df[-3:]
-
예제4: 맨 끝에서 3명의 점수중 마지막 2개의 칼럼만 출력하고 싶다.
test_ndarray[-3:,-2:]
df.iloc[-3:,-2:]
-
예제1: 중간고사 점수가 20점 이상이면서 동시에 출석점수가 60점미만인 학생들의 기말고사 점수를 출력
(방법1) 데이터베이스 스타일
df.query("mid >= 20 and att <60")
df.query("mid >= 20 and att <60")['fin']
(방법2) 넘파이 스타일이라면?
test_ndarray
test_ndarray[:,3] >= 20 ## 중간고사가 20점이상
test_ndarray[:,1] < 60 ## 출석이 60미만
(test_ndarray[:,3] >= 20) & (test_ndarray[:,1] < 60)
test_ndarray[(test_ndarray[:,3] >= 20) & (test_ndarray[:,1] < 60),-1] # 이게 무슨코드야
- 구현난이도 어려움, 가독성 꽝
-
예제2: '중간고사점수<기말고사점수'인 학생들의 출석점수 평균을 구하자.
df.query('mid<fin')['att'].mean()
-
방법1: dictionary에서 만든다.
pd.DataFrame({'att':[30,40,50],'mid':[50,60,70]})
pd.DataFrame({'att':(30,40,50),'mid':(50,60,70)})
pd.DataFrame({'att':np.array([30,40,50]),'mid':np.array([50,60,70])})
-
방법: 2차원 ndarray에서 만든다.
np.arange(2*3).reshape(2,3)
pd.DataFrame(np.arange(2*3).reshape(2,3))
-
방법1: 딕셔너리를 통하여 만들면 딕셔너리의 key가 자동으로 열의 이름이 된다.
pd.DataFrame({'att':np.array([30,40,50]),'mid':np.array([50,60,70])})
-
방법2: pd.DataFrame()의 옵션에 columns를 이용
pd.DataFrame(np.arange(2*3).reshape(2,3),columns=['X1','X2','X3'])
-
방법3: df.columns에 원하는 열이름을 덮어씀 (1)
df=pd.DataFrame(np.arange(2*3).reshape(2,3))
df
df.columns = ['X1','X2','X3']
df
df.columns
-
방법4: df.columns에 원하는 열이름을 덮어씀 (2)
df=pd.DataFrame(np.arange(2*3).reshape(2,3))
df
df.columns = pd.Index(['X1','X2','X3'])
df
방법4가 방법3의 방식보다 컴퓨터가 이해하기 좋다. (= 불필요한 에러를 방지할 수 있다)
df.columns, type(df.columns)
['X1','X2','X3'], type(['X1','X2','X3'])
pd.Index(['X1','X2','X3']), type(pd.Index(['X1','X2','X3']))
-
방법1: 중첩 dict이면 nested dic의 key가 알아서 행의 이름으로 된다.
pd.DataFrame({'att':{'guebin':30, 'iu':40, 'hynn':50} , 'mid':{'guebin':5, 'iu':45, 'hynn':90}})
-
방법2: pd.DataFrame()의 index 옵션 이용
pd.DataFrame({'att':[30,40,50] , 'mid':[5,45,90]}, index=['guebin','iu','hynn'])
-
방법3: df.index에 덮어씌움
df=pd.DataFrame({'att':[30,40,50] , 'mid':[5,45,90]})
df
df.index = pd.Index(['guebin','iu','hynn'])
#df.index = ['guebin','iu','hynn'] <- 이것도 실행 되기는 된다.
df
-
방법4: df.set_index() 를 이용하여 덮어씌운다
df=pd.DataFrame({'att':[30,40,50] , 'mid':[5,45,90]})
df
df.set_index(pd.Index(['guebin','iu','hynn']))
(주의) 아래는 에러가 난다.
df.set_index(['guebin','iu','hynn'])
df.set_index([['guebin','iu','hynn']]) # 꺽쇠를 한번 더 넣어주면 에러를 피할수 있다.
df = pd.DataFrame({'att':[30,40,50],'mid':[5,45,90]})
df
-
type
type(df)
-
len
len(df) # row의 갯수
-
shape
df.shape
-
for문의 반복변수
for k in df:
print(k) # 딕셔너리같죠
for k in {'att':[30,40,50],'mid':[5,45,90]}:
print(k)
-
2차원 ndarray가 pd.DataFrame에 대응한다면 1차원 ndarray는 pd.Series에 대응한다.
a=pd.Series(np.random.randn(10))
a
type(a)
len(a)
a.shape
for value in a:
print(value)
-
데이터
np.random.seed(43052)
att = np.random.choice(np.arange(10,21)*5,20)
rep = np.random.choice(np.arange(5,21)*5,20)
mid = np.random.choice(np.arange(0,21)*5,20)
fin = np.random.choice(np.arange(0,21)*5,20)
key = ['202212'+str(s) for s in np.random.choice(np.arange(300,501),20,replace=False)]
df=pd.DataFrame({'att':att,'rep':rep,'mid':mid,'fin':fin},index=key)
df
-
방법1
df.att
-
방법2: dict스타일
df['att']
-
방법3: dict스타일
df[['att']]
- df.att 나 df['att']는 series를 리턴하고 df[['att']]는 dataframe을 리턴한다.
-
방법4: ndarray스타일
df.iloc[:,0]
-
방법5: ndarray스타일
df.iloc[:,[0]]
- df.iloc[:,0]은 series를 리턴하고 df.iloc[:,[0]]은 dataframe을 리턴한다.
-
방법6: ndarray 스타일과 dict 스타일의 혼합
df.loc[:,'att']
-
방법7: ndarray 스타일과 dict 스타일의 혼합
df.loc[:,['att']]
- df.loc[:,'att']은 series를 리턴하고 df.loc[:,['att']]은 dataframe을 리턴한다.
-
방법7: nparray 스타일 + bool 인덱싱
df.iloc[:,[True,False,False,False]]
-
방법8: ndarray와 dict의 홉합형 + bool 인덱싱
df.loc[:,[True,False,False,False]]
-
방법1: dict 스타일
df[['att','fin']]
-
방법2: ndarray 스타일 (정수리스트로 인덱싱, 슬라이싱, 스트라이딩)
df.iloc[:,[0,1]] # 정수의 리스트를 전달하여 컬럼추출
df.iloc[:,range(2)]
df.iloc[:,:2] # 슬라이싱 , 0,1,2에서 마지막 2는 제외되고 0,1에 해당하는 것만 추출
df.iloc[:,::2] # 스트라이딩
-
방법3: ndarray 와 dict의 혼합형
df.loc[:,['att','mid']]
df.loc[:,'att':'mid'] # 마지막의 mid도 포함된다.
df.loc[:,'rep':]
-
방법4: bool을 이용한 인덱싱
df.iloc[:,[True,False,True,False]]
df.loc[:,[True,False,True,False]]
-
방법1
df.iloc[0]
-
방법2
df.iloc[[0]]
-
방법3
df.iloc[0,:]
-
방법4
df.iloc[[0],:]
-
방법5
df.loc['202212380']
-
방법6
df.loc[['202212380']]
-
방법7
df.loc['202212380',:]
-
방법8
df.loc[['202212380'],:]
-
방법9
len(df)
_lst = [True]+[False]*19
df.iloc[_lst]
df.iloc[_lst,:]
df.loc[_lst]
df.loc[_lst,:]
-
방법1
df.iloc[[0,2]]
df.iloc[[0,2],:]
-
방법2
df.loc[['202212380','202212363']]
df.loc[['202212380','202212363'],:]
-
그 밖의 방법들
df.iloc[::3] # 스트라이딩
df.iloc[:5]
df.loc[:'202212312']
df.loc[list(df.att<80),'rep':]
df.loc[df.att<80,'rep':]
df.iloc[list(df.att<80),1:]
-
아래는 에러가 난다 주의!
df.iloc[df.att<80,1:]
-
예제1
df.query('att==90 and mid>30')
-
예제2
df.query('att<rep and mid<fin')
-
예제3
df.query('att < rep < 80')
-
예제4
df.query('50 < att <= 90 and mid < fin')
-
예제5
df.query(' (mid+fin)/2 >=60')
-
예제6
_mean = df.att.mean()
_mean
df.query('att >= 73')
df.query('att >= @_mean')
# df.query('att>= _mean')은 실행 안된다.
-
예제7
df
df.query("index <= '202212354' or index=='202212387'")
사실 이 기능은 시계열자료에서 꽃핀다.
-
예제8
pd.date_range('20211226',periods=10)
_df=pd.DataFrame(np.random.normal(size=(10,4)),columns=list('ABCD'),index=pd.date_range('20211226',periods=10))
_df
_df.query(" '2021-12-29' <= index <= '2022-01-03' ")
_df.query(" '2021-12-29' <= index <= '2022-01-03' and A+B<C ")
-
query가 만능은 아니다.
df.columns = pd.Index(['att score', 'rep score', 'mid score', 'fin score'])
df.query(" att score < 90 ")
# df.loc[df['att score'] < 90,:] <-- 이렇게 구현하면 된다! (아니면 변수이름을 바꿔주는 코드를 짜든가)
ndarray = np.arange(2*3).reshape(2,3)
df = pd.DataFrame(ndarray)
df
ndarray.T
df.T
ndarray.sum(axis=0)
df.sum(axis=0)
ndarray.sum(axis=1)
df.sum(axis=1)
df
ndarray.cumsum(axis=0)
df.cumsum(axis=0)
ndarray.cumsum(axis=1)
df.cumsum(axis=1)
ndarray.tolist()
df.to_dict()
df.to_numpy()
df.to_numpy().tolist()
생략
-
아래의 데이터프레임에서 1,3번째 열을 추출하라.
df= pd.DataFrame({'att':[90,90,95],'rep':[80,90,90],'mid':[50,60,70], 'fin':[70,80,50]})
df