본문 바로가기
AI SCHOOL/TIL

[DAY 11] pandas 기초 - DataFrame, Series, Indexing 등

2023. 1. 10.

오늘은 pandas 기초에 대해 공부했다.

키워드 : pandas, DataFrame, Series, rows & columns, Indexing, 요약통계, 파일 저장 & 로드

pandas

Python 라이브러리로, 데이터 조작 및 분석을 할 때 사용한다. 데이터 구조를 표현하는 객체인 DataFrame과 Series라는 클래스 객체를 이해해야 pandas를 다루는 데 문제 없을 것이다.

DataFrame과 Series의 이해

DataFrame은  2차원 리스트 구조이며 수학적으로는 행렬로 표현할 수 있다.
- 2차원 리스트 구조 예시 : [[1, 2, 3], [4, 5, 6]]
Series는 1차원 리스트 구조이며 수학적으로는 벡터로 표현할 수 있다.
- 1차원 리스트 구조 예시 : [1, 2, 3]

기본구조

Series는 row, column의 개념이 없고 DataFrame은 2차원으로 row, column이 존재한다.
그림의 DataFrame 예시는 5 rows 4 columns 구조이다.

이제 코드로 구현해보자.

import pandas as pd
import numpy as np

df = pd.DataFrame()

라이브러리 로드를 먼저 하고 빈 데이터프레임을 하나 생성했다.

df를 5행 4열 데이터프레임으로 구성해보자.

df['약품명'] = ['비타민', 'Omega3', '오메가3', 'Vitamin', 'vitamin']
df['종류'] = ['일반', '전문', '전문', '일반', '일반']
df['제조'] = '국내'
df['가격'] = 3500

dictionary에 데이터를 추가하는 것과 같이 추가한다.
'제조'와 '가격'과 같이 값을 하나만 쓰면 모든 행에 그 값이 들어간다.
이 결과 5행 4열의 아래와 같은 데이터 프레임이 만들어진다.

5행4열

하나의 컬럼 "종류"만 출력해보면

print(df['종류'])

# 실행 결과
0    일반
1    전문
2    전문
3    일반
4    일반
Name: 종류, dtype: object

1차원 벡터 형태인 시리즈가 출력됨을 확인할 수 있다.

데이터 타입 확인

# type 을 사용해서 데이터의 타입을 출력할 수 있다.
print(type(df['종류']))
print(type(df))

# 실행 결과
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.DataFrame'>

df['종류']와 df의 타입 출력 결과 Series와 DataFrame가 출력된다.

컬럼값 변경하기

df['가격'] = [3500, 3200, 4000, np.nan, 2000]
print(df['가격'])

# 실행 결과
0    3500.0
1    3200.0
2    4000.0
3       NaN
4    2000.0
Name: 가격, dtype: float64

'가격' 컬럼의 데이터가 변경되었다.
nan은 not a number의 약자로 결측치(missing value)를 의미한다.
nan의 데이터 타입은 float이다.

데이터 타입 : object > float > int

print(pd.Series([1, 2, 3]))  # int

# 실행 결과
0    1
1    2
2    3
dtype: int64

 

print(pd.Series([1, 2, np.nan, 4]))   # float

# 실행 결과
0    1.0
1    2.0
2    NaN
3    4.0
dtype: float64

결측치의 존재로 1, 2, 4 또한 float로 저장

print(pd.Series([1, 2, np.nan, 4, '문자']))   # object

# 실행 결과
0      1
1      2
2    NaN
3      4
4     문자
dtype: object

 '문자'의 존재로 1, 2, nan, 4 또한 object로 저장

컬럼 삭제

# 방법 1 : df.drop(column = '종류')
# 방법 2 : df.drop('종류', axis=1)
df = df.drop('종류', axis=1)

'종류' 컬럼을 삭제했다. drop 메소드 사용 후 df에 다시 할당해 주는 것을 잊지 말자.
여기까지 했다면 현재 DataFrame의 구성은 아래와 같다.

삭제된컬럼
df 구성 -> 가격 변경 -> 종류 삭제

 

데이터 요약하기

# DataFrame의 정보 확인 : info() 함수 사용
df.info()

# 실행 결과
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   약품명     5 non-null      object 
 1   제조      5 non-null      object 
 2   가격      4 non-null      float64
dtypes: float64(1), object(2)
memory usage: 248.0+ bytes

데이터프레임의 전체 정보를 출력하고 있다. 전체 entries, 컬럼 개수, 컬럼별 data type, non-null 데이터 개수 등을 확인할 수 있다.

# 데이터 프레임의 크기를 출력합니다.
# (행, 열)
print(df.shape)

# 실행 결과
(5, 3)

df는 5행 3열임을 shape을 통해 확인

# 데이터의 타입만 봅니다.
print(df.dtypes)

# 실행 결과
약품명     object
제조      object
가격     float64
dtype: object

데이터타입만 확인. 이 정보는 info()를 통해서도 확인이 가능하다.

info()는 괄호를 사용하고, shape와 dtypes는 괄호 없이 동작하는데 차이가 무엇일까?
=> info()는 데이터프레임의 method이며 shape과 dtypes는 property이기 때문이다.

수치형 데이터의 기술통계

print(df.describe())

# 실행 결과
	가격
count     4.0
mean   3175.0
std     850.0
min    2000.0
25%    2900.0
50%    3350.0
75%    3625.0
max    4000.0

별도의 파라미터를 설정하지 않았음에도 수치형 데이터인 '가격' 컬럼에 대한 통계만 출력된다.
count : 결측치를 제외한 데이터 개수
mean : 평균
std : 표준편차
min, max : 최솟값, 최댓값
25%, 50%, 75% : 최솟값이 0%, 최댓값이 100%일 때 25%, 50%, 75% 위치 값
- 1사분위수, 2사분위수, 3사분위수

범주형 데이터의 기술통계

print(df.describe(include='object'))

# 실행 결과
        약품명  제조
count     5   5
unique    5   1
top     비타민  국내
freq      1   5

describe 메소드의 파라미터로 include='object'를 사용하여 범주형 데이터의 기술통계를 확인한다.
include='O' 과 exclude='number' 또한 같은 결과를 얻는다.
count : 결측치를 제외한 데이터 개수
unique : 유일값 개수
top : 최빈값(가장 개수가 많은 값)
freq : 최빈값의 빈도수

'약품명'은 5개의 모두 다른 데이터를 가지고, '제조'는 5개 데이터 모두 국내라는 점을 생각하며 결과를 이해해보자.

2개 이상의 컬럼 가져오기

파이썬에서 2개 이상의 데이터를 다룰 때는 보통 리스트[]를 사용한다.

print(df[['약품명', '가격']])

# 실행 결과
       약품명      가격
0      비타민  3500.0
1   Omega3  3200.0
2     오메가3  4000.0
3  Vitamin     NaN
4  vitamin  2000.0


하나의 컬럼을 리스트형으로 사용해서 데이터프레임 형태로 가져오기

print(df[['약품명']])

# 실행 결과
       약품명
0      비타민
1   Omega3
2     오메가3
3  Vitamin
4  vitamin

'약품명' 컬럼을 Series가 아닌 DataFrame 형태로 출력하였다.

행을 기준으로 데이터 가져오기

# 인덱스 번호로 첫번째 데이터 가져오기
print(df.loc[0])

# 실행 결과
약품명       비타민
제조         국내
가격     3500.0
Name: 0, dtype: object

 

# 위에서 3개의 행 데이터 가져오기
print(df.loc[[0, 1, 2]])

# 실행 결과
      약품명  제조      가격
0     비타민  국내  3500.0
1  Omega3  국내  3200.0
2    오메가3  국내  4000.0

 

행과 열을 함께 가져오기
- loc과 iloc을 비교하며 사용

# loc[행, 열]
print(df.loc[0:3, :'제조'])   # 0부터 3까지 포함

# 실행 결과
       약품명  제조
0      비타민  국내
1   Omega3  국내
2     오메가3  국내
3  Vitamin  국내

 

# iloc[행index, 열index]
print(df.iloc[0:4, :2])  # 0부터 4-1까지

# 실행 결과
       약품명  제조
0      비타민  국내
1   Omega3  국내
2     오메가3  국내
3  Vitamin  국내

 

# loc[행, 열]
print(df.loc[[0, 1, 2], ['약품명', '가격']])

# 실행 결과
      약품명      가격
0     비타민  3500.0
1  Omega3  3200.0
2    오메가3  4000.0

 

# iloc[행index, 열index]
print(df.iloc[0:3, 0:2])

# 실행 결과
      약품명  제조
0     비타민  국내
1  Omega3  국내
2    오메가3  국내

 

특정 약품명만 가져오기 - indexing 사용

# 파이썬의 정규표현식에서는 |는 or를 &는 and를 의미합니다.
# 여러 검색어로 검색을 한다 가정하고 | 로 검색어를 넣어준다고 생각하면 됩니다.
# str.contains 를 사용해서 약품명을 가져올 수 있습니다.

print(df['약품명'].str.contains('비타|vita'))

# 실행 결과
0     True
1    False
2    False
3    False
4     True
Name: 약품명, dtype: bool

'약품명' 컬럼 데이터 5개 각각에 비타 혹은 vita가 포함되는지 여부에 따라 bool 값이 Series로 출력

이를 활용하여 비타 혹은 vita가 포함되는 약품명을 가진 데이터만 출력

print(df[df['약품명'].str.contains('비타|vita')])
# 이렇게 써도 같은 결과 얻음 print(df[[True, False, False, False, True]])

# 실행 결과
       약품명  제조      가격
0      비타민  국내  3500.0
4  vitamin  국내  2000.0


하지만 약품명 'Vitamin'은 대소문자 차이로 False가 되었다.
약품명을 모두 소문자로 만든 컬럼을 추가해보자.

파생변수 만들기

# 약품명을 모두 소문자로 만든 컬럼을 추가
df['약품명2'] = df['약품명'].str.lower()


새로 추가한 '약품명2' 컬럼을 사용해보자.

print(df[df['약품명2'].str.contains('비타|vita')])    # 3행이 나온다

# 실행 결과
       약품명  제조      가격     약품명2
0      비타민  국내  3500.0      비타민
3  Vitamin  국내     NaN  vitamin
4  vitamin  국내  2000.0  vitamin


이를 그림으로 표현하면 아래와 같다

파생변수

 

가격이 특정 조건에 만족하는 데이터 찾기

3500원 이상인 의약품 데이터만 추출해보자.

print(df[df['가격'] >= 3500])

# 실행 결과
    약품명  제조      가격  약품명2
0   비타민  국내  3500.0   비타민
2  오메가3  국내  4000.0  오메가3

비교 연산자와 Indexing을 사용하여 원하는 데이터를 출력했다.

정렬하기 - sort_values 메소드 사용

print(df.sort_values(['약품명2','가격'], ascending=[False, True]))

# 실행 결과
       약품명  제조      가격     약품명2
2     오메가3  국내  4000.0     오메가3
0      비타민  국내  3500.0      비타민
4  vitamin  국내  2000.0  vitamin
3  Vitamin  국내     NaN  vitamin
1   Omega3  국내  3200.0   omega3

약품명2를 기준으로 내림차순 정렬한 상태에서 가격을 기준으로 오름차순 정렬한 결과이다.
약품명2가 서로 같은 데이터 2개의 가격은 2000.0과 NaN인데, 결측치가 숫자보다 더 크다는 규칙이 있기 때문에 오름차순 정렬할 경우 2000.0의 순번이 먼저다.

파일로 저장하고 로드하기
- DataFrame의 to_excel 또는 to_csv 메소드를 통해 xlsx 파일 또는 csv 파일로 저장
- pandas의 read_excel 또는 read_csv 메소드를 통해 xlsx 파일 또는 csv 파일 로드
- 예시로 xlsx 파일로 지금까지 다룬 데이터프레임을 저장하고 로드해본다

# to_excel 를 통해 xlsx 파일로 저장
df.to_excel('pandas_test.xlsx', encoding='cp949', index=False)

df에 한글이 포함되어 있기 때문에 encoding 방식을 cp949로 설정하고
기본 index까지 포함하여 저장하는 것을 방지하기 위해 index=False로 설정한다.

# 저장된 xlsx 파일을 로드하고 출력
df_test = pd.read_excel('pandas_test.xlsx')
print(df_test)

# 실행 결과
       약품명  제조      가격     약품명2
0      비타민  국내  3500.0      비타민
1   Omega3  국내  3200.0   omega3
2     오메가3  국내  4000.0     오메가3
3  Vitamin  국내     NaN  vitamin
4  vitamin  국내  2000.0  vitamin​

df를 저장한 pandas_test를 로드하여 출력해본 결과 잘 출력된 것을 확인할 수 있다.

반응형

댓글