ㅅㅇ

Pandas _ 01-1 pandas 개요, Series 생성 및 접근 본문

AI_STUDY/Pandas

Pandas _ 01-1 pandas 개요, Series 생성 및 접근

SO__OS 2022. 6. 3. 19:58
플레이데이터 빅데이터캠프 공부 내용 _ 6/3, 6/7

Pandas_01-1 pandas 개요, Series 생성 및 접근

1.  판다스(Pandas)

데이터 분석과 관련된 다양한 기능을 제공하는 파이썬 패키지
    - 데이터 셋을 이용한 다양한 통계 처리 기능을 제공한다.
    - 표 형태의 데이터를 다루는데 특화된 파이썬 모듈.
        - 엑셀의 기능을 제공하는 파이썬 모듈이라고 생각하면 이해가 쉽다.
    - 표 형태의 데이터를 다루기 위한 시리즈(Series)와 데이터프레임(DataFrame) 클래스 제공
   

(1) Series : 1차원 자료구조를 표현
(2) DataFrame : 행렬의 표를 표현


[설치법]
    - `pip install pandas`
    - `conda instll pandas`
    - 아나콘다에는 미리 install 되어 제공된다.
https://pandas.pydata.org/
https://pandas.pydata.org/docs/

 

2. Series 개요

: 1차원 자료구조
    - 1차원의 의미란 ?

      값의 순서를 한 방향으로만 표현한 것.
    
(1)  DataFrame(표)의 한 행이나 한 열을 표현한다.
    - 예를들어, db 테이블에서 where로 한 행만 조회했다. 그렇다면 이 한 행이 Series 자료구조로 쓸 수 있을 것.
    
(2) 각 원소는 index로 접근할 수 있다.
    - index는 순번(index)과 지정한 이름(index명) 두가지로 구성된다.
        - 순번은 자동으로 생기고 index 명은 지정해야 한다.
            - 만약 index명을 명시적으로 지정하지 않으면 순번이 index명이 된다.
    - 순번은 0부터 1씩 증가하는 정수. (양수인덱스, 음수인덱스)
    
    ** 인덱스 접근법에 대해서는 리스트와 딕셔너리을 합친 것과 같다고 생각하면 된다.
    
    
(3) 벡터화 연산(element-wise : 원소별 연산)을 지원
    - Series 객체에 연산을 하면 각각의 Series 원소들에 연산이 된다.
        - 예를 들어 한 series에 대해 10을 곱하는 처리를 명령하면 해당 모든 데이터가 원소단위로 싹다 10씩 곱해진다. 


(4) Series를 구성하는 원소들을 다루는 다양한 메소드 제공

 

3. Series 생성

- 사실, 데이터프레임을 만들지, series를 만들 일은 없다. 

그런나, 표에서 한 행이나 한 열이나 조회 결과가 시리즈로 나와 이를 사용하기 때문에 알아둬야 한다.

 

- 배열형태 자료구조    
 - 리스트
 - 튜플
 - 넘파이 배열(ndarray)

 

- 구문
    - `Series(배열형태 자료구조)`

 

(1) Series(list)  _ 인덱스명 미지정

import pandas as pd # 관례적으로 pd가 pandas의 별칭

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

 

- 조회 시 index명과 value 가 출력된다.

print(type(s1))
s1

----------------------
<class 'pandas.core.series.Series'>

index명   value
0           1
1           2
2           3
3           4
4           5
dtype: int64    series 원소들의 데이터타입  - int64 (정수 64bit : 숫자 하나를 표현하는데 64bit)

- index 순번은 자동으로 생성되는데, 지금 index명을 지정을 안 해서 index명이 순번으로 들어감.

- dtype : int 64 : series 원소들의 데이터타입 

정수 64bit : 숫자 하나를 표현하는데 64bit

** 이는 내부적으로 넘파이를 써서이다.(파이썬이랑 데이터타입이 다른 것도 있다. 이 내부는 씨언어 기반이기 때문에) 

 

 - 현재 Series에는 원소 다섯개 있다. 그렇다면 64*5 만큼 메모리 공간차리하고 있다는 것.

- int8, int16, int32, int64가 있다.

 

 

(2) Series(dict) _ 인덱스명 지정

d = {'가':1, '나':2, '다':3}
s2 = pd.Series(d)
s2

-------------------
가    1
나    2
다    3
dtype: int64

 

(3) Series(list, index=[index명]) _ 인덱스명 지정

s3 = pd.Series([80,70,90,100], index=['국어','영어','과학','수학'])
s3

------------------
국어     80
영어     70
과학     90
수학    100
dtype: int64

 

- iterator, generator을 넣으면 그 값들을 Series로 만들어 준다.

 ex) range() iterator를 넣어주었다.

s4 = pd.Series(range(10), index=list('deacfkxrju'))
s4

 -- index명에는 문자열을 list() 함수에 넣어 문자로 쪼개서 index명으로 넣어주었다.

 

4. Series안의 원소(element) 접근 _ 조회

4.1 Indexing 조회


(1) index 순번으로 조회
    - Series[순번]
    - Series.iloc[순번]
    

ex.) 

# 1) index (순번)으로 조회
print(s3[0], s3[1])    # 양수 index 접근
print(s3[-1], s3[-2]) #음수 index 접근

# 2) iloc indxer
# 그냥 순번 조회랑 똑같은 결과로 나온다.
print(s3.iloc[0], s3.iloc[1])
print(s3.iloc[-1], s3.iloc[-2])

--------------
80 70
100 90
80 70
100 90

 

(2) index 이름으로 조회
    - Series[index명]
    - Series.loc[index명]
    - Series.index명
        - index명이 문자열일 경우 `. 표기법` 사용가능 (순번조회는 안됨.)
            - 근데 공백이 있다면 조회 불가능이다. 이 방법 안됨. 변수처럼 쓸 수 있는 인덱스 일때만 가능.
  

    - index명이 문자열이면 문자열(" ") 로, 정수이면 정수로 호출
        - s['name'], s[2], 

        - s.loc['name'], s.loc[2]

 

ex) 

# (1) index이름(명) 조회
print(s3['국어'], s3['과학'])

# (2) loc indexer
print(s3.loc['국어'], s3.loc['과학'])

# (3) . 표기법 (dot notation)
print(s3.국어, s3.과학)

---------------
80 90
80 90
80 90



(3) 팬시(fancy) 인덱싱으로 조회

: 한번에 여러개의 원소(element) 들을 조회

 

- 조회하려는 index들을 리스트로 묶어서 전달
    - Series[index리스트]    =>    s[[원소1, 원소2, 원소3 ...]]
          
    - 여러 원소 조회 시 조회할 index를 list로 전달
        - `s[[1,2,3]]`  # 1번 2번 3번 인덱스 조회
        
    - 참고로 이는 판다스 기능이지. 파이썬 리스트에는 없는 기능이다.
    - 밖 [] 대괄호는 indexer연산자이고, 안 [] 대괄호는 리스트이다.

 

ex) 

print(s3[[0,1]])
print(s3[['국어','영어']])

-----------------
    국어    100
    영어     50
    dtype: int64

    국어    100
    영어     50
    dtype: int64

- 조회하려는 index들을 리스트로 묶어서 전달

fancy 방법으로 리스트로 묶어 넣으니,

인덱스명과 값이 함께 반환. 마치 인덱싱 없이 s3  시리즈 자체를 출력한 것 처럼 dtype도 출력됨.

그 중에 지정한 인덱스명과 원소만 출력.

   
4.2 Slicing 조회

: Series[start index :  end index : step]
 

  - start index

       생략하면 0번 부터


  - end index
        - index 순번일 경우는 포함 하지 않는다.
        - index 명의 경우는 포함한다. 이를 주의~!

        - end index 생략 : 마지막 index까지


    - step 

         생략하면 1씩 증가


- Slicing의 결과는 원본의 참조(View)를 반환
    - slicing한 결과를 변경시 원본도 같이 바뀐다.
    - Series.copy() : Series를 복사한 새로운 객체 반환

 

(1) index 순번으로 Slicing  조회

 

ex) index 순번 _ 양수 인덱스

# index 순번으로 (index(순번) : 0~9)
s4[3:8:2]

    c    3
    k    5
    r    7
    dtype: int64

------------------------
# end index 생략. 3 ~ 마지막
s4[3:]
# end index 생략. 3 ~ 마지막. 세칸씩.
s4[3::3]

# step 생략. step : 1 
s4[3:8]

# 시작 index 생략 : 0
s4[:7]

 

ex) index 순번 _ 음수 인덱스

# step : 음수 => reverse 조회
s4[::-1]
 
    u    9
    j    8
    r    7
    x    6
    k    5
    f    4
    c    3
    a    2
    e    1
    d    0
    dtype: int64

----------------
# 음수인덱스: reverse 조회. 시작 : 뒤 인덱스, 끝 : 앞 인덱스, step : -1 씩 (인덱스 작아지면서)
s4[5:1:-1]
 
    k    5
    f    4
    c    3
    a    2
    dtype: int64
    
 -------------------
# (음수인덱스)뒤에서 2번째부터 ~ (양수인덱스)앞에서 4번까지(3번째 제외하고) 
s4[-2:3:-1]

    j    8
    r    7
    x    6
    k    5
    f    4
    dtype: int64

 

(2) index명 으로 Slicing 조회

 

-  index명으로 slicing할 때 end index도 포함해서 조회

# 인덱스명 조회
s4['e':'r']

    e    1
    a    2
    c    3
    f    4
    k    5
    x    6
    r    7
    dtype: int64

---------------
# 뒤에서 앞으로
s4['r':'e':-2] 

    r    7
    k    5
    c    3
    e    1
    dtype: int64

 

(3) Series/DataFrame - index 명은 중복될 수 있다.
  dict은 key 중복되지 않는데, 이들은 index명 중복 허용한다.

  중복된 값들 중 일부, 하나만 조회하고 싶다면 인덱스 순번으로 조회하면 되기에 index명은 중복을 허용하는 것이다.

 

ex) 인덱스명 중복으로 넣어주었다.

s5 = pd.Series(range(10), index=list('AAABBBCCCC'))
s5

    A    0
    A    1
    A    2
    B    3
    B    4
    B    5
    C    6
    C    7
    C    8
    C    9
    dtype: int64

 

ex) 인덱스명이 같기에 해당 인덱스명을 모두 조회한다.

s5['A']

A    0
A    1
A    2
dtype: int64

-  이때, 인덱스명과 값 둘다 출력

 

ex) index명 중복된 시리즈를 슬라이싱 조회하면 시작과 끝은 어디일까?

=> 첫번째 start index명 ~ 마지막 end index명 조회

 

# 첫번째 A부터 마지막 B까지 다 조회
s5['A':'B']

A    0
A    1
A    2
B    3
B    4
B    5
dtype: int64

 

5. Series안의 원소(element) 접근 _ 변경

5.1.1 Indexing 변경

(1) 특정 index 값을 변경

s1[0] = 1000

(2) pandas에서 결측치값으로 변경

결측치 : 수집이 안된값. 데이터가 없는 값. 모르는 값.

              => NA(Not Available), N/A, NaN(Not A Number) 이라고 표현

방법 

1. None

2. numpy의 nan변수를 이용

- 결측치를 가지면 type이 float이 된다.

s1[2] = None

import numpy as np
s1[5] = np.nan

 

(3) 여러 index에 값들을 한번에 변경 => fancy indexing

     같은 값으로 변경

s1[[0,3,6]] = 3200

 

(4) 여러 index에 값들을 한번에 변경 => fancy indexing
     각각 다른 값으로 변경  =>  튜플 대입(리스트 대입도 가능)

s1[[1,4,7,8]] = 1000, 4000, 7000, 8000

 

5.1.2 Slicing 변경

(1) 값은 값으로 변경

s1[:4] = 1234  # 0 ~ 3

0    1234.0
1    1234.0
2    1234.0
3    1234.0

s1[::3] = 98765

 

5.2 Series안의 원소(element) 접근 _ copy

 - deep copy(깊은 복사)
    - 원본의 카피본을 반환하여 값 변경시 원본이 변경되지 않는다.
    - 파이썬 리스트는 slicing시 deep copy
    - indexing은 deep copy
-  shallow copy(얕은 복사)
    - 원본을 반환하여 값 변경시 원본에 영향을 준다.
    - Series, DataFrame, 넘파이 배열(ndarray)은 slicing 조회시 shallow copy
 - copy() 메소드
    - Series, DataFrame, ndarray를 복사하여 반환한다.
    - deep copy => 복사본 객체를 만들어 준다.

 

5.2.1 shallow copy

slicing 한 결과의 원소를 변경하면 원본도 같이 바뀐다.

- 원본을 참조하고 있다. 같은 곳을 쳐다보고 있기 때문에(뷰)

- 새롭게 복사본을 만드는 게 아니다.

- 장점 : 메모리 공간을 절약할 수 있다.   단점 : 변경할 때 원본도 바뀌는 것 자체가.

- 어디서 주로 사용되는가?

   데이터프레임은 조회를 많이 하지, 변경을 잘 안 하기 때문에

   그리고 데이터프레임은 어마어마한 데이터가 있으니 메모리 공간을 절약할 필요가 있다.

 

# 슬라이싱 복사 후 값 변경 시 원본데이터까지 변경됨.

s2 = pd.Series(range(10))
s100 = s2[2:8]   # 슬라이싱 변경
s100[3] = 10000  # 값 바꾸면?
s2 # s2도 같이 바뀐다.

0        0
1        1
2        2
3    10000
4        4
5        5
6        6
7        7
8        8
9        9
dtype: int64

5.2.2 copy()

: series/dataframe 객체.copy()  => deep copy

s2 = pd.Series(range(10))
s200 = s2[2:8].copy()  
s200[3] = 300
s2
# 이렇게 copy()로 복사를 하면 원본 데이터 s2는 변경되지 않는다.

 

- 위 예제에서 인덱스 [3] 변경할 때, index 순번 3 값이 변경되는 것이 아니라,

  인덱스명으로 접근하게 된다. 3이라는 인덱스명을 가진 값이 변경

s200[3] = 300
s200

2      2
3    300
4      4
5      5
6      6
7      7

- 이때, 순번으로 접근하고 싶다면? iloc 을 사용하면 된다.

s200.iloc[3]

5

 

6. Series안의 원소(element) 접근 _ Boolean 인덱싱 (Masking)

Series 의 indexing 연산자에 boolean 리스트를 넣으면 True인 index의 값들만 조회한다. 
    - Boolean 연산자들을 이용해 원하는 조건의 값들을 조회할 수 있다

- 다중 조건인 경우 반드시 ( )로 조건을 묶어야 한다.

     - 파이썬과는 다르게 `and`, `or` 예약어는 사용할 수 없다.

s3 = pd.Series([70,20,100,200,50])
bool_index = [True, True, False, False, True]  # bool값을 원소로 가지며 s3와 크기가 같은 list
s3[bool_index]  # True인 index의 값들이 조회

0    70
1    20
4    50
dtype: int64

 

- 왜 쓰냐? 역할은 sql의 where 절 역할을 한다.

  시리즈 값 데이터 중 조건을 만족하는 애들을 가져오고 싶을 때

  아래와 같이 쓴다.

 

** element-wise 연산 (Vectorization -벡터화)
   Series 연산자 상수 => Series의 각각의 원소들과 상수를 연산한다는 것을 기억하자.

s3 >= 100  # 각 원소마다 비교한다. => F F T T F    BOOL 결과를 Series로 반환

0    False
1    False
2     True
3     True
4    False
dtype: bool
# s3에서 100 이상인 값들만 조회할 때

s3[s3 >= 100] # s3[[False, False, True, True, False]]

2    100
3    200
dtype: int64

 

- 다중 조건 : and 조건 : &

  and는 사용 못함. & 사용하고 피연산자를  ()  로 묶는다.

# s3에서 50 ~ 150 사이의 사이의 값들만 조회

s3[(s3>= 50) & (s3<=100)]

 

- 다중 조건 : or 조건  :  |

# s3 에서 50미만, 150 이상인 값들만 조회
s3[(s3<50) | (s3>=150)]

 

- 다중 조건 : not 조건 :  ~

# 100 이상이 아닌 값들을 조회
s3[~(s3>=100)]