데이터분석(AI학습 20)

이유진·2024년 7월 8일

-- 02.pandas.opynb--

Pandas

panel data and analysis

공식: https://pandas.pydata.org

Pandas : 데이터 분석 라이브러리

행(row), 열(column) 형태의 정형 데이터 객체를 다룸

2차원 데이터

엑셀의 시트, RDB 의 테이블과 같은 형태

대표적인 객체는

DataFrame 과 Series

Series

  • pandas의 기본 객체 중 하나
  • numpy의 ndarray를 기반으로 인덱싱 기능이 추가된 1차원 배열을 나타냄 (index x value 의 형태)
  • index를 지정하지 않을 시, 기본적으로 ndarray와 같이 0-based 인덱스 생성, 지정할 경우 명시적으로 지정된 index를 사용
  • 같은 타입의 0개 이상의 데이터를 가질 수 있음

import numpy as np
import pandas as pd

Series 생성

s1 = pd.Series([10, 20, 30])
s1

왼쪽이 index, 오른쪽이 value (값), dtype : 데이터 타입

데이터로만 생성했을때, index 는 0-base 인덱스로 생성됨

s1.values

s1.index

s1.dtype

s3 = pd.Series(np.arange(200))
s3

s3[4]

data=, index=, 명시하여 생성

s4 = pd.Series([1, 2, 3], [100, 200, 300])
s4

numpy는 무조건 0-base 인덱스. 그러나 pandas는 인덱스 명시 가능.

s4[0] ----> Error

s4[100]

s4.index

index는 굳이 정수일 필요 없다!

s5 = pd.Series([1, 2, 3], ['john', 'mark', 'charlie'])
s5

s5['john']

index 중복 허용된다!!!!

s6 = pd.Series([1, 2, 3], ['john', 'john', 'charlie'])
s6

s6['john'] # 결과 Series!!!

dict로 Series 생성

sdata = {'김철수': 35000, '이상현': 67000, '최종수': 12000, '박진관': 4000}
s6 = pd.Series(sdata)
s6

s7 = pd.Series(np.arange(5), index=np.arange(100, 105), dtype=np.int16)
s7

s7.index

s7.index.values

s7[102], s7[104]

s7[[102, 104]]

s7[100] # scalar value

s7[[100]] # Series 1차원

s7[[104, 102, 102, 100]]

s7[104] = 70
70

s7[105] = 90 # 없던 index에 value 대입 -> 새로 생김 Dict과 비슷함.
s7

s7[[101, 102]] = 10, 20
s7

s7.index

s8 = pd.Series(np.arange(6), s7.index) # 기존의 index 사용가능.
s8

Series name, index name, index 변경

s6

s6.name = '급여'
s6

s6.index.name = '이름'
s6

s6.index

s6.index = ['Kim', 'Lee', 'Choi', 'Park']
s6

Series ndim, shape, size, len, unique, count, value_counts 함수

  • size : 개수 반환
  • shape : 튜플형태로 shape반환
  • unique: 유일한 값만 ndarray로 반환
  • count : NaN을 제외한 개수를 반환
  • mean: NaN을 제외한 평균
  • value_counts: NaN을 제외하고 각 값들의 빈도를 반환

s1 = pd.Series([1, 1, 2, 1, 2, 2, 2, 1, 1, 3, 3, 4, 5, 5, 7, np.NaN])
s1

NaN (Not a Number : 숫자가 들어와야 하는데 숫자가 아닌 값)

실무 데이터를 다루다 보면 NaN 을 엄청나게 자주 만나게 된다.

원본데이터의 '누락' 이라든지, DBMS 상의 null 값이라든지 등등. 여러가지 이슈로 NaN 값 발생

그래서 데이터 분석시 NaN 값을 제거 하든지 혹은 치환 하든지.. 해서 처리할줄 알아야 한다

s1

s1.ndim

s1.shape

s1.size

len(s1)

s1.unique()

s1.count() # 실제 데이터가 있는 값만 count! NaN은 제외됨.

a1 = np.array([2, 2, 2, 2, np.NaN])
a1.mean() # nan 이 나온다... numpy 의 경우 array 원소 중에 NaN 이 있으면 연산 불가 (즉 NaN 이 나옴)

pd.Series(a1).mean() # NaN 원소 무시하고 평균값 산출

s1.value_counts()

s1.head() # 상위 5개

s1.tail() # 하위 5개

s1.head(3)

s1.tail(3)

Series 연산

  • index 기준으로 연산

numpy 와 마찬가지로

Series 도 Series 끼리 연산 가능.

기억하실 포인트는 '같은 인덱스' 기준으로 연산한다는 겁니다

이 특징은 DataFrame 에서도 동일하게 적용됩니다.

s1 = pd.Series([1, 2, 3, 4], ['a', 'b', 'c', 'd'])
s2 = pd.Series([6, 3, 2, 1], ['d', 'c', 'b', 'a']) # 인덱스 순서 다르다

s1

s2

s1 + s2

산술연산

  • Series의 경우에도 스칼라와의 연산 각 원소별로 스칼라와의 연산이 적용
  • Series와의 연산은 각 인덱스에 맞는 값끼리 연산이 적용
    • 이때, 인덱스의 pair가 맞지 않으면, 결과는 NaN

s1 ** 2

s1 ** s2

s1['k'] = 7
s2['e'] = 9

s1

s2

s1 + s2

Boolean selection

  • boolean Series가 []와 함께 사용되면 True 값에 해당하는 값만 새로 반환되는 Series객체에 포함됨
  • 다중조건의 경우, &(and), |(or)를 사용하여 연결 가능

s = pd.Series(np.arange(10), np.arange(10) + 1)
s

s > 5 # 결과는 boolean series

s[s > 5]

s[s % 2 == 0]

index를 사용한 필터링도 가능!

s.index > 5 # boolean mask

s[s.index % 2 == 0]

Series 값 삭제 : drop()

s = pd.Series(np.arange(100, 105), ['a', 'b', 'c', 'd', 'e'])
s

s['a'] = 200
s

s['k'] = 300
s

s.drop('k') # 원본 변화 없음

s

★중요★

drop() 함수는 drop 한'결과' 를 새로 만들어서 리턴한거고

원본 데이터 s 는 '변경'하지 않습니다

numpy , pandas, 그밖의 수많은 데이터 관련 모듈들 에서의

대부분의 객체 함수들은 호출한 원본 객체를 '변경'하진 않고

원본의 '사본'을 만든뒤 '사본' 에 연산수행하여 그 '사본' 을 리턴하도록 동작 한다

(함수마다 조금씩 다르긴 하다)

그러나!

inplace=True 파라미터를 주면 '사본' 을 만들지 않고 '원본'을 변화시키도록 동작한다

s.drop('k', inplace = True) # 리턴값이 None(없다)! 따라서 원본이 변한다.

s

Slicing

  • 리스트, ndarray와 동일하게 적용
  • index 가 문자열인 경우 slicing 시 마지막도 포함 (ndarray 와 차이점!)

s1 = pd.Series(np.arange(100, 105))
s1

s[1:3]

인덱스가 '문자' 인경우는 어떻게 될까?

s2 = pd.Series(np.arange(100, 105), ['a','b','c','d','e'])
s2

s2[1:3] # 동작한다!?!?!! # 인덱스가 숫자타입이 아닌경우, 0-base 인덱싱, 슬라이싱 사용 가.능

s2['b':'d'] # index가 문자열타입인 경우 마지막 index값 포함.

Multi level index

s3 = pd.Series([1, 2, 3, 4, 5, 6], ['a', 'a', 'b', 'b', 'c', 'c'])
s3

단일 level index다

s3.index

multi level index를 가진 Series

s4 = pd.Series(
np.arange(100,106),
index = [['a', 'a', 'b', 'b', 'c', 'c'],
[ 1, 2, 1, 2, 1, 2]]
)
s4

s4.index

tuple 인덱싱으로 value 접근

s4['a', 1]

s4['a']

s4 : 2-level index

s4['a'] : 1-level index

s4['a'][1]

s4['a':'b'] # level 0의 슬라이스 인덱스

s4[('a',2):('b',2)]

xs() 를 사용한 인덱스

cross-section

axis = 0, level = 0

s4.xs('a') # level 0 인덱싱 <= s4['a']와 동일

s4.xs(('a',1)) # <= s4['a', 1]과 동일

s4

s4.xs(2) # 에러 : level값을 적지 않으면 0(Default) 에서 검색함.

s4.xs(2, level = 1)

s4.xs(2, level = -1)

s4.xs((2,'b'), level=(1,0))

Series에서 level 별 계산

data = pd.Series(
[100, 200, 300, 400, 500, 600],
index=[
["a", "a", "a", "b", "b", "c"], # level 0 index
[1, 2, 3, 1, 2, 1], # level 1 index
]
)
data

data.sum()

data.mean()

data.sum(level=None)

data.sum(level=0)

data.groupby(level=0).sum()

profile
독해지자

0개의 댓글