| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- Transformer
- dementional reduction
- 정보처리기사
- 소프트웨어 개발
- 트랜스포머
- CLIP
- Python
- ASR
- TTS
- RNN
- 랭그래프
- python 기초
- 객체지향
- 기초
- 딥러닝
- python기초
- 머신러닝
- 자연어처리
- 힙정렬
- RDBMS
- 캐글
- 데이터 시각화
- 데이터엔지니어
- CNN
- 에이전트
- 알고리즘
- UMAP
- SQL
- LangGraph
- 생성형 인공지능
- Today
- Total
수달이네 기술 블로그
2. Pandas 본문
판다스(Pandas)
데이터 분석을 위한 파이썬 라이브러리, 표, 데이터등 다양한 형태의 데이터를 처리하고 분석하는 도구
pip install pandas
위 코드를 이용하여 설치 가능하다.
import pandas as pd
판다스를 import후 pd라는 별명으로 사용할 것이다.
Series 와 DataFrame
1. Series
1차원 배열과 같은 자료구조로 하나의 열을 나타냄.
- 인덱스, 값으로 구성되어있음.
import pandas as pd
idx = ['김사과', '반하나', '오렌지', '이메론', '배애리']
data = [67, 75, 90, 62, 98]
# pd.Series(데이터, 인덱스, ...)
pd.Series(data)
# 0 67
# 1 75
# 2 90
# 3 62
# 4 98
# dtype: int64
- 값은 ndarray기반으로 저장된다.
se1 = pd.Series(data, idx)
se1
# 김사과 67
# 반하나 75
# 오렌지 90
# 이메론 62
# 배애리 98
# dtype: int64
- pd.Series(인덱스, 데이터)로 저장된다.
- 정수, 실수, 문자열등 다양한 형태의 데이터를 담을 수 있다.
2. DataFrame
2차원 테이블 형태의 데이터를 다루는데 사용되는 자료구조
data = [[67, 93, 91],
[75, 68, 96],
[87, 81, 82],
[62, 70, 75],
[98, 56, 87]]
idx = ['김사과', '반하나', '오렌지', '이메론', '배애리']
col = ['국어', '영어', '수학']
# pd.DataFrame(데이터, 인덱스, 컬럼, ...)
pd.DataFrame(data)
| 0 | 1 | 2 | |
| 0 | 67 | 93 | 91 |
| 1 | 75 | 68 | 96 |
| 2 | 87 | 81 | 82 |
| 3 | 62 | 70 | 75 |
| 4 | 98 | 56 | 87 |
- 위와 같은 결과로 출력된다.
- 인덱스가 지정되지 않았을 경우 0~n까지 자동으로 입력된다.
pd.DataFrame(data, idx)
| 0 | 1 | 2 | |
| 김사과 | 67 | 93 | 91 |
| 반하나 | 75 | 68 | 96 |
| 오렌지 | 87 | 81 | 82 |
| 이메론 | 62 | 70 | 75 |
| 배애리 | 98 | 56 | 87 |
- 인덱스를 지정해주면 정해진 인덱스로 인덱스가 출력된다.
pd.DataFrame(data, idx, col)
| 국어 | 영어 | 수학 | |
| 김사과 | 67 | 93 | 91 |
| 반하나 | 75 | 68 | 96 |
| 오렌지 | 87 | 81 | 82 |
| 이메론 | 62 | 70 | 75 |
| 배애리 | 98 | 56 | 87 |
- 컬럼을 지정해주면 컬럼도 지정 가능하다.
df = pd.DataFrame(index=idx, columns=col, data=data)
df
- 명확하게 해줄 수도 있다.
print(df.index)
print(df.columns)
print(df.values)
# Index(['김사과', '반하나', '오렌지', '이메론', '배애리'], dtype='object')
# Index(['국어', '영어', '수학'], dtype='object')
# [[67 93 91]
# [75 68 96]
# [87 81 82]
# [62 70 75]
# [98 56 87]]
- 위처럼 인덱스 컬럼, 값을 따로 출력 가능하다.
CSV파일 읽기
df = pd.read_csv("파일위치")
df
위와 같이 읽어줄 수 있다.
| 이름 | 그룹 | 소속사 | 성별 | 생년월일 | 키 | 혈액형 | |
| 0 | 지민 | 방탄소년단 | 빅히트 | 남자 | 1995-10-13 | 174.0 | A |
| 1 | 정국 | 방탄소년단 | 빅히트 | 남자 | 1997-09-01 | 179.0 | A |
| 2 | 민지 | 뉴진스 | 어도어 | 여자 | 2004-05-07 | 169.0 | A |
- csv파일은 dataframe타입이다.
1. 데이터 프레임 기본 정보 알아보기
df.info()
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 20 entries, 0 to 19
# Data columns (total 8 columns):
# # Column Non-Null Count Dtype
# --- ------ -------------- -----
# 0 이름 20 non-null object
# 1 그룹 20 non-null object
# 2 소속사 19 non-null object
# 3 성별 20 non-null object
# 4 생년월일 20 non-null object
# 5 키 19 non-null float64
# 6 혈액형 19 non-null object
# 7 브랜드평판지수 20 non-null int64
# dtypes: float64(1), int64(1), object(6)
# memory usage: 1.4+ KB
위와 같이 info함수를 사용하면 컬럼, 데이터 형태, 결측값 등을 확인할 수 있다.
df.columns
# Index(['이름', '그룹', '소속사', '성별', '생년월일', '키', '혈액형'], dtype='object')
- 데이터 프레임이므로 컬럼을 확인할 수도 있다.
new_columns = ['name', 'group', 'company', 'gender', 'birthday', 'height', 'blood', 'brand']
df.columns = new_columns
df
| name | group | company | gender | birthday | height | blood | |
| 0 | 지민 | 방탄소년단 | 빅히트 | 남자 | 1995-10-13 | 174.0 | A |
| 1 | 정국 | 방탄소년단 | 빅히트 | 남자 | 1997-09-01 | 179.0 | A |
| 2 | 민지 | 뉴진스 | 어도어 | 여자 | 2004-05-07 | 169.0 | A |
- 위처럼 컬럼명을 수정해줄 수 있다.
# describe(): 통계 정보를 반환
df.describe()
| height | brand | |
| count | 19.000000 | 2.000000e+01 |
| mean | 170.536842 | 2.700190e+06 |
| std | 7.225204 | 1.381919e+06 |
| min | 161.000000 | 1.680587e+06 |
| 25% | 164.750000 | 1.887423e+06 |
| 50% | 168.000000 | 2.074682e+06 |
| 75% | 179.000000 | 2.623465e+06 |
| max | 182.000000 | 6.267302e+06 |
위와 같이 통계값(개수, 평균, 정규값, 최소값 등등)을 확인할 수도 있다.
- 위의 값을 보면 계산 가능한 int값만 적용되었는데,
df.describe(include=object) # Top: 최빈값, freq: 최빈값의 빈도
위처럼 object를 포함하는 것으로 해주면
| name | group | company | gender | birthday | blood | |
| count | 20 | 20 | 19 | 20 | 20 | 19 |
| unique | 20 | 6 | 5 | 2 | 20 | 4 |
| top | 지민 | 방탄소년단 | 빅히트 | 여자 | 1995-10-13 | A |
| freq | 1 | 5 | 7 | 13 | 1 | 11 |
- object값만 포함하여 object로 계산가능한 통계값을 출력해준다
- 개수, 종류, 최빈값, 최빈값의 빈도 순이다.
# 원하는 개수의 데이터 보기
df.head(원하는 개수) # 상위 5개의 row를 출력
| name | group | company | gender | birthday | height | blood | |
| 0 | 지민 | 방탄소년단 | 빅히트 | 남자 | 1995-10-13 | 174.0 | A |
| 1 | 정국 | 방탄소년단 | 빅히트 | 남자 | 1997-09-01 | 179.0 | A |
| 2 | 민지 | 뉴진스 | 어도어 | 여자 | 2004-05-07 | 169.0 | A |
| 3 | 하니 | 뉴진스 | 어도어 | 여자 | 2004-10-06 | 161.7 | O |
| 4 | 뷔 | 방탄소년단 | 빅히트 | 남자 | 1995-12-30 | 179.0 | AB |
- 기본 상위 5개의 데이터를 보여주며, 원하는 개수에 정수값을 입력하면 그개수만큼의 값을 보여준다.
df.tail(원하는 개수) # 하위 5개의 row를 출력
| name | group | company | gender | birthday | height | blood | |
| 15 | 윤아 | 소녀시대 | 에스엠 | 여자 | 1990-05-30 | 168.0 | B |
| 16 | 조이 | 레드벨벳 | 빅히트 | 여자 | 1996-09-03 | 168.0 | A |
| 17 | 슬기 | 레드벨벳 | 빅히트 | 여자 | 1994-02-10 | 161.0 | A |
| 18 | 강다니엘 | 워너원 | NaN | 남자 | 1996-12-10 | 182.0 | A |
| 19 | 진 | 방탄소년단 | 빅히트 | 남자 | 1992-12-04 | 179.0 | O |
- 기본 하위 5개의 데이터를 보여주며 원하는 개수에 정수값을 입력하면 그 개수만큼의 값을 렬
2. 정렬
# 정렬하기
df.sort_index([ascending=False]) # index로 오름차순 정렬: 기본값
| name | group | company | gender | birthday | height | blood | |
| 0 | 지민 | 방탄소년단 | 빅히트 | 남자 | 1995-10-13 | 174.0 | A |
| 1 | 정국 | 방탄소년단 | 빅히트 | 남자 | 1997-09-01 | 179.0 | A |
| 2 | 민지 | 뉴진스 | 어도어 | 여자 | 2004-05-07 | 169.0 | A |
| 3 | 하니 | 뉴진스 | 어도어 | 여자 | 2004-10-06 | 161.7 | O |
| 4 | 뷔 | 방탄소년단 | 빅히트 | 남자 | 1995-12-30 | 179.0 | AB |
| 5 | 다니엘 | 뉴진스 | 어도어 | 여자 | 2005-04-11 | 165.0 | NaN |
- 위 함수로 인덱스 값으로 정렬해준다.
- 기본 오름차순이며, ascending = False를 할 경우 내림차순으로 정렬해준다.
df.sort_values(by='컬럼', [ascending=False], [na_position='first'])# 키로 오름차순 정렬
- 위 함수로 원하는 컬럼을 기준으로 정렬해준다. 마찬가지로 ascending을 통해 내림차순으로 변경할 수 있다.
- na_position을 통해 nan값을 맨 앞으로 끌어올려줄 수도 있다.
# 1차 정렬: 키(내림차순), 2차 정렬: 브랜드(내림차순)
df.sort_values(by=['height', 'birthday'], ascending=[False, False], na_position='first')
- 만약 위처럼 배열 값을 컬럼으로 넣어부면 1차 정렬 후 같은 값을 2차 정렬 시켜준다.
데이터 다루기
df['blood']
# 0 A
# 1 A
# 2 A
# 3 O
# 4 AB
# 5 NaN
# 6 O
# 7 A
# 8 B
# 9 A
# 10 A
# 11 B
# 12 A
# 13 A
# 14 B
# 15 B
# 16 A
# 17 A
# 18 A
# 19 O
# Name: blood, dtype: object
- 위처럼 컬럼 값을 지정해주면, 인덱스와 해당하는 컬럼값만 추출 가능하다.
df[:3]
| name | group | company | gender | birthday | height | blood | |
| 0 | 지민 | 방탄소년단 | 빅히트 | 남자 | 1995-10-13 | 174.0 | A |
| 1 | 정국 | 방탄소년단 | 빅히트 | 남자 | 1997-09-01 | 179.0 | A |
| 2 | 민지 | 뉴진스 | 어도어 | 여자 | 2004-05-07 | 169.0 | A |
위처럼 인덱스 값을 이용하여 간단하게 원하는 값만 출력해줄 수도 있다.
loc인덱싱
# loc 인덱싱: 컬럼 인덱싱
df.loc[3:5, 'name'] # df['name']
# 3 하니
# 4 뷔
# 5 다니엘
# Name: name, dtype: object
- 인덱싱도 쉽게 가능하다.
- 컬럼값에 여러개를 넣으면 dataframe(표)의 형태로 보여준다.
df.loc[2:5, 'name':'gender']
| name | group | company | gender | |
| 2 | 민지 | 뉴진스 | 어도어 | 여자 |
| 3 | 하니 | 뉴진스 | 어도어 | 여자 |
| 4 | 뷔 | 방탄소년단 | 빅히트 | 남자 |
| 5 | 다니엘 | 뉴진스 | 어도어 | 여자 |
iloc인덱싱
df.iloc[:, 0:3] # 3을 포함하지 않음
| name | group | company | |
| 0 | 지민 | 방탄소년단 | 빅히트 |
| 1 | 정국 | 방탄소년단 | 빅히트 |
| 2 | 민지 | 뉴진스 | 어도어 |
| 3 | 하니 | 뉴진스 | 어도어 |
| 4 | 뷔 | 방탄소년단 | 빅히트 |
- 위처럼 iloc를 사용하면 데이터 이름이 아닌 숫자를 통해 컬럼 인덱싱 가능하다.
데이터 값으로 인덱싱
df['height'] >= 180
# 0 False
# 1 False
# 2 False
# 3 False
# 4 False
# 5 False
# 6 False
# 7 False
# 8 False
# 9 False
# 10 True
# 11 False
# 12 False
# 13 False
# 14 False
# 15 False
# 16 False
# 17 False
# 18 True
# 19 False
# Name: height, dtype: bool
위처럼 데이터 값을 통해서 결과값을 출력하면 결과에 해당하는 값만 True로 반환된다.
df[df['height'] >= 180]
해당 값을 df내에 넣을 경우’
| name | group | company | gender | birthday | height | blood | |
| 10 | RM | 방탄소년단 | 빅히트 | 남자 | 1994-09-12 | 181.0 | A |
| 18 | 강다니엘 | 워너원 | NaN | 남자 | 1996-12-10 | 182.0 | A |
위처럼 해당하는 값만 인덱싱 되어 출력된다.
company = [ '어도어']
df['company'].isin(company)
# 0 False
# 1 False
# 2 True
# 3 True
# 4 False
# 5 True
# 6 True
# 7 False
# 8 True
# 9 False
# 10 False
# 11 False
# 12 False
# 13 False
# 14 False
# 15 False
# 16 False
# 17 False
# 18 False
# 19 False
# Name: company, dtype: bool
원하는 값을 포함하는 값을 출력시키려면 위처럼 배열로 object를 만들어주고
마찬가지로 값을 넣어주면 된다.
df[df['company'].isin(company)]
| name | group | company | gender | birthday | height | blood | |
| 2 | 민지 | 뉴진스 | 어도어 | 여자 | 2004-05-07 | 169.0 | A |
| 3 | 하니 | 뉴진스 | 어도어 | 여자 | 2004-10-06 | 161.7 | O |
| 5 | 다니엘 | 뉴진스 | 어도어 | 여자 | 2005-04-11 | 165.0 | NaN |
| 6 | 혜인 | 뉴진스 | 어도어 | 여자 | 2008-04-21 | 170.0 | O |
| 8 | 해린 | 뉴진스 | 어도어 | 여자 | 2006-05-15 | 164.5 | B |
- 위처럼 ‘어도어’인 컴퍼니만 만들어진다.
결측값
df.info()
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 20 entries, 0 to 19
# Data columns (total 8 columns):
# # Column Non-Null Count Dtype
# --- ------ -------------- -----
# 0 name 20 non-null object
# 1 group 20 non-null object
# 2 company 19 non-null object
# 3 gender 20 non-null object
# 4 birthday 20 non-null object
# 5 height 19 non-null float64
# 6 blood 19 non-null object
# 7 brand 20 non-null int64
# dtypes: float64(1), int64(1), object(6)
# memory usage: 1.4+ KB
위에서 Non-Null Count에서 나오는 20 non-null은 null값이 아닌 데이터의 수이다. 즉, 20개의 데이터가 있는 현제 데이터에서 19 non-null이라고 나오는 값은 1개의 결측값이 존재한다는 의미이다.
혹은, 위에서 NaN이라고 출력되던 값이 결측값들이다.
df.isna()
df.isnull()
해당 함수를 통해서 결측값인 경우 True로 출력된다.
| name | group | company | gender | birthday | height | blood | |
| 0 | False | False | False | False | False | False | False |
| 1 | False | False | False | False | False | False | False |
| 2 | False | False | False | False | False | False | False |
| 3 | False | False | False | False | False | False | False |
| 4 | False | False | False | False | False | False | False |
| 5 | False | False | False | False | False | False | True |
| 6 | False | False | False | False | False | False | False |
| 7 | False | False | False | False | False | False | False |
| 8 | False | False | False | False | False | False | False |
| 9 | False | False | False | False | False | True | False |
| 10 | False | False | False | False | False | False | False |
| 11 | False | False | False | False | False | False | False |
| 12 | False | False | False | False | False | False | False |
| 13 | False | False | False | False | False | False | False |
| 14 | False | False | False | False | False | False | False |
| 15 | False | False | False | False | False | False | False |
| 16 | False | False | False | False | False | False | False |
| 17 | False | False | False | False | False | False | False |
| 18 | False | False | True | False | False | False | False |
| 19 | False | False | False | False | False | False | False |
반대로는
df.notnull()
이 존재한다.
df['height'].isna()
# 0 False
# 1 False
# 2 False
# 3 False
# 4 False
# 5 False
# 6 False
# 7 False
# 8 False
# 9 True
# 10 False
# 11 False
# 12 False
# 13 False
# 14 False
# 15 False
# 16 False
# 17 False
# 18 False
# 19 False
# Name: height, dtype: bool
위처럼 컬럼에서 결측값을 확인할 수 있으며 마찬가지로 df[]에 넣어주면 해당하는 데이터프레임만 확인 가능하다.
# fillna(): 결측값을 채워주는 함수
df['height'].fillna(0) # df['height].fillna(0, inplace=True) 적용
# 0 174.0
# 1 179.0
# 2 169.0
# 3 161.7
# 4 179.0
# 5 165.0
# 6 170.0
# 7 162.0
# 8 164.5
# 9 0.0
# 10 181.0
# 11 163.0
# 12 179.0
# 13 167.0
# 14 168.0
# 15 168.0
# 16 168.0
# 17 161.0
# 18 182.0
# 19 179.0
# Name: height, dtype: float64
fillna()함수로 결측값을 채워줄 수 있으며, 위에선 0으로 채워넣었다.
이때 df.copy()함수를 통해 데이터프레임을 복사해줄 수 있는데, 이걸 이용하면
- 위에서 copy를 사용하는 이유는 현재 실행중인 프로그램의 원본 데이터 값을 건드리지 않기 위해
height = df_copy['height'].mean()
df_copy['height'] = df_copy['height'].fillna(height)
df_copy['height']
# 0 174.000000
# 1 179.000000
# 2 169.000000
# 3 161.700000
# 4 179.000000
# 5 165.000000
# 6 170.000000
# 7 162.000000
# 8 164.500000
# 9 170.536842
# 10 181.000000
# 11 163.000000
# 12 179.000000
# 13 167.000000
# 14 168.000000
# 15 168.000000
# 16 168.000000
# 17 161.000000
# 18 182.000000
# 19 179.000000
# Name: height, dtype: float64
- copy로 height의 평균을 계산하고, 해당 값을 fillna로 넣어주는 방식을 사용할 수 있따.
height = df_copy['height'].median() # 50%값, 중위
height
- 중앙값을 넣어줄 수도 있다.
# dropna(): 결측값이 있는 행 또는 열을 제거. 결측값이 한개라도 있는 경우 삭제
# axis=0 (행 삭제)
# axis=1 (열 삭제)
df_copy.dropna([axis=0])
- 혹은 위와 같이 행 자체를 삭제해 줄 수도 있다.
- 기본 axis = 0이며 1로 설정해주면 결측값 열을 삭제해 줄수도 있다.
데이터 추가(행, 열)
dic = {
'name': '김사과',
'group': '과수원',
'company': '애플',
'gender': '여자',
'birthday': '2000-01-01',
'height': 160.0,
'blood': 'A',
'brand': 1234567
}
# concat(): 데이터를 합침. axis=0 (기본값)
df_copy = pd.concat([df_copy, pd.DataFrame(dic, index=[0])], ignore_index=True)
df_copy.iloc[-1]
# name 김사과
# group 과수원
# company 애플
# gender 여자
# birthday 2000-01-01
# height 160.0
# blood A
# brand 1234567
# Name: 25, dtype: object
위와 같이 데이터 행을 추가 가능하다.
df_copy['nation'] = '대한민국'
df_copy.head()
# name group company gender birthday height blood brand nation
# 0 지민 방탄소년단 빅히트 남자 1995-10-13 174.0 A 6267302 대한민국
# 1 정국 방탄소년단 빅히트 남자 1997-09-01 179.0 A 5805844 대한민국
새로운 행을 추가해주려면 위와 같이 사용해 줄 수 있따.
df_copy.loc[df_copy['name'] == '김사과', 'nation'] = '미국'
df_copy.tail()
위와 같은 식으로 원하는 행의 내용을 수정해줄 수 있다.
# 행 제거하기
df_copy.drop(20, axis=0) # 0: 행, 1: 열
df_copy.drop([1, 3, 5, 7, 20], axis=0)
행은 drop으로 제거 가능하고
(위처럼 여러 행을 한번에 제거도 가능하다)
# 열 제거하기
df_copy.drop('nation', axis=1)
열또한 drop으로 제거 가능한데 axis = 1로 하면 제거 가능하다.
df_copy.drop(['nation', 'group'], axis=1)
위처럼 여러행 제거도 가능
통계함수
아까 사용했던 describe함수를 이용할 때 사용했던 여러 통계값을 직접 찾아볼 수도 있다.
df_copy['height'].sum() # 합계
df_copy['height'].count() # 개수, NaN은 포함하지 않음
df_copy['height'].mean() # 평균
df_copy['height'].median() # 중앙값
df_copy['height'].max() # 최대값
df_copy['height'].min() # 최소값
df_copy['height'].var() # 분산
df_copy['height'].std() # 표준편차
- 평균: 모든 데이터의 합 / 데이터 개수
- 중앙값: 데이터를 크기순으로 정렬했을때 가운데값
- 분산: 얼마나 데이터가 평균에서 퍼쳐있는지
- 표준편차: 분산의 제곱근(이것또한 분포정도를 측정)

그룹
그룹을 통해 데이터를 그룹으로 묶어서 분석하는데에 사용한다.
# 그룹을 맺으면 통계함수를 사용할 수 있음
df_copy.groupby('group').count()
| group | name | company | gender | birthday | height | blood | brand |
| 뉴진스 | 5 | 5 | 5 | 5 | 5 | 4 | 5 |
| 레드벨벳 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
| 방탄소년단 | 5 | 5 | 5 | 5 | 5 | 5 | 5 |
| 블랙핑크 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
| 소녀시대 | 2 | 2 | 2 | 2 | 1 | 2 | 2 |
| 워너원 | 2 | 1 | 2 | 2 | 2 | 2 | 2 |
- 위 코드는 그룹으로 데이터를 묶어준 이후 해당 컬럼에 해당하는 값을 보여준다.
- NaN은 제외하고 계산된다.
df_copy.groupby('group').mean(numeric_only=True)
| group | height | brand |
| 뉴진스 | 166.04 | 3082933.2 |
| 레드벨벳 | 164.50 | 1786140.5 |
| 방탄소년단 | 178.40 | 3858656.0 |
| 블랙핑크 | 165.00 | 2024410.5 |
| 소녀시대 | 168.00 | 1982581.5 |
| 워너원 | 180.50 | 1830385.5 |
| blood | gender | height | brand |
| A | 남자 | 179.000 | 3.560683e+06 |
| 여자 | 165.400 | 2.371581e+06 | |
| AB | 남자 | 179.000 | 3.470048e+06 |
| B | 여자 | 165.875 | 2.004014e+06 |
| O | 남자 | 179.000 | 1.680587e+06 |
| 여자 | 165.850 | 3.231469e+06 |
- 위처럼 group을 통해 여러 값을 한번에 분석할 수도 있다.
중복값 제거
# drop_duplicates(): 중복된 데이터를 제거
df_copy['blood'].drop_duplicates()
- 중복된 데이터를 제거해준다.
df_copy['blood'].drop_duplicates(keep='last')
# 4 AB
# 5 NaN
# 15 B
# 18 A
# 19 O
# Name: blood, dtype: object
- 어떤 인덱스가 남았는지 표시해준다.
df_copy['company'].value_counts()
# company
# 빅히트 7
# 어도어 5
# 와이지 4
# 에스엠 2
# 판타지오 1
# Name: count, dtype: int64
df_copy['company'].value_counts(dropna=False) # NaN를 포함
- 이건 데이터 value값의 개수를 읽어오는 일을 한다.
데이터 프레임 합치기
df1 = pd.read_csv('idol.csv')
df2 = pd.read_csv('idol2.csv')
df_copy = df1.copy()
pd.concat([df1, df_copy])# axis=0 (기본값)
- 기본값이 0이기 때문에 행으로 추가된다.
이름 그룹 소속사 성별 생년월일 키 혈액형 0 지민 방탄소년단 빅히트 남자 1995-10-13 174.0 A 1 정국 방탄소년단 빅히트 남자 1997-09-01 179.0 A 2 민지 뉴진스 어도어 여자 2004-05-07 169.0 A 3 하니 뉴진스 어도어 여자 2004-10-06 161.7 O 생략 0 지민 방탄소년단 빅히트 남자 1995-10-13 174.0 A 1 정국 방탄소년단 빅히트 남자 1997-09-01 179.0 A 2 민지 뉴진스 어도어 여자 2004-05-07 169.0 A 3 하니 뉴진스 어도어 여자 2004-10-06 161.7 O 4 뷔 방탄소년단 빅히트 남자 1995-12-30 179.0 AB 5 다니엘 뉴진스 어도어 여자 2005-04-11 165.0 NaN 6 혜인 뉴진스 어도어 여자 2008-04-21 170.0 O
- 위처럼 두개의 csv파일이 합쳐지는데 index가 연속적으로 붙어나오는 것을 알 수 있다. 이걸 해결하렴ㄴ
df_concat = pd.concat([df1, df_copy])
# reset_index(): index를 새롭게 적용
# drop=True 옵션을 사용하여 기존 index가 컬럼으로 만들어지는 것을 방지
df_concat.reset_index(drop=True)
- 위처럼 reset_index를 통해 index를 새로 만들어줄 수 있다
- drop=true가 없으면 원래 인덱스가 새로운 컬럼으로 추가되는데, 이걸 넣어 원래 인덱스를 없애준다.
pd.concat([df1, df2], axis=1) # 같은 index와 결합
- 열을 통해 결합시켜준다.
merge 메서드
df_right = df2.drop([1, 3, 5, 7, 9], axis=0)
df_right = df_right.reset_index(drop=True)
df_right
- 만약 일부 컬럼을 제거하고, index를 리셋해줄 경우에
- 이름이 같더라도 아무런데나 붙어 데이터가 고장날 것이다.
이때 merge를 사용할 수 있다.
df1 = pd.read_csv('idol.csv')
# merge(): 특정 고유한 키(unique, id)값을 기준으로 합침
# merge(데이터프레임1, 데이터프레임2, on='유니크값', how='병합의 기준')
# 병합의 기준: left, right, inner, cross
pd.merge(df1, df_right, on='이름', how='left')
- on은 기준이 될 컬럼명
- how는 left, right, cross, inner 등등을 정해줄 수 있다.(rdbms의 join과 같은 내용)
left는 왼쪽에 있는 값, inner는 둘다 있는 값, cross는 모든 경우의 수를 출력한다.
등수매기기
# rank(): 데이터프레임 또는 시리즈의 순위를 매기는 함수. 기본값은 ascending
df1['브랜드순위'] = df1['브랜드평판지수'].rank([ascending=False])
df1
rank를 통해 해당 값의 순위를 매겨줄 수 있다.
- 위 코드는 브랜드 순위라는 컬럼을 만들어 준후 rank를 넣어줌
- ascending을 통해 내림차순으로 만들어줄 수도 있다.
- 기본 float로 나오지만 astype함수로 int로 만들어줄 수 있다.
# astype(): 특정열의 자료형을 변경
df1['브랜드순위'] = df1['브랜드순위'].astype(int)
df1
날짜 타입 사용하기
# to_datatime(): object타입에서 datetime타입으로 변환
df_copy['birthday'] = pd.to_datetime(df_copy['birthday'])
print(type(df_copy['birthday']))
print(df_copy['birthday'].dtypes)
위의 object메소드였던 birthday를 datetime자료형으로 변환해준다.
df_copy['birthday'].dt.year #년 출력
df_copy['birthday'].dt.month #월 출력
df_copy['birthday'].dt.day #일출력
df_copy['birthday'].dt.hour #시간 출력
df_copy['birthday'].dt.minute #분 출력
df_copy['birthday'].dt.second #초 출력
df_copy['birthday'].dt.dayofweek # 요일: 0(월요일) ~ 6(일요일)df_copy['birthday'].dt.isocalendar().week
df_copy['birthday'].dt.isocalendar().week #해당 날짜가 몇주차인가?
apply함수
데이터 프레임이나 시리즈의 데이터를 사용자 정의 함수, 내장함수에 적용하여 새로운 값을 계산하거나 변환할 때 사용됩니다.
def male_or_female(x):
if x == '남자':
return 1
elif x == '여자':
return 0
else:
return None
- 위 함수는 남자가 들어오면 1 리턴, 여자가 들어오면 0 리턴, 잘못 들어오면 None을 리턴하는 값이다.
df_copy['gender'].apply(male_or_female)
만약 해당 값으로 컬럼을 만들고자 한다면 apply를 사용해
def male_or_female(x):
if x == '남자':
return 1
elif x == '여자':
return 0
else:
return None
df_copy['gender'].apply(male_or_female)
# 0 1
# 1 1
# 2 0
# 3 0
# 4 1
# 5 0
# 6 0
# 7 0
# 8 0
# 9 0
# 10 1
# 11 0
# 12 1
# 13 0
# 14 0
# 15 0
# 16 0
# 17 0
# 18 1
# 19 1
# Name: gender, dtype: int64
위처럼 값을 변환 해줄 수 있다.
그러나 해당 함수를 간단하게 만들어주려면
df_copy['gender'].apply(lambda x: 1 if x == '남자' else 0)
- 람다식으로 true는 1 남자가 아니면 0을 출력하도록 만들 수 있다.
해당 apply함수는 피처 엔지니어링 시 데이터 값을 숫자로 변환시켜 줄 때 주로 사용한다.
더 간단하게 map으로 사용하기
map_gender = {'남자':1, '여자':0}
df_copy['gender'].map(map_gender)
# 0 1
# 1 1
# 2 0
# 3 0
# 4 1
# 5 0
# 6 0
# 7 0
# 8 0
# 9 0
# 10 1
# 11 0
# 12 1
# 13 0
# 14 0
# 15 0
# 16 0
# 17 0
# 18 1
# 19 1
# Name: gender, dtype: int64
- map을 통해 딕셔너리로 지정해둔 값을 빠르게 숫자로 만들어줄 수 있다.
- 원래값 : 데이터값
산술연산
df1 = pd.DataFrame({
'파이썬':[60, 70, 80, 90, 95],
'데이터분석':[40, 60, 70, 55, 87],
'머신러닝딥러닝':[35, 40, 30, 70, 55]
})
total = df1['파이썬'] + df1['데이터분석'] + df1['머신러닝딥러닝']
# 0 135
# 1 170
# 2 180
# 3 215
# 4 237
# dtype: int64
만약 게산시 NaN이 껴 있었다면 NaN이 결과값으로 보낸다.
Get_dummies(원핫 인코딩)

데이터의 종류는 위와 같다
범주형 데이터 판단 기준
데이터 분석, 머신러닝 모델을 만들 때 컬럼을 범주형 데이터로 변환할 지 삭제해야할지 판단해야한다.
- 실제 데이터는 숫자처럼 보이나, 의미가 없기도 하고,
- 명목형을 컴퓨터에 인지시키기 위해 숫자로 데이터를 넣어주는데 이걸 순서가 있는 숫자로 인식할 가능성도 존재한다.
- 범주형으로 처리하지 않으면 분석결과가 왜곡되기도 한다.
기준
- 값의 종류가 적고 의미있는 그룹을 형성할 때
- 성별, 지역, 직급, 날씨등
- 그룹분석이 가능하고, 평균·합계를 내는 것보다 범주별 비교가 더 의미 있는 케이스입니다.
- 숫자처럼 보이지만 수학적으로 의미가 없을 때
- 회원번호, 상품코드, 우편번호, 전화번호등
- 겉으로는 숫자처럼 보이나, 산술적 연산이 의미가 없는 것들
- 머신러닝 입력을 위해 인코딩이 필요한 경우
- color, 브라우저등
- 머신러닝은 문자열을 직접 다루지 못하므로 범주형으로 변환한 뒤 원핫 인코딩 또는 레이블 인코딩을 적용한다.
- 연속 값이지만 범주로 나누는 것이 더 의미가 있을때
- 나이(10대, 20대, 30대), 매출(고,중,저), 위험등급(Low, Medium,High)
- 상세하게 보는 게 의미가 없는 경우.
- 이처럼 의미있는 구간을 만들어 카테고리화하면 분석 인사이트가 더 명확해진다.
- 나이(10대, 20대, 30대), 매출(고,중,저), 위험등급(Low, Medium,High)
제거할 컬럼 기준
- 고유값이 너무 많아 패턴이 없는 경우
- 주문번호, 주민번호, UUID, 세션ID등 패턴이 없는 경우
- 지나치게 상세한 정보(과도한 해상도)
- 초 단위로 들어가 있는 timestamp, 도로명+상세주소 등
- 정보는 많지만 의미있는 패턴을 제공하지 않으므로 가공해야한다
- 시간: year, month, hour, weekday등으로 분리
- 주소: 시, 구 단위
- 결측치가 지나치게 많은 것.
- ex) 전체의 80% 이상이 null
- 대부분의 경우 해당 컬럼은 과감히 삭제하는 것이 중요
원 핫 인코딩
원-핫 인코딩은 각 범주를 별도의 열로 변환하고, 해당 범주에 해당하는 곳에 1을 나머지에 0을 채우는 방식
- red = 1 0 0, blue = 0 1 0, green = 0 0 1
df = pd.get_dummies(df, columns=['혈액형'])
| 이름 | 중략 | 혈액형_A | 혈액형_AB | 혈액형_B | 혈액형_O | |
| 0 | 지민 | … | True | False | False | False |
| 1 | 정국 | … | True | False | False | False |
| 2 | 민지 | … | True | False | False | False |
| 3 | 하니 | … | False | False | False | True |
| 4 | 뷔 | … | False | True | False | False |
레이블 인코딩(라벨인코딩)
각 데이터를 하나의 숫자로 연결시켜주는 작업
- red, green, blue: red=0, green=1, blue=2
'AI공부 > 머신러닝' 카테고리의 다른 글
| 5. selenium을 이용한 크롤링 (1) | 2025.11.26 |
|---|---|
| 4. 공공 데이터셋 가져오기 (0) | 2025.11.26 |
| 참고) 머신러닝/딥러닝 모델별 장단점 표 (0) | 2025.11.25 |
| 3. matplot (0) | 2025.11.19 |
| 1. numpy (0) | 2025.11.12 |