MCP - 13일차(Pandas-Series)

Jun·2026년 2월 15일

MCP

목록 보기
18/20

데이터 분석의 기초: Series 객체

Pandas는 행(row)과 열(column) 형태의 '정형 데이터'를 다루는 대표적인 Python 라이브러리입니다. 엑셀 시트나 RDB의 테이블과 유사한 2차원 구조를 다루며, 그 기본이 되는 객체가 바로 SeriesDataFrame입니다.


1. Series란?

  • Pandas의 가장 기본적인 객체 중 하나입니다.
  • Numpy의 ndarray를 기반으로 하며, 인덱싱 기능이 추가된 1차원 배열입니다.
  • index x value의 형태를 가집니다.
  • 같은 타입의 데이터를 0개 이상 가질 수 있습니다.

2. Series 생성 및 기초 속성

기본 생성 (0-based Index)

데이터만 전달하면 인덱스는 0부터 자동으로 부여됩니다.

import numpy as np
import pandas as pd  #pandas를 위해 필수 #pandas를 위해 필수
s1 = pd.Series([10, 20, 30])
print(s1)
# 결과: 왼쪽이(0,1,2) index,
# 오른쪽이(10,20,30) value, 
# dtype은 데이터 타입

# 주요 속성 확인
s1.values  # 값 확인 (ndarray)
# array([10, 20, 30])

s1.index   # 인덱스 범위/구성 확인
# RangeIndex(start=0, stop=3, step=1)

s1.dtype   # 데이터 타입 확인
dtype('int64')

명시적 인덱스 설정

인덱스는 숫자일 필요가 없으며 중복도 허용됩니다.

# 숫자 인덱스 지정
pd.Series(data=[1, 2, 3], index=[100, 200, 300])

# 출력결과
0
1001
2002
3003
# index 는 굳이 정수일 필요 없다!
s5 = pd.Series(data=[1, 2, 3], index=['john', 'mark', 'charlie'])
0
john1
mark2
charlie3
# 인덱싱
s5['john'] # np.int64(1)

# 인덱스 중복 허용
s6 = pd.Series([1, 2, 3], ['john', 'john', 'charlie'])
0
john1
john2
charlie3
# 중복 indexing 결과 Series!!
s6['john']
0
john1
john2

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)
   0  
1000
1011
1022
1033
1044
# 단일 값 접근 (Scalar 반환)
s7[102] #np.int16(2)

# 여러 값 접근 (Series 반환) 1차원 (차원 변화 없슴.)
s7[[102, 104]] 
   0  
1022
1044
# 값 변경 및 신규 삽입
s7[104] = 70  # 기존 값 변경
s7
   0  
1000
1011
1022
1033
10470
s7[105] = 90  # 기존에 없던 인덱스에 값을 대입 시 새로 생성 (Numpy와 차별점)
   0  
1000
1011
1022
1033
10470
10590

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())          # 결과: nan (연산 불가)

print(pd.Series(a1).mean()) # 결과: 2.0 (nan 무시)

6. Series 연산

Series끼리의 연산은 순서가 아닌 같은 인덱스를 기준으로 수행됩니다.

s1 = pd.Series([1, 2, 3, 4], ['a', 'b', 'c', 'd'])
   0  
a1
b2
c3
d6
s2 = pd.Series([6, 3, 2, 1], ['d', 'c', 'b', 'a'])
   0  
d6
c3
b2
a1
print(s1 + s2) # 'a'는 'a'끼리, 'b'는 'b'끼리 연산
# 인덱스 쌍이 맞지 않으면 결과는 NaN으로 채워집니다.
   0  
a2
b4
c6
d12

7. Boolean Selection (필터링)

조건식을 [] 안에 넣어 원하는 데이터만 추출할 수 있습니다.

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

s > 5 # 조건에 맞으면 True, 틀리면 False
    0  
1False
2False
3False
4False
5False
6False
7True
8True
9True
10True
s[s > 5]        # 5보다 큰 값만 추출
    0  
76
87
98
109
s[s % 2 == 0]   # 짝수 값만 추출
    0  
10
32
54
76
98

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  #Index(['a', 'a', 'b', 'b', 'c', 'c'], dtype='object')

# ↑ 단일 level index 다!


# multi-level index 를 가진 Series
s4 = pd.Series(
    np.arange(100, 106),
    index = [
        ['a', 'a', 'b', 'b', 'c', 'c'], # Level 0
        [ 1 ,  2 ,  1,   2 ,  1,   2 ], # Level 1
    ]
)
 Level 0  Level 1   Data (데이터)  
a1100
2101
b1102
2103
c1104
2105
# 인덱스
s4.index #MultiIndex([('a', 1),
                     #('a', 2),
            		 #('b', 1),
            		 #('b', 2),
            		 #('c', 1),
            		 #('c', 2)],
           			 #)

#인덱싱 방법
s4['a', 1]     # 튜플 형태 접근  #np.int64(100)

s4.xs('a')     # 특정 레벨 추출 (Cross-section)

s4.xs(('a', 1))  # () 괄호 꼭 필요!   # s4['a', 1] 과 동일

# s4.xs(2)  # 에러, level 0 에서 2 라는 index? 없다!
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])

    # [사례 1] 람다(lambda)를 이용한 제곱 연산
    result_sq = s.apply(lambda x: x ** 2)

    # [사례 2] 사용자 정의 함수로 문자열 포맷팅
    def custom_func(x):
        return f"Value: {x}"
    result_custom = s.apply(custom_func)

    # [사례 3] args를 통한 추가 인자(factor) 전달
    def multiply(x, factor):
        return x * factor
    result_mult = s.apply(multiply, args=(10,))

    # [사례 4] 문자열 공백 제거 및 소문자 변환
    s2 = pd.Series(["  Apple ", "Banana", " Cherry "])
    result_str = s2.apply(lambda x: x.strip().lower())
    
    
   #[사례 1]출력 결과 
    0     1
	1     4
	2     9
	3    16
	4    25
	dtype: int64
    
    #[사례 2]출력 결과 
    0    Value: 1
	1    Value: 2
	2    Value: 3
	3    Value: 4
	4    Value: 5
	dtype: object
    
    #[사례 3]출력 결과 
    0    10
	1    20
	2    30
	3    40
	4    50
	dtype: int64
    
    #[사례 4]출력 결과 
    0     apple
	1    banana
	2    cherry
	dtype: object
    

📊 주요 실행 결과 (표)

  구분    데이터 예시 (첫 행)    설명  
제곱 적용1 → 1, 5 → 25모든 원소에 지수 연산 수행
문자 포맷1 → "Value: 1"숫자 데이터를 문자열 템플릿에 결합
인자 전달1 → 10, 5 → 50args=(10,)을 통해 10배수 연산
문자열 처리" Apple " → "apple"양끝 공백 제거(strip) 및 소문자화

rename()을 이용한 인덱스 변경

Series의 특정 인덱스 이름을 바꾸고 싶을 때는 rename() 메서드를 사용합니다.
딕셔너리 형태({기존: 변경})로 전달하면 원하는 인덱스만 콕 집어 바꿀 수 있습니다.

    # 인덱스 1번을 'haha'로 변경
    s2_renamed = s2.rename(index={1: 'haha'})
    
    print(s2_renamed)

📊 인덱스 변경 결과 (s2.rename)

  Index (인덱스)    Data (데이터)  
0" apple "
haha"banana"
2" Cherry "

💡 핵심 정리

  1. apply(args=...): 함수에 고정된 상수값을 전달해야 할 때 args 파이썬 튜플을 사용합니다.
  2. Method Chaining: s2.apply(lambda x: x.strip()).apply(lambda x: x.lower()) 처럼 여러 번 이어서 사용할 수도 있습니다.
  3. Immutability: rename이나 apply 모두 원본을 바로 바꾸지 않고 새로운 객체를 반환합니다. 원본을 바꾸려면 다시 할당(s2 = s2.rename(...))해야 합니다.
profile
Hard Trying

0개의 댓글