아이티윌_데이터 분석 55기/강의내용 필기_Python

#2 2일차_문자열 매서드, pandas 자료구조(Series, DataFrame), 적용함수

ecosso 2026. 5. 12. 16:18

01 문자열 매서드

 -01 대소치환

 -02 문자열 길이 (함수)

 -03 문자열 추출 (indexing)

 -04 시작/끝 여부

 -05 공백/문자열 삭제

 -06 문자열 치환

 -07 문자열 분리

 -08 포함횟수

 -09 문자열 결합

 -10 문자열 반복

 -11 문자열 포맷변경

 -12 문자열 삽입

 

02 pandas 자료구조

 -01 Series

 -02 DateFrame

 

03 적용함수

 -01 map 함수

 -02 map 매서드

 -03 apply 매서드

 -04 applymap 매서드


01 문자열 매서드

 -01 대소치환

a1.upper() # 대문자 치환
'ABCDE'.lower() # 소문자 치환
'ABCDE'.title() # camel 표기법 치환

a1.upper() # 대문자 치환
Out[205]: 'ABCDE'

'ABCDE'.lower() # 소문자 치환
Out[206]: 'abcde'

'ABCDE'.title() # camel 표기법 치환
Out[207]: 'Abcde'

 -02 문자열 길이 (함수)

len(list1) # 리스트의 원소의 개수
len(a1) # 문자열의 크기

len(list1) # 리스트의 원소의 개수
Out[208]: 4

len(a1) # 문자열의 크기
Out[209]: 5

 -03 문자열 추출 (indexing)

a1[1:4]

a1[1:4]
Out[210]: 'bcd'

 -04 시작/끝 여부

a1.startswith('a')
a1.endswith('a')

a1.startswith('a')
Out[211]: True

a1.endswith('a')
Out[212]: False

 

a1[0] == 'a'
a1[-1] == 'a'

a1[0] == 'a'
Out[213]: True

a1[-1] == 'a'
Out[214]: False

 -05 공백/문자열 삭제

a2 = '  abc  '
a2.strip()  # 양쪽에서 공백 삭제
a1.strip('a') # 양쪽에서 a 삭제

a2.strip()  # 양쪽에서 공백 삭제
Out[222]: 'abc'

a1.strip('a') # 양쪽에서 a 삭제
Out[223]: 'bcde'

 

a3 = 'aaabacaaa'
a3.strip('a')
a3.lstrip('a')
a3.rstrip('a')

a3.strip('a')
Out[225]: 'bac'

a3.lstrip('a')
Out[226]: 'bacaaa'

a3.rstrip('a')
Out[227]: 'aaabac'

 -06 문자열 치환

a1.replace('a') # 두번째 인수(바꿀 문자열) 전달 오류 

a1.replace('a') # 두번째 인수(바꿀 문자열) 전달 오류 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[228], line 1
----> 1 a1.replace('a') # 두번째 인수(바꿀 문자열) 전달 오류 

TypeError: replace() takes at least 2 positional arguments (1 given)


a1.replace('a','') # 빈 문자열 전달 시 삭제

a1.replace('a','') # 빈 문자열 전달 시 삭제
Out[229]: 'bcde'

 

a3.replace('a','A')      # a 전체가 A로 치환
a3.replace('a','A',2)   # 앞의 2개까지만 A로 치환

a3.replace('a','A')
Out[232]: 'AAAbAcAAA'

a3.replace('a','A',2)
Out[233]: 'AAabacaaa'

 -07 문자열 분리

a4 = 'abc:de:fg'
a4.split(':')[0]

a4.split(':')
Out  [3]: ['abc', 'de', 'fg']

a4.split(':')[0]
Out  [4]: 'abc'

 -08 포함횟수.

'abcaa'.count('a')


 -09 문자열 결합

'a' + 'b'


 -10 문자열 반복

'a' * 10


 -11 문자열 포맷변경

'%4s' % '123'


 -12 문자열 삽입

'%4s' % '123'

'abc'.rjust(10, '*')
'abc'.ljust(10, '*')

'%4s' % '123'
Out[69]: ' 123'

'abc'.rjust(10, '*')
Out[70]: '*******abc'

'abc'.ljust(10, '*')
Out[71]: 'abc*******'

 

'5'.zfill(10) # 왼쪽에 0을 삽입하여 총 길이를 맞춤

'5'.zfill(10) # 왼쪽에 0을 삽입하여 총 길이를 맞춤
Out[72]: '0000000005'

 

# 예) '2' -> '02'
'%02d' % int('2')
'2'.rjust(2,'0')
'2'.zfill(2)

'%02d' % int('2')
Out[73]: '02'

'2'.rjust(2,'0')
Out[74]: '02'

'2'.zfill(2)
Out[75]: '02

 -13 문자열 위치

'abc123'.find('@') # 찾는 값이 없으면 -1-을 리턴

'abc123@naver.com'.find('@')

'abc123@naver.com'[0:'abc123@naver.com'.find('@')]

'abc123'.find('@') # 찾는 값이 없으면 -1-을 리턴
'abc123@naver.com'.find('@')
'abc123@naver.com'[0:'abc123@naver.com'.find('@')]

 


[ 연습문제 ]
jumin = ['8812111223928','8905042323343','9005061234343']
email = ['abc@naver.com', 'a1004@gamil.com']
sal = ['100.00', '120.00', '200.00']

1. 생년월일 추출
'8812111223928'[0:6]
f1 = lambda x : x[0:6]
list(map(f1, jumin))

 

+)

f1 = lambda x : x[:6]
list(map(f1, jumin))

 

 2. 검색엔진 추출(naver, gmail)
'abc@naver.com'.split('@')[1].split('.')[0]
f2 = lambda x : x.split('@')[1].split('.')[0]
list(map(f2, email))

3. 급여를 정수형태로 리턴
int('100.00'.split('.')[0])
f3 = lambda x : int(x.split('.')[0])
list(map(f3, sal))

 

+)

int(sal) # 불가
int('100') # 가능
int(100.00) # 가능
int('100.00') # 불가(바로 실수처럼 생긴 문자열 -> 정수로 변환)
int(float('100.00')) # 가능

f3 = lambda x : int(float(x))
list(map(f3, sal))


02 pandas 자료구조

 - Series, DataFrame

 - key-value 구조

 

import pandas as pd
from pandas import Series, DataFrame

-01 Series

 DataFrame을 구성하는 요소로 1차원이다.

 

 1) 생성

s1 = Series([1,2,3,4,5])
s2 = Series([10,20,30,40,50])
s3 = Series([10,20,30,40,50], index = ['a','b','c','d','e'])
s3 # key값을 가지게 되었음을 확인할 수 있다.

s1
Out[127]: 
0    1
1    2
2    3
3    4
4    5
dtype: int64

s2
Out[128]: 
0    10
1    20
2    30
3    40
4    50
dtype: int64

s3
Out[129]: 
a    10
b    20
c    30
d    40
e    50
dtype: int64

2) 연산

s1 + 100
s1 + s2

s1 + 100
Out[131]: 
0    101
1    102
2    103
3    104
4    105
dtype: int64

s1 + s2
Out[132]: 
0    11
1    22
2    33
3    44
4    55
dtype: int64

 

s1 + s3

Series는 key-value 구조이므로 연산 시 같은 위치의 원소끼리 계산되는 것이 아니라, 같은 인덱스(index : key)를 가진 원소끼리 계산된다.

따라서 s1의 인덱스 0~4와 s3의 인덱스 a~e는 서로 일치하지 않기 때문에, 연산 결과는 모두 NaN이 된다.

s1 + s3
Out[133]: 
0   NaN
1   NaN
2   NaN
3   NaN
4   NaN
a   NaN
b   NaN
c   NaN
d   NaN
e   NaN
dtype: float64

 

이는 연산 과정에서 서로 없는 인덱스를 자동으로 생성하고 해당 값에 NaN을 부여하기 때문이다.

예를 들어:

 

> s1에는 1: 30이 존재하지만 s3에는 인덱스 1이 없다.
  → s3에 1: NaN을 생성한다.
  → 따라서 30 + NaN = NaN

 

반대로:

 

> s3에는 a: 2가 존재하지만 s1에는 인덱스 a가 없다.
  → 는 s1에 a: NaN을 생성한다.
  → 따라서 2 + NaN = NaN

 

즉, Series 연산에 있어 일치하는 키가 없었기 때문에 각 키의 합집합만큼의 행이 발생하며 모두 NaN이 리턴되었다.

 

** Series에서의 연산 원리

 1) 양쪽 Series의 key의 합집합 확인

 2) 각 Series를 모든 key에 대해 재배치 (이 과정에서 한쪽에만 있는 key의 값이 NA가 됨)

 3) 두 Series 연산 -> 한쪽에만 존재하는 key에 대해서는 NA가 리턴

 

s1.reindex(['a','b','c','d','e',0,1,2,3,4]) + s3.reindex(['a','b','c','d','e',0,1,2,3,4])
s4 = Series([10,20,30,40,50], index = ['c','d','e','f','g'])
s3 + s4

s3 + s4
Out[137]: 
a     NaN
b     NaN
c    40.0
d    60.0
e    80.0
f     NaN
g     NaN
dtype: float64

c,d,e에 대해서는 연산결과가 존재, 나머지 key는 NA로 리턴되었음을 확인할 수 있다.

 

** Seriesm의 산술연산 메서드
s3.add(s4, fill_value = 0) # 더하기

일치하지 않는 key가 NA처리되어 산술연산의 결과가 NA로 리턴되는 것을 방지하기 위해, NA 대신 0으로 치환을 진행한다.

fill_value는 상황에 따라 조정한다.

s3.add(s4, fill_value = 0)
Out[138]: 
a    10.0
b    20.0
c    40.0
d    60.0
e    80.0
f    40.0
g    50.0
dtype: float64

 

s3.sub(s4, fill_value = 0) # 빼기
s3.mul(s4, fill_value = 1) # 곱하기
s3.div(s4, fill_value = 1)  # 나누기

s3.sub(s4, fill_value = 0)
Out[142]: 
a    10.0
b    20.0
c    20.0
d    20.0
e    20.0
f   -40.0
g   -50.0
dtype: float64

s3.mul(s4, fill_value = 1)
Out[143]: 
a      10.0
b      20.0
c     300.0
d     800.0
e    1500.0
f      40.0
g      50.0
dtype: float64

s3.div(s4, fill_value = 1)
Out[144]: 
a    10.000000
b    20.000000
c     3.000000
d     2.000000
e     1.666667
f     0.025000
g     0.020000
dtype: float64

나누기, 곱하기의 경우 본래 값을 유지하기 위해서는 0이 아닌 1로 치환해야 한다.

따라서 이 경우 fill_value = 1이 설정되었다.


 3) 구조변경

s3.reindex(['c','d','e','a','b']) # key 재배치
s2.index # index 확인

 


s2.index = ['a','b','c','d','e']
list('abcde')

list('abcde')
Out[146]: ['a', 'b', 'c', 'd', 'e']

s2.index = list('abced')

 

s2.index
Out[148]: Index(['a', 'b', 'c', 'e', 'd'], dtype='object')

list() 기능을 이용하여 좀 더 쉽게 인덱스를 변경할 수 있다.

 


 4) 색인 (매우 중요)

s1[0]     # 첫 번째 원소 추출
s1[0:2]   # 처음부터 연속적으로 두 개 추출
s1[[0,3]] # 비연속적인 위치 추출 가능

s2['a']   # 이름 기반 추출
s2['a':'c'] # 이름 기반 연속 추출

s2.a # key indexing

# ** 색인 메서드
# .iloc : 위치기반 추출
# .loc : 이름, 조건 추출

s1[0]
s1.iloc[0]

s1[-1]      # 불가
s1.iloc[-1] # 가능

s2['a'] # 가능
s2.loc['a'] # 가능
s2.iloc['a'] # 불가(a가 위치가 아니므로)

 

s1[s1 >= 3] # 가능
s1.loc[s1 >=3] # 가능


 5) 기타 메서드

s1.index # index(key)만 추출
s1.values # value만 추출
s1.dtype # 데이터 타입 확인

s1.index # index(key)만 추출
Out[186]: RangeIndex(start=0, stop=5, step=1)

s1.values # value만 추출
Out[187]: array([1, 2, 3, 4, 5])

s1.dtype # 데이터 타입 확인
Out[188]: dtype('int64')

 -02 DateFrame

 2차원의 key-value 구조를 가진 데이터 구조이다.

 

 1) 생성
df1 = DataFrame({'col1' : [1,2,3,4], 'col2' : ['A','B','C','D']})
df2 = DataFrame({'col1' : [1,2,3,4], 'col2' : ['A','B','C','D']}, index = list('abcd'))



 2) 색인

# ** key(column) 접근

df1.iloc[0] # 첫 번째 행 선택 (행 우선순위이기에 뒤의 : 을 생략 가능하다.)
df1.iloc[0,0] # 첫 번째 행, 첫 번째 컬럼
df1.iloc[0,:] # 첫 번째 행의 모든 컬럼
df1.iloc[:,0] # 모든 행의 첫 번째 컬럼

df1.iloc[0,0] # 첫 번째 행, 첫 번째 컬럼
Out[201]: np.int64(1)

df1.iloc[0,:] # 첫 번째 행의 모든 컬럼
Out[202]: 
col1    1
col2    A
Name: 0, dtype: object

df1.iloc[:,0] # 모든 행의 첫 번째 컬럼
Out[203]: 
0    1
1    2
2    3
3    4
Name: col1, dtype: int64

 

# ** 행, 열 접근

df2.loc['a']      # a 행 선택

df2.loc['a', : ]  # a 행 선택

 

df2.loc['a', 'col1'] 


df2.loc[:,'col1']
df2.loc[2,'col1'] # 에러

조건에 대한 색인이므로 loc 사용
# 컬럼이 A인 행 선택
df2['col2'] == 'A'
df2.loc[df2['col2'] == 'A',:]

 

# ** 주의 : loc의 경우 위치값을 전달하면 이름으로 해석한다.
# index가 부여되지 않은 경우 -> 이름 또는 위치로 모두 전달 가능
df1.loc[1:3, 'col2']

 

0,1,2,3이 이름으로 해석이 되고 있는 상황이기에 1:3에 해당되는 1,2,3 의 값을 가진 행이 선택되었다.

df1.loc[1:3, 'col2']
Out[215]: 
1    B
2    C
3    D
Name: col2, dtype: object

 3) 구조변경

  (1) 전체 변경

df1.index = list('abcd')
df1.columns = ['A','B']

 

인덱스 혹은 컬럼을 변경할 수 있다.

인덱스 혹은 컬럼의 일부 변경이 필요한 순간이 종종 있다.

 

  (2) 일부 수정

df1.index[1] = 'B'

그러나 인덱스 전부를 모두 덮어씌우기는 가능하나, 위와 같이 인덱스의 일부 수정은 불가능하다.

df1.index[1] = 'B'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[264], line 1
----> 1 df1.index[1] = 'B'

File ~\anaconda3\Lib\site-packages\pandas\core\indexes\base.py:5383, in Index.__setitem__(self, key, value)
   5381 @final
   5382 def __setitem__(self, key, value) -> None:
-> 5383     raise TypeError("Index does not support mutable operations")

TypeError: Index does not support mutable operations

위와 같이 에러가 발생함을 알 수 있다.

 

a1 = list(df1.index)
a1[1] = 'B'
df1.index = a1

# 위와 같은 과정으로 수정이 가능하나 매번 반복하기에 어려움이 있다.

df1.rename?

더보기
더보기
Signature:
df1.rename(
    mapper: 'Renamer | None' = None,
    *,
    index: 'Renamer | None' = None,
    columns: 'Renamer | None' = None,
    axis: 'Axis | None' = None,
    copy: 'bool | None' = None,
    inplace: 'bool' = False,
    level: 'Level | None' = None,
    errors: 'IgnoreRaise' = 'ignore',
) -> 'DataFrame | None'
Docstring:
Rename columns or index labels.

Function / dict values must be unique (1-to-1). Labels not contained in
a dict / Series will be left as-is. Extra labels listed don't throw an
error.

See the :ref:`user guide <basics.rename>` for more.

Parameters
----------
mapper : dict-like or function
    Dict-like or function transformations to apply to
    that axis' values. Use either ``mapper`` and ``axis`` to
    specify the axis to target with ``mapper``, or ``index`` and
    ``columns``.
index : dict-like or function
    Alternative to specifying axis (``mapper, axis=0``
    is equivalent to ``index=mapper``).
columns : dict-like or function
    Alternative to specifying axis (``mapper, axis=1``
    is equivalent to ``columns=mapper``).
axis : {0 or 'index', 1 or 'columns'}, default 0
    Axis to target with ``mapper``. Can be either the axis name
    ('index', 'columns') or number (0, 1). The default is 'index'.
copy : bool, default True
    Also copy underlying data.

    .. note::
        The `copy` keyword will change behavior in pandas 3.0.
        `Copy-on-Write
        <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__
        will be enabled by default, which means that all methods with a
        `copy` keyword will use a lazy copy mechanism to defer the copy and
        ignore the `copy` keyword. The `copy` keyword will be removed in a
        future version of pandas.

        You can already get the future behavior and improvements through
        enabling copy on write ``pd.options.mode.copy_on_write = True``
inplace : bool, default False
    Whether to modify the DataFrame rather than creating a new one.
    If True then value of copy is ignored.
level : int or level name, default None
    In case of a MultiIndex, only rename labels in the specified
    level.
errors : {'ignore', 'raise'}, default 'ignore'
    If 'raise', raise a `KeyError` when a dict-like `mapper`, `index`,
    or `columns` contains labels that are not present in the Index
    being transformed.
    If 'ignore', existing keys will be renamed and extra keys will be
    ignored.

Returns
-------
DataFrame or None
    DataFrame with the renamed axis labels or None if ``inplace=True``.

Raises
------
KeyError
    If any of the labels is not found in the selected axis and
    "errors='raise'".

See Also
--------
DataFrame.rename_axis : Set the name of the axis.

Examples
--------
``DataFrame.rename`` supports two calling conventions

* ``(index=index_mapper, columns=columns_mapper, ...)``
* ``(mapper, axis={'index', 'columns'}, ...)``

We *highly* recommend using keyword arguments to clarify your
intent.

Rename columns using a mapping:

>>> df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
>>> df.rename(columns={"A": "a", "B": "c"})
   a  c
0  1  4
1  2  5
2  3  6

Rename index using a mapping:

>>> df.rename(index={0: "x", 1: "y", 2: "z"})
   A  B
x  1  4
y  2  5
z  3  6

Cast index labels to a different type:

>>> df.index
RangeIndex(start=0, stop=3, step=1)
>>> df.rename(index=str).index
Index(['0', '1', '2'], dtype='object')

>>> df.rename(columns={"A": "a", "B": "b", "C": "c"}, errors="raise")
Traceback (most recent call last):
KeyError: ['C'] not found in axis

Using axis-style parameters:

>>> df.rename(str.lower, axis='columns')
   a  b
0  1  4
1  2  5
2  3  6

>>> df.rename({1: 2, 2: 4}, axis='index')
   A  B
0  1  4
2  2  5
4  3  6
File:      c:\users\green\anaconda3\lib\site-packages\pandas\core\frame.py
Type:      method

 

# index 수정

df1.rename(index={'d':'D'})

df1.rename({'d':'D'}, axis = 0) 와 같다.

df1.rename(index={'d':'D'})
Out[270]: 
   A  B
a  1  A
b  2  B
c  3  C
D  4  D

마지막 d가 D로 변경되었음을 확인할 수 있다.

따라서 index 수정은 rename 매서드의 사용이 필수적임을 확인할 수 있다.

 

# column 수정

df1.rename({'A':'col1'}, axis = 1)

* axis의 default는 0이다.

* index : 0, column : 1 로 지정이 가능하다.

df1.rename({'A':'col1'}, axis = 1)
Out[271]: 
   col1  B
a     1  A
b     2  B
c     3  C
d     4  D

 4) 기타 매서드

df1.dtypes   # str()과 유사하다.

컬럼별 데이터타입이 출력된다.

df1.dtypes
Out[273]: 
A     int64
B    object
dtype: object

 

df1.shape    # 사이즈(행, 컬럼)

df1.shape 
Out[274]: (4, 2)

 

df1.shape[0] # 행 크기
df1.shape[1] # 컬럼 크기

df1.shape[0] # 행 크기
Out[275]: 4

df1.shape[1] # 컬럼 크기
Out[276]: 2

 

df1.info()   # 데이터프레임 요약 (컬럼별 데이터타입, 컬럼별 null 확인, 총 사이즈 확인)

df1.info()
<class 'pandas.core.frame.DataFrame'>
Index: 4 entries, a to d
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   A       4 non-null      int64 
 1   B       4 non-null      object
dtypes: int64(1), object(1)
memory usage: 268.0+ bytes

 

df1.index        # index 확인
df1.columns   # column 확인
df1.values      # 값 확인

df1.index
Out[278]: Index(['a', 'b', 'c', 'd'], dtype='object')

df1.columns
Out[279]: Index(['A', 'B'], dtype='object')

df1.values
Out[280]: 
array([[1, 'A'],
       [2, 'B'],
       [3, 'C'],
       [4, 'D']], dtype=object)

[ 연습문제 ]
# 1. 모든 직원의 ENAME, SAL 컬럼 선택


emp[['ENAME, 'SAL'']]


# 또는


emp.loc[:,['ENAME', 'SAL']]

emp.loc[:,['ENAME', 'SAL']]
Out[254]: 
     ENAME   SAL
0    SMITH   800
1    ALLEN  1600
2     WARD  1250
3    JONES  2975
4   MARTIN  1250
5    BLAKE  2850
6    CLARK  2450
7    SCOTT  3000
8     KING  5000
9   TURNER  1500
10   ADAMS  1100
11   JAMES   950
12    FORD  3000
13  MILLER  1300

# 2. 8~10의 위치에 해당하는 행 선택
emp.iloc[8:11, :] # 8~10 선택
emp.loc[8:11, :]  # 8~11 선택

# 마지막 end 포함여부에 차이가 있기 때문에 문자에 대한 slice인지 숫자에 대한 slice인지 구분해야 한다.
# 문자열 slice는 마지막을 포함하기 때문에 11가지 포함한다.
# 따라서 두 코드 모두 가능하나 범위가 어디까지 포함되는지에 대한 이해가 필요하다.

emp.iloc[8:11, :]
Out[255]: 
    EMPNO   ENAME        JOB     MGR         HIREDATE   SAL  COMM  DEPTNO
8    7839    KING  PRESIDENT     NaN  1981-11-17 0:00  5000   NaN      10
9    7844  TURNER   SALESMAN  7698.0  1981-09-08 0:00  1500   0.0      30
10   7876   ADAMS      CLERK  7788.0  1987-05-23 0:00  1100   NaN      20

emp.loc[8:11, :]
Out[256]: 
    EMPNO   ENAME        JOB     MGR         HIREDATE   SAL  COMM  DEPTNO
8    7839    KING  PRESIDENT     NaN  1981-11-17 0:00  5000   NaN      10
9    7844  TURNER   SALESMAN  7698.0  1981-09-08 0:00  1500   0.0      30
10   7876   ADAMS      CLERK  7788.0  1987-05-23 0:00  1100   NaN      20
11   7900   JAMES      CLERK  7698.0  1981-12-03 0:00   950   NaN      30

# 3. 0, 13 위치에 해당하는 행의 ENAME, SAL, COMM 컬럼 선택
emp.loc[[0,13], ['ENAME', 'SAL', 'COMM']]

emp.loc[[0,13], ['ENAME', 'SAL', 'COMM']]
Out[257]: 
     ENAME   SAL  COMM
0    SMITH   800   NaN
13  MILLER  1300   NaN

# 4. SMITH의 ENAME부터 DEPTNO 컬럼까지 모두 선택
emp.loc[emp['ENAME'] == 'SMITH','ENAME':'DEPTNO']

# True / False 로 나뉘는 경우는 loc만 사용 가능하다.

emp['ENAME'] == 'SMITH'
Out[258]: 
0      True
1     False
2     False
3     False
4     False
5     False
6     False
7     False
8     False
9     False
10    False
11    False
12    False
13    False
Name: ENAME, dtype: bool

emp.loc[emp['ENAME'] == 'SMITH','ENAME':'DEPTNO']
Out[259]: 
   ENAME    JOB     MGR         HIREDATE  SAL  COMM  DEPTNO
0  SMITH  CLERK  7902.0  1980-12-17 0:00  800   NaN      20

# 5. 10번 부서원의 ENAME, JOB, DEPTNO 컬럼 선택
emp.loc[emp['DEPTNO'] == 10, ['ENAME','JOB','DEPTNO']]

emp.loc[emp['DEPTNO'] == 10, ['ENAME','JOB','DEPTNO']]
Out[260]: 
     ENAME        JOB  DEPTNO
6    CLARK    MANAGER      10
8     KING  PRESIDENT      10
13  MILLER      CLERK      10

값이 숫자인 경우 비교에 있어 수치형으로 지정해주어야 한다.

R의 경우 숫자형을 '10'과 같이 문자형으로 지정하여도 자동으로 수치로 변환하나, Python은 그러한 변환을 거치지 않는다.

따라서 조회하려는 데이터타입을 잘 확인해야 한다.


# [ 예제 - 문자열 메서드 적용 ]
1. 이름을 소문자로 변경
emp['ENAME'].lower  # error

# 1) map 함수
f1 = lambda x : x.lower()
Series(map(f1, emp['ENAME']))

Series(map(f1, emp['ENAME']))
Out[285]: 
0      smith
1      allen
2       ward
3      jones
4     martin
5      blake
6      clark
7      scott
8       king
9     turner
10     adams
11     james
12      ford
13    miller
dtype: object

 

# 2) map 메서드
# Series에게도 map을 자주 사용하다보니 series 전용 map 메서드가 탄생하게 되었다.
# 즉시 호출이 가능하다.
emp['ENAME'].map(f1)

emp['ENAME'].map(f1)
Out[286]: 
0      smith
1      allen
2       ward
3      jones
4     martin
5      blake
6      clark
7      scott
8       king
9     turner
10     adams
11     james
12      ford
13    miller
Name: ENAME, dtype: object

# 2. 입사연도 추출
# 1) map 함수
f2 = lambda x : x.split('-')[0]
Series(map(f2, emp['HIREDATE']))

# 2) map 매서드
emp['HIREDATE'].map(f2)

Series(map(f2, emp['HIREDATE']))
Out[292]: 
0     1980
1     1981
2     1982
3     1981
4     1981
5     1981
6     1981
7     1987
8     1981
9     1981
10    1987
11    1981
12    1981
13    1982
dtype: object

emp['HIREDATE'].map(f2)
Out[293]: 
0     1980
1     1981
2     1982
3     1981
4     1981
5     1981
6     1981
7     1987
8     1981
9     1981
10    1987
11    1981
12    1981
13    1982
Name: HIREDATE, dtype: object

 

# 또는
emp['HIREDATE'].map(lambda x : x[:4])


03 적용함수
 각 원소별, 행별, 열별 함수의 반복적으로 적용하여 조합을 리턴하는 함수이며, 분리(fetch) - 적용 - 결합의 매커니즘을 가지고 있다.


 -01 map 함수
 1차원 객체(list, Series)의 원소별 함수 적용
 여러 객체의 원소별 적용
 리턴 타입 : 사용자 지정 가능 (list, Series)


 -02 map 매서드
 1차원 객체(Series 전용)의 원소별 함수 적용
 단 하나의 객체의 원소별 적용 가능
 리턴 타입 : Series (자동)


 -03 apply 매서드
 2차원의 DataFrame만 호출 가능
 행별, 열별 적용


df = DataFrame([[1,2,3],[4,5,6],[7,8,9]], columns = list('ABC'))
df

 문법 : df.apply(func,          # 적용할 함수
                         axis = 0)   # 방향 (행별, 열별)
df.apply(sum, axis = 0)
df.apply(sum, axis = 1)


 ** 축 번호 : 행(0), 컬럼(1)
df.sum(axis = 0) # 행별 총합 (세로 방향)
df.sum(axis = 1) # 열별 총합 (가로 방향)

 행별 총합을 R에서는 같은 행끼리 묶어서 서로 다른 열의 값을 연산하게 된다.
 컬럼별 총합을 R에서는 같은 컬럼끼리 묶어서 서로 다른 행의 값을 연산하게 된다.

 파이썬에서는 행별 총합을 '서로 다른 행끼리' 의 연산을 진행하게 된다.
 파이썬에서는 컬럼별 총합을 '서로 다른 컬럼끼리'의 연산을 진행하게 된다.

 즉, R과 연산 방향이 반대다.


 -04 applymap 매서드
 2차원의 DataFrame만 호출 가능
 원소별 적용

'%.2f' % 100  # 상수 적용 가능
'%.2f' % df   # 데이터프레임 적용 불가
df

df.applymap(lambda x : '%.2f' % x)


# [ 예제 - 문자열 메서드 적용 (card_history) ]
card = pd.read_csv('card_history.csv', encoding='cp949')

# 1) 식료품 컬럼 총합
card['식료품'].map(lambda x : int(x.replace(',',''))).sum()

### 문제풀이
f1 = lambda x : int(x.replace(',',''))
card['식료품'] = card['식료품'].map(f1)
card['식료품'].sum()

# 2) 각 품목별 총합
card.sum()
card['식료품'].map(lambda x : int(x.replace(',',''))).sum()


me = card[card.columns[1:]].map(lambda x : int(x.replace(',',''))).sum()
me2 = card[card.columns[1:]].applymap(lambda x: int(x.replace(',', ''))).sum()

### 문제풀이
card.applymap(f1)

# 식료품 컬럼은 1번에서 변환을 진행하였으므로 no, 식료품 컬럼은 제외하기로 함

card.iloc[:,2:] = card.iloc[:,2:].applymap(f1)
card.iloc[:,1:].sum(axis = 0)