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)
'아이티윌_데이터 분석 55기 > 강의내용 필기_Python' 카테고리의 다른 글
| #6 6일차_pd의 행·열 결합 / 수학 및 통계 함수·메서드 / 결측치 처리 (0) | 2026.05.18 |
|---|---|
| #5 5일차_형 변환 함수/매서드, SQL사용, DB 연동, array (0) | 2026.05.15 |
| #4 4일차_사용자 정의함수, groupby 연산, 조인 (0) | 2026.05.14 |
| #3 3일차_조건문, 반복문 (0) | 2026.05.13 |
| #1 1일차_파이썬 설치 및 실행, 실습, 자료구조(리스트) (0) | 2026.05.11 |