데이터 분석의 기초: Series 객체
Pandas는 행(row)과 열(column) 형태의 '정형 데이터'를 다루는 대표적인 Python 라이브러리입니다. 엑셀 시트나 RDB의 테이블과 유사한 2차원 구조를 다루며, 그 기본이 되는 객체가 바로 Series와 DataFrame입니다.
1. Series란?
- Pandas의 가장 기본적인 객체 중 하나입니다.
- Numpy의
ndarray를 기반으로 하며, 인덱싱 기능이 추가된 1차원 배열입니다.
- index x value의 형태를 가집니다.
- 같은 타입의 데이터를 0개 이상 가질 수 있습니다.
2. Series 생성 및 기초 속성
기본 생성 (0-based Index)
데이터만 전달하면 인덱스는 0부터 자동으로 부여됩니다.
import numpy as np
import pandas as pd
s1 = pd.Series([10, 20, 30])
print(s1)
s1.values
s1.index
s1.dtype
dtype('int64')
명시적 인덱스 설정
인덱스는 숫자일 필요가 없으며 중복도 허용됩니다.
pd.Series(data=[1, 2, 3], index=[100, 200, 300])
s5 = pd.Series(data=[1, 2, 3], index=['john', 'mark', 'charlie'])
s5['john']
s6 = pd.Series([1, 2, 3], ['john', 'john', 'charlie'])
s6['john']
3. 딕셔너리(dict)를 이용한 생성
딕셔너리의 Key는 Index가 되고, Value는 데이터 값이 됩니다.
sdata = {'김철수': 35000, '이상현': 67000, '최종수': 12000, '박진관': 4000}
pd.Series(sdata)
| 0 |
|---|
| 김철수 | 35000 |
| 이상현 | 67000 |
| 최종수 | 12000 |
| 박진관 | 4000 |
4. 인덱싱과 값 변경
s7 = pd.Series(data=np.arange(5), index=np.arange(100, 105), dtype=np.int16)
s7[102]
s7[[102, 104]]
s7[104] = 70
s7
s7[105] = 90
| | 0 |
|---|
| 100 | 0 |
| 101 | 1 |
| 102 | 2 |
| 103 | 3 |
| 104 | 70 |
| 105 | 90 |
5. 주요 함수 및 통계 (NaN 처리)
Pandas의 집계 연산은 NaN(결측치)을 제외하고 계산하는 특징이 있습니다.
- size: 전체 개수 반환
- shape: 튜플 형태로 형태 반환
- unique(): 유일한 값들을 ndarray로 반환
- count(): NaN을 제외한 데이터 개수
- mean(): NaN을 제외한 평균!!
- value_counts(): 각 값들의 빈도수 반환 (NaN 제외)
[예시: Numpy vs Pandas의 NaN 처리]
a1 = np.array([2, 2, 2, 2, np.nan])
print(a1.mean())
print(pd.Series(a1).mean())
6. Series 연산
Series끼리의 연산은 순서가 아닌 같은 인덱스를 기준으로 수행됩니다.
s1 = pd.Series([1, 2, 3, 4], ['a', 'b', 'c', 'd'])
s2 = pd.Series([6, 3, 2, 1], ['d', 'c', 'b', 'a'])
print(s1 + s2)
7. Boolean Selection (필터링)
조건식을 [] 안에 넣어 원하는 데이터만 추출할 수 있습니다.
s = pd.Series(np.arange(10), np.arange(10) + 1)
s > 5
| | 0 |
|---|
| 1 | False |
| 2 | False |
| 3 | False |
| 4 | False |
| 5 | False |
| 6 | False |
| 7 | True |
| 8 | True |
| 9 | True |
| 10 | True |
s[s > 5]
s[s % 2 == 0]
8. 데이터 삭제: drop() 및 inplace
-
대부분의 Pandas 함수는 원본을 건드리지 않고 사본을 반환합니다.
drop() 함수는 drop 한결과 를 새로 만들어서 리턴한거고
원본 데이터 s 는 변경하지 않습니다
-
numpy , pandas, 그밖의 수많은 데이터 관련 모듈들 에서의
대부분의 객체 함수들은 호출한 원본 객체를 변경하진 않고
원본의 사본을 만든뒤 사본 에 연산수행하여 그 사본 을 리턴하도록 동작합니다
그러나!
-
inplace=True 파라미터를 주면 사본 을 만들지 않고 원본을 변화시키도록 동작합니다
s = pd.Series(np.arange(100, 105), ['a', 'b', 'c', 'd', 'e'])
s.drop('a')
s.drop('b', inplace=True)
9. Multi-level Index (다중 인덱스)
계층적인 인덱스 구조를 가질 수 있습니다.
s3 = pd.Series([1, 2, 3, 4, 5, 6], ['a', 'a', 'b', 'b', 'c', 'c'])
s3.index
s4 = pd.Series(
np.arange(100, 106),
index = [
['a', 'a', 'b', 'b', 'c', 'c'],
[ 1 , 2 , 1, 2 , 1, 2 ],
]
)
| Level 0 | Level 1 | Data (데이터) |
|---|
| a | 1 | 100 |
| 2 | 101 |
| b | 1 | 102 |
| 2 | 103 |
| c | 1 | 104 |
| 2 | 105 |
s4.index
s4['a', 1]
s4.xs('a')
s4.xs(('a', 1))
s4.xs(2, level=1)
10. apply()와 rename()
Pandas의 apply()는 데이터 전처리 시 가장 빈번하게 사용하는 함수 중 하나입니다.
각 원소에 복잡한 로직을 적용하거나 문자열을 가공할 때 매우 유용합니다.
Series.apply(func, convert_dtype=True, args=(), **kwargs)
다양한 apply() 활용 사례
단순 연산부터 인자 전달, 문자열 처리까지의 예제입니다.
import pandas as pd
import numpy as np
s = pd.Series([1, 2, 3, 4, 5])
result_sq = s.apply(lambda x: x ** 2)
def custom_func(x):
return f"Value: {x}"
result_custom = s.apply(custom_func)
def multiply(x, factor):
return x * factor
result_mult = s.apply(multiply, args=(10,))
s2 = pd.Series([" Apple ", "Banana", " Cherry "])
result_str = s2.apply(lambda x: x.strip().lower())
0 1
1 4
2 9
3 16
4 25
dtype: int64
0 Value: 1
1 Value: 2
2 Value: 3
3 Value: 4
4 Value: 5
dtype: object
0 10
1 20
2 30
3 40
4 50
dtype: int64
0 apple
1 banana
2 cherry
dtype: object
📊 주요 실행 결과 (표)
| 구분 | 데이터 예시 (첫 행) | 설명 |
|---|
| 제곱 적용 | 1 → 1, 5 → 25 | 모든 원소에 지수 연산 수행 |
| 문자 포맷 | 1 → "Value: 1" | 숫자 데이터를 문자열 템플릿에 결합 |
| 인자 전달 | 1 → 10, 5 → 50 | args=(10,)을 통해 10배수 연산 |
| 문자열 처리 | " Apple " → "apple" | 양끝 공백 제거(strip) 및 소문자화 |
rename()을 이용한 인덱스 변경
Series의 특정 인덱스 이름을 바꾸고 싶을 때는 rename() 메서드를 사용합니다.
딕셔너리 형태({기존: 변경})로 전달하면 원하는 인덱스만 콕 집어 바꿀 수 있습니다.
s2_renamed = s2.rename(index={1: 'haha'})
print(s2_renamed)
📊 인덱스 변경 결과 (s2.rename)
| Index (인덱스) | Data (데이터) |
|---|
| 0 | " apple " |
| haha | "banana" |
| 2 | " Cherry " |
💡 핵심 정리
- apply(args=...): 함수에 고정된 상수값을 전달해야 할 때
args 파이썬 튜플을 사용합니다.
- Method Chaining:
s2.apply(lambda x: x.strip()).apply(lambda x: x.lower()) 처럼 여러 번 이어서 사용할 수도 있습니다.
- Immutability:
rename이나 apply 모두 원본을 바로 바꾸지 않고 새로운 객체를 반환합니다. 원본을 바꾸려면 다시 할당(s2 = s2.rename(...))해야 합니다.