df.apply(func, axis=0, raw=False, result_type=None, args=(), kwargs)
function : 각 행이나 열에 적용할 함수 입니다.
axis : {0 : Index / 1 : columns} 함수를 적용할 축 입니다.
row : {True : ndarray / False : Series} 함수에 전달할 축의 형식입니다.
True면 ndarray형태로 전달하고 False면 Series형태로 전달합니다. 기본적으로 Series입니다.
result_type : {expand / reduce / broadcast} 반환값의 형태를 결정합니다. expand이면 배열 형태를
기준으로 열을 확장합니다.(기본 인덱스로), reduce인 경우는 그대로 Serise형태로 반환합니다.
broadcase인 경우 기존 열 형식대로 확장하여 반환합니다.(열의 수가 같아야합니다.)
객체 생성
col = ['col1','col2','col3']
row = ['row1','row2','row3']
data = [[1,2,3],[4,5,6],[7,8,9]]
df = pd.DataFrame(data=data,index=row,columns=col)
print(df)
# col1 col2 col3
#row1 1 2 3
#row2 4 5 6
#row3 7 8 9
func의 성질에 따른 차이
func항목이 np.sqrt처럼 축에대해 계산할 수 없는 형식이라면 아래와 같이 각 요소에 적용됩니다.
print(df.apply(np.sqrt))
# col1 col2 col3
#row1 1.000000 1.414214 1.732051
#row2 2.000000 2.236068 2.449490
#row3 2.645751 2.828427 3.000000
np.sum처럼 축에대해 적용이 가능한경우라면 축 기준으로 연산을 수행합니다.
print(df.apply(np.sum))
#col1 12
#col2 15
#col3 18
#dtype: int64
axis에 따른 차이
axis가 0인경우 Index(행)에 대해 연산을 수행하고, 1인경우는 columns(열)에 대해 연산을 수행합니다.
print(df.apply(np.prod,axis=0))
#col1 28
#col2 80
#col3 162
#dtype: int64
print(df.apply(np.prod,axis=1))
#row1 6
#row2 120
#row3 504
#dtype: int64
result_type에 따른 차이
먼저 lamba를 사용하여 기존 DataFrame에 [1,2,3]객체를 apply해보겠습니다.
print(df.apply(lambda x : [1,2,3]))
# col1 col2 col3
#row1 1 1 1
#row2 2 2 2
#row3 3 3 3
result_type = 'expand'인 경우
func를 기준으로 확장하여 columns를 지정하게 되는것을 확인할 수 있습니다.
print(df.apply(lambda x : [1,2,3], axis=1,result_type='expand'))
# 0 1 2
#row1 1 2 3
#row2 1 2 3
#row3 1 2 3
result_type = 'broadcast'인 경우
func를 기준으로 확장하되, columns는 기존 DataFrame의 것을 사용하는것을 확인할 수 있습니다.
print(df.apply(lambda x : [1,2,3], axis=1,result_type='broadcast'))
# col1 col2 col3
#row1 1 2 3
#row2 1 2 3
#row3 1 2 3
result_type = 'reduce'인 경우
func를 기준으로 축소하여 columns없이 Series 객체로 반환하는것을 확인할 수 있습니다
print(df.apply(lambda x : [1,2,3], axis=1,result_type='reduce'))
#row1 [1, 2, 3]
#row2 [1, 2, 3]
#row3 [1, 2, 3]
#dtype: object
applymap 메서드는 객체의 각 요소에 함수를 적용하는 메서드입니다.
즉, apply메서드와는 다르게 DataFrame의 각 요소 하나하나에 함수를 적용하여 스칼라 값을 반환합니다.
df.apply(func, axis=0, raw=False, result_type=None, args=(), kwargs)
func : 단일 값을 반환하는 함수 입니다.
na_action : {None / 'ignore} NaN의 무시 여부입니다. 'ignore'이면 NaN을 함수로 전달하지 않습니다.
col = ['col1','col2','col3']
row = ['row1','row2','row3']
data = [[1,2,3],[4,5,6],[7,pd.NA,9]]
df = pd.DataFrame(data=data,index=row,columns=col)
print(df)
# col1 col2 col3
#row1 1 2 3
#row2 4 5 6
#row3 7 <NA> 9
applymap의 적용
함수 적용시 각 요소에 대해 함수의 연산이 되는것을 확인할 수 있습니다.
print(df.applymap(lambda x : x**2,na_action='ignore'))#제곱해준다 na는 무시하고
# col1 col2 col3
#row1 1 4 9
#row2 16 25 36
#row3 49 <NA> 81
pipe 메서드는 함수를 연속적으로 사용할 때 유용한 메서드입니다.
특히 함수가 인수를 사용할 때 pipe 메서드를 사용하면 보다 직관적으로 적용할 수 있습니다
df.pipe(func, args, kwargs)
func : 함수입니다.
arg : 함수의 인수입니다.
kwargs : dict 형태의 함수의 인수입니다.
객체 생성
org_data = pd.DataFrame({'info':['삼성전자/3/70000','SK하이닉스/2/100000']})
print(org_data)
>>
info
0 삼성전자/3/70000
1 SK하이닉스/2/100000
그리고 함수 두개를 만들어보겠습니다.
code_name(data) 는 (종목명/수량/가격)형태인 문자열 data를 입력받아서 각각 으로 분리하고 수량과 가격의 dtype을 int로 변경하는 함수 입니다.
org_data = pd.DataFrame({'info':['삼성전자/3/70000','SK하이닉스/2/100000']})
def code_name(data):
result=pd.DataFrame(columns=['name','count','price']) #result 에다가 '삼성전자/3/70000','SK하이닉스/2/100000'넣는다
df = pd.DataFrame(list(data['info'].str.split('/'))) # '/ ' 로 구분하여 문자열을 나누어 리스트에 넣음
result['name'] = df[0] # 여기엔 첫번째 값인 이름이 입력 (삼성전자)
result['count']= df[1] # 여기엔 두번째 값인 수량이 입력(3)
result['price']= df[2] # 여기엔 세번째 값인 가격이 입력(70000)
result = result.astype({'count':int,'price':int}) # count와 price를 int로 바꿈(기존str)
return result
print(code_name(org_data))
>>
name count price
0 삼성전자 3 70000
1 SK하이닉스 2 100000
value_cal(data,unit=' ')은 가격과 수량을 곱한다음에 단위로 unit arg를 붙이는 함수입니다.
def value_cal(data,unit=''):
result = pd.DataFrame(columns=['name','value'])
result['name'] =data['name'] # 이름은 기존거를 가져옴
result['value']=data['count']*data['price'] # value는 count * price를 입력함
result = result.astype({'value':str}) # value를 str로 변경(단위를 붙이기 위함)
result['value']=result['value']+unit # 단위를 붙임
return(result)
input=code_name(org_data)
print(value_cal(input,'원'))
>>
name value
0 삼성전자 210000원
1 SK하이닉스 200000원
pipe 메서드를 사용하지 않는경우
만약 pipe메서드를 사용하지 않는다면 아래와같이 함수를 사용해야 합니다.
print(value_cal(code_name(org_data),'원'))
name value
0 삼성전자 210000원
1 SK하이닉스 200000원
pipe메서드를 사용한다면 아래와같이 직관적으로 나타낼 수 있다.
print(org_data.pipe(code_name).pipe(value_cal,'원')) #이름과 원을 이어서 출력한다
>>
name value
0 삼성전자 210000원
1 SK하이닉스 200000원
agg메서드는 apply와 비슷하게 함수를 적용하는 메서드이지만,
여러개의 함수를 동시에 적용할 수 있다는 장점이 있습니다.
그리고
__name__
를통해 사용자정의 함수명을 따로 설정할경우 그 이름을 사용한다는 점을 활용하여
함수를 사용한 DataFrame을 보다 깔끔하게 정리하는데도 용이하게 쓸 수 있습니다.
기본 사용법
df.agg(func=None, axis=0, args, kwargs)
func
: 함수입니다.
axis
:{0 : index(row) / 1 : columns} 축입니다 0은 행, 1은 열 입니다.
arg
: 함수의 인수 입니다..
kwargs
: dict 형태의 함수의 인수입니다.
객체생성
df = pd.DataFrame([[1,4,7],[2,5,8],[3,6,9]])
print(df)
>>
0 1 2
0 1 4 7
1 2 5 8
2 3 6 9
입력되는 함수의 형태에 따라
입력함수로는 먼저 np.함수 형태나 그냥 문자열 형태로의 입력이 가능합니다.np함수의 경우
(agg() 함수는 Pandas에서 사용되는 함수로, DataFrame이나 Series에 다양한 집계(aggregation) 함수를 적용할 수 있도록 도와줍니다. agg() 함수는 여러 개의 집계 함수나 사용자 정의 함수를 한 번에 적용할 수 있어서 매우 유용합니다.)
ex1 = df.agg(np.prod)
print(ex1)
>>
0 6
1 120
2 504
dtype: int64
문자열일 경우
ex2 = df.agg('prod')
print(ex2)
>>
0 6
1 120
2 504
dtype: int64
lambda함수나 사용자 정의 함수를사용할 수도 있습니다.
lambda함수를 사용할 경우 열 명칭은 <lambda>가 됩니다.
ex3 = df.agg([lambda x : min(x) * max(x)])#최소값가 최대값을 곱해서 출력해준다
print(ex3)
>>
0 1 2
<lambda> 3 24 63
사용자정의 함수를 사용하게되면 기본적으로 함수명 열 이름으로 설정이 됩니다.
def func_sub(input):
return max(input)-min(input)
ex4 = df.agg([func_sub,'sum'])
print(ex4)
>>
0 1 2
func_sub 2 2 2
sum 6 15 24
만약 함수명을 __name__메서드를 통해 따로 설정해주면 그 이름이 쓰입니다
def func_sub(input):
return max(input)-min(input)
func_sub.__name__='내함수'
ex5 = df.agg([func_sub,'sum'])
print(ex5)
>>
0 1 2
내함수 2 2 2
sum 6 15 24
여러 함수를 동시에 적용하는 경우
list나 dict형태로 func값을 입력하는 경우 여러 함수를 동시에 적용할 수 있습니다.
list로 입력하는 경우
ex6 = df.agg(['min','max','sum','prod'])
print(ex6)
>>
0 1 2
min 1 4 7
max 3 6 9
sum 6 15 24
prod 6 120 504
dict를 이용하는 경우 순서를 변경하는것도 가능합니다.
ex7 = df.agg({2:'sum',0:'max',1:'min'})
print(ex7)
>>
2 24
0 3
1 4
dtype: int64
transform메서드는 agg와 비슷하게 함수를 적용하는 메서드이지만,
단일 요소별로 함수를 동시에 적용할 수 있다는 장점이 있습니다. 마치 apply와 applymap의 차이와 비슷합니다.
df.transform(func, axis=0, args, kwargs)
func
: 함수입니다.
axis
:{0 : index(row) / 1 : columns} 축입니다 0은 행, 1은 열 입니다.
arg
: 함수의 인수 입니다.
kwargs
: dict 형태의 함수의 인수입니다.
col = ['col1','col2','col3']
row = ['row1','row2','row3']
df = pd.DataFrame(data=[[10,40,70],[20,50,80],[30,60,90]],index=row,columns=col)
print(df)
>>
col1 col2 col3
row1 10 40 70
row2 20 50 80
row3 30 60 90
입력되는 함수의 형태에 따라
입력함수로는 먼저 np.함수 형태나 그냥 문자열 형태로의 입력이 가능합니다.np함수의 경우
ex1 = df.transform(np.sqrt)#제곱근 구하기
print(ex1)
>>
col1 col2 col3
row1 3.162278 6.324555 8.366600
row2 4.472136 7.071068 8.944272
row3 5.477226 7.745967 9.486833
문자열일 경우
ex2 = df.transform('sqrt')
print(ex2)
>>
col1 col2 col3
row1 3.162278 6.324555 8.366600
row2 4.472136 7.071068 8.944272
row3 5.477226 7.745967 9.486833
lambda함수나 사용자 정의 함수를사용할 수도 있습니다
agg와 다르게 기존 레이블이 표시됩니다.
ex3 = df.transform(lambda x : np.sqrt(x))#transform은 agg와 다르게 기존 레이블이 표시가된다
print(ex3)
>>
col1 col2 col3
row1 3.162278 6.324555 8.366600
row2 4.472136 7.071068 8.944272
row3 5.477226 7.745967 9.486833
여러 함수를 동시에 적용하는 경우
list나 dict형태로 func값을 입력하는 경우 여러 함수를 동시에 적용할 수 있습니다.
list로 입력하는 경우 마치 multi index처럼 multi columns가 생성됩니다.
ex4 = df.transform(['exp','sqrt'])#지수와 제곱근 모두를 출력한다
print(ex4)
>>
col1 col2 col3
exp sqrt exp sqrt exp sqrt
row1 2.202647e+04 3.162278 2.353853e+17 6.324555 2.515439e+30 8.366600
row2 4.851652e+08 4.472136 5.184706e+21 7.071068 5.540622e+34 8.944272
row3 1.068647e+13 5.477226 1.142007e+26 7.745967 1.220403e+39 9.486833
dict를 이용하는 경우 순서를 변경하는것도 가능합니다.
ex5 = df.transform({'col2':'exp','col1':'sqrt'})#따로따로 적용가능
print(ex5)
>>
col2 col1
row1 2.353853e+17 3.162278
row2 5.184706e+21 4.472136
row3 1.142007e+26 5.477226
df.eval(expr, inplace=False, kwargs)
expr
: 문자열 형태의 계산식입니다.
inplace
: {True / False} 계산된 값이 원본을 변경할지의 여부입니다. 기본적으로 원본은 변경되지 않습니다.
객체생성
data = [[1,2,3],[4,5,6],[7,8,9]]
col = ['col1','col2','col3']
row = ['row1','row2','row3']
df = pd.DataFrame(data = data, index = row, columns= col)
print(df)
>>
col1 col2 col3
row1 1 2 3
row2 4 5 6
row3 7 8 9
col1*col2-col3의 값을 갖는 col4를 만들어보겠습니다. 'col4'='col1'+'col2'-'col3'를 문자열 그대로 사용합니다.
계산이 적용된 col4열이 생성된 것을 확인할 수 있습니다.
print(df.eval('col4=col1*col2-col3'))#col의 4는 col1*col2-col3을 한 값을 넣어서 생성한다
>>
col1 col2 col3 col4
row1 1 2 3 -1
row2 4 5 6 14
row3 7 8 9 47
하지만 inplace인수가 기본값인 False이기 때문에 원본은 변경되지 않은것을 알 수 있습니다.(기본은 false 값으로 true값을 해주기 전까지는 바뀌지 않는다)
print(df)
>>
col1 col2 col3
row1 1 2 3
row2 4 5 6
row3 7 8 9
ㅈ
inplace = True인 경우
Inplace = True
로 할 경우 원본이 변경되는것을 확인할 수 있습니다.
※ inplace = True로 할경우 사본이 생성되지 않기 때문에 print할 경우 None이 출력됩니다.
print(df.eval('col4=col1*col2-col3',inplace=True))
>>
None
print(df)
>>
col1 col2 col3 col4
row1 1 2 3 -1
row2 4 5 6 14
row3 7 8 9 47
값 가져오기 : result = df.at['행', '열']
값 설정하기 : df.at['행', '열'] = value
df = pd.DataFrame([[1,2], [3,4]], index=['row1', 'row2'], columns=['col1', 'col2'])
print(df)
>>
col1 col2
row1 1 2
row2 3 4
값 가져오기
행, 열 값을 인수로 입력하여 변수에 할당함으로써 값을 가져올 수 있습니다.
result = df.at['row1', 'col2']#첫번쨰 행에서 두번째 열의 수를 출력한다
print(result)
>> 2
값 설정하기
행, 열 값을 인수로 지정 후 값을 할당하여 값을 설정할 수 있습니다.
df.at['row2', 'col1'] = '변경'#행2번째 열1번째 데이터를 '변경'이라는 문자열로 교체함
print(df)]ㅂ
>>
col1 col2
row1 1 2
row2 변경 4
기타
loc 메서드를 이용해 Series로 추출한 뒤 at메서드를 이용해 스칼라값을 얻는 방식으로 활용이 가능합니다.
df.loc['row2'].at['col2']
>> 4
행/열 설정에 따라 자유로운 인덱싱이 가능합니다.
loc는 bool 배열과 함께 사용이 가능합니다.
df = pd.DataFrame([[1,2,3], [4,5,6], [7,8,9]], index=['row1', 'row2', 'row3'], columns=['col1', 'col2', 'col3'])
print(df)
>>
col1 col2 col3
row1 1 2 3
row2 4 5 6
row3 7 8 9
단일 레이블을 지정할경우 Series 형태로 반환됩니다.
result = df.loc['row1']
print(result)
>>
col1 1
col2 2
col3 3
Name: row1, dtype: int64
레이블로 구성된 리스트. [ [ ] ]를 사용하면 DataFrame형태로 반환됩니다.
result = df.loc[ ['row1','row'3] ]
print(result)
>>
col1 col2 col3
row1 1 2 3
row3 7 8 9
행과 열을 설정하여 단일 레이블의 값을 입력가능합니다.
result = df.loc['row2', 'col2']
print(result)
>> 5
슬라이스를 이용하여 인덱싱을 할 수 있습니다.
result = df.loc['row1' : 'row3', 'col2']
print(result)
>>
col2
row1 1
row2 4
row3 7
Name : col2, dtype: int64
bool로 구성된 list를 이용하여 인덱싱을 할 수 있습니다.
bool = [False, True, False] # row2에 대응되는 값만 True
result = df.loc[bool]
col1 col2 col3
row2 4 5 6
bool로 구성된 Series를 반환하는 조건문의 사용도 가능합니다. 아래의 경우 col3열에 대해서 5보다 큰 경우인 row2, row3행만 반환됩니다.
result = df.loc[ df['col3'] > 5 ]
print(result)
>>
col1 col2 col3
row2 4 5 6
row3 7 8 9
여기에 해당조건을 만족하는 특정 열을 반환할 수도 있습니다. 아래의 경우 col3에서 5보다 큰 값을 만족하는 행에 대해서 col2의 값만 반환합니다.
result = df.loc[ df['col3'] > 5, ['col2'] ]
print(result)
>>
col2
row2 5
row3 8
람다함수를 이용하여 인덱싱이 가능합니다. 아래의 경우 col2의 값중 5인 값을 만족하는 행을 반환합니다.
result = df.loc[lambda df : df['col2'] == 5]
print(result)
>>
col1 col2 col3
row2 4 5 6
값 설정하기
기본적으로 조건을 만족하는 모든 항목의 값이 변경됩니다.
레이블을 지정하여 값 설정하기.
df.loc[ ['row1', 'row3'], ['col3'] ] = 'A'
print(df)
>>
col1 col2 col3
row1 1 2 A
row2 4 5 6
row3 7 8 A
하나의 레이블만 지정할 경우 해당 행/열 전체의 값 설정이 가능합니다.
df.loc[ ['row1'] ] = 'A' # 행을 변경할 경우
print(df)
>>
col1 col2 col3
row1 A A A
row2 4 5 6
row3 7 8 9
df.loc[ : , ['col3'] ] = 'B' # 열을 변경할 경우 행을 전체선택 ( : ) 해줍니다.
print(df)
>>
col1 col2 col3
row1 1 2 B
row2 4 5 B
row3 7 8 B
조건을 설정하여 만족하는 값의 변경이 가능합니다.
아래의 경우 col2에서 3보다 큰 열은 row2, row3이기 때문에 해당 열의 값이전부 변경되었습니다.
df.loc[df['col2'] > 3] = 'A'#열에서 값이 3보다 큰 행을 찾는다,df.loc[...]: 해당 조건을 만족하는 행을 선택합니다.
col1 col2 col3
>>
row1 1 2 3
row2 A A A
row3 A A A
값 가져오기 : result = df.iat['행', '열']
값 설정하기 : df.iat['행', '열'] = value
df = pd.DataFrame([1,2,3], [4,5,6], [7,8,9]], index=['row1', 'row2', 'row3'], columns=['col1', 'col2', 'col3'])
print(df)
>>
col1 col2 col3
row1 1 2 3
row2 4 5 6
row3 7 8 9
값 가져오기
정수기반 조회 메서드이기 때문에, 행/열 쌍을 정수로 입력해야합니다.
아래의 경우 [rows=1,columns=2] 를 출력하는 것으로, 0부터 시작하기 때문에 [row2, col3]의 값인 6을 출력하게 됩니다.
result = df.iat[1,2]#정수로 입력하기 때문에 행2열3값을 가리킵니다
print(result)
>> 6
값 설정하기
마찬가지로 정수값을 지정하여 해당 행/열의 값을 바꿀 수 있습니다.
df.iat[1,2] = 'A'
print(df)
>>
col1 col2 col3
row1 1 2 3
row2 4 5 A
row3 7 8 9
head함수는 Dataframe 객체를 위에서부터 n열 반환하는 함수입니다.
기본값은 5입니다.
먼저, head 함수의 사용을 위해 np.random함수로 10x10 난수 DataFrame를 만들어 보겠습니다.
먼저, head 함수의 사용을 위해 np.random함수로 10x10 난수 DataFrame를 만들어 보겠습니다.
data = np.random.randint(10,size=(10,10))
df = pd.DataFrame(data=data)
print(df)
>>
0 1 2 3 4 5 6 7 8 9
0 6 6 7 4 8 5 2 5 9 8
1 4 5 5 8 4 1 7 2 7 4
2 7 0 4 6 2 2 5 9 4 0
3 6 5 6 4 9 6 9 6 1 7
4 8 8 1 2 4 2 9 3 0 9
5 3 5 8 6 5 6 0 5 2 0
6 6 0 4 2 5 6 3 7 5 2
7 3 7 5 1 9 6 1 0 7 8
8 5 4 3 7 0 2 9 0 3 9
9 9 7 1 0 0 8 9 9 8 6
n=양수 n이 0보다 크면 위에서부터 n까지 열을 반환합니다.
print(df.head(3))
>>
0 1 2 3 4 5 6 7 8 9
0 5 5 9 5 9 0 3 3 7 8
1 5 4 4 4 6 4 0 3 2 1
2 7 6 2 6 9 6 3 2 6 8
n=음수 n이 0보다 작으면 DataFrame의 끝에서부터 n개열을 제외하고 반환합니다.
print(df.head(-3))
>>
0 1 2 3 4 5 6 7 8 9
0 6 5 3 4 5 9 8 6 2 8
1 6 4 6 7 6 2 3 7 0 4
2 6 0 7 5 3 9 6 4 4 8
3 7 7 6 9 8 7 8 2 4 5
4 2 4 1 9 7 2 5 3 3 6
5 6 9 7 5 2 1 3 5 3 0
6 3 2 7 0 0 3 2 6 3 5
index_tuples = [('row1', 'val1'), ('row1', 'val2'), ('row2', 'val1'), ('row2', 'val2'), ('row2', 'val3'), ('row3', 'val2'),('row3', 'val3')]
values = [ [1,2,3], [4,5,6], [7,8,9], [10,11,12], [13,14,15], [16,17,18], [19,20,21]]
index = pd.MultiIndex.from_tuples(index_tuples) # 인덱스 설정
df = pd.DataFrame(values, columns=['col1', 'col2', 'col3'], index = index)
print(df)
>>
col1 col2 col3
row1 val1 1 2 3
val2 4 5 6
row2 val1 7 8 9
val2 10 11 12
val3 13 14 15
row3 val2 16 17 18
val3 19 20 21
하나의 행을 지정할 경우 단일 index로 반환된다.
result = df.loc['row2']
print(result)
>>
col1 col2 col3
val1 7 8 9
val2 10 11 12
val3 13 14 15
multi index에서 특정 index를 튜플로 지정할 경우 Series로 반환됩니다.
또한, 아래의 경우에서 튜플이 아니라 단일 행/열 레이블 형태로 입력하여도
같은 결과가 도출됩니다. (예 : result = df.loc[ ' row2', 'val2' ] )
result = df.loc[('row2','val2')]
print(result)
>>
col1 10
col2 11
col3 12
Name: (row2, val2), dtype: int64
만약 DataFrame 형태로 반환하고 싶다면 [ [ ] ] 형태로 인덱싱하면됩니다.
result = df.loc[[('row2','val2')]]
print(result)
>>
col1 col2 col3
row2 val2 10 11 12
여기에 열 값까지 설정해줄 경우 해당 값을 반환할 수 있습니다.
result = df.loc[('row2','val2'), 'col3']
print(result)
>> 12
Multi Index의 튜플을 통해 슬라이스하여 인덱싱이 가능합니다.
result = df.loc[('row1','val2') : ('row3','val2')] # row1의 val2부터 row3의 val2까지
print(result)
>>
col1 col2 col3
row1 val2 4 5 6
row2 val1 7 8 9
val2 10 11 12
val3 13 14 15
row3 val2 16 17 18