AI/Pandas

04. 산술 연산(연산 메소드)

Python version : 3.7.10

Pandas version : 1.1.5

시리즈 연산

1. 시리즈와 숫자

만약 시리즈 객체에 어떤 숫자를 더하면 시리즈의 개별 원소에 각각 숫자를 더하고 계산한 결과를 시리즈 객체로 반환합니다.

student1 = pd.Series({
    '국어' : 100,
    '영어' : 80,
    '수학' : 90
    })

percentage = student1/200
print(percentage)

시리즈와 숫자 간의 사칙연산은 굉장히 간단하고 직관적인 방법으로 연산이 가능합니다.

type()메소드를 활용하여 print(type(percentage)) 연산이 끝난 값도 시리즈 객체임을 알 수 있습니다.

2. 시리즈와 시리즈(연산 메소드 add(), sub(), mul(), div())

시리즈 끼리의 연산도 직관적인 방법으로 가능합니다.

student1 = pd.Series({
    '국어' : 100,
    '영어' : 80,
    '수학' : 85
    })
student2 = pd.Series({
    '수학' : 80,
    '국어' : 90,
    '영어' : 95
    })

addition = student1 + student2
subtraction = student1 - student2
multiplication = student1 * student2
division = student1 / student2

result = pd.DataFrame([addition, subtraction, multiplication, division], index=['덧셈', '뺄셈', '곱셈', '나눗셈'])
print(result)

위 코드는 두 시리즈로 사칙 연산을 실행하고 그 결과를 데이터프레임에 담아서 출력하는 코드입니다.
두 시리즈 객체의 열 순서가 다르지만 판다스는 자동으로 이를 맞춰서 계산해줍니다.

하지만 시리즈 끼리의 연산을 할 때 두 시리즈의 원소 개수가 다르거나,
크기가 같아도 인덱스 값이 다를 경우 정상적으로 연산이 불가능합니다.
이럴 때 결과 값이 NaN으로 처리됩니다.
다음 코드에서 확인할 수 있습니다.

import numpy as np

student1 = pd.Series({
    '국어' : np.nan, #numpy로 NaN 값을 표현
    '영어' : 80, 
    '수학' : 90
    })
student2 = pd.Series({
    '수학' : 80,
    '국어' : 90
})

addition = student1 + student2
subtraction = student1 - student2
multiplication = student1 * student2
division = student1 / student2

result = pd.DataFrame([addition, subtraction, multiplication, division], index=['덧셈', '뺄셈', '곱셈', '나눗셈']) 
print(result)

위 코드에서는 numpynp.nan을 사용해서 NaN을 표현했습니다.
두 시리즈는 모두 국어 인덱스를 가지고 있습니다.
하지만 student1 객체는 국어 점수가 NaN으로 존재하지 않기 때문에
최종 결과에서 NaN이 처리됩니다.

student2 객체는 영어 인덱스를 가지고 있지 않습니다.
따라서 결과의 영어 부분은 모두 NaN으로 처리됩니다.

NaN은 데이터를 분석하는데 있어 큰 오류를 만들 수 있습니다.
따라서 NaN이 되지 않도록 처리해줄 필요가 있고
연산 메소드를 사용해서 가능합니다.

student1 = pd.Series({
    '국어' : np.nan, #numpy로 NaN 값을 표현
    '영어' : 80, 
    '수학' : 90
    })
student2 = pd.Series({
    '수학' : 80,
    '국어' : 90
})

sr_add = student1.add(student2, fill_value=0)
sr_sub = student1.sub(student2, fill_value=0)
sr_mul = student1.mul(student2, fill_value=0)
sr_div = student1.div(student2, fill_value=0)

result = pd.DataFrame([sr_add, sr_sub, sr_mul, sr_div], index=['덧셈', '뺄셈', '곱셈', '나눗셈']) 
print(result)

add(), sub()등 연산 메소드에 옵션 fill_value0을 대입하게 되면
student1의 국어에 NaN0을 채워주고
student1엔 있지만 student2엔 없는 영어열을 모두 0으로 채워줍니다.

데이터 프레임 연산

데이터 프레임은 여러 시리즈가 모인 것이므로 시리즈 연산을 확장하는 개념으로 이해하는 것이 좋습니다.
행/열 인덱스를 기준으로 정렬하고 일대일 대응되는 원소끼리 연산을 처리합니다.

1. 데이터 프레임과 숫자

데이터 프레임에 어떤 숫자로 사칙 연산을 하고 싶을 때 사용합니다. 모든 원소에 연산이 적용됩니다.
이때 계산을 실행한 결과는 새로운 데이터 프레임 객체로 반환됩니다.

다음 코드는 데이터 프레임에 10을 더하는 과정입니다.
seaborn 라이브러리에서 제공하는 데이터 셋 중 타이타닉을 사용할 것입니다.
이 데이터 셋에는 타이타닉호 탑승자에 대한 인적사항과 구조 여부 등을 정리한 자료입니다.

import seaborn as sns

titanic = sns.load_dataset('titanic')
df = titanic.loc[ : , ['age', 'fare']]
print(df.head()) # head() 메소드는 첫 5행만 표시하는 메소드이다.
print('\n')
addition = df + 10
print(addition.head())

낯선 코드들이 많은데 천천히 파해쳐봅시다.
sns.load_dataset('titanic') seaborn 라이브러리의 load_dataset() 메소드를 사용하여 'titanic'데이터 셋을 가져와서 데이터 프레임 객체로 반환합니다.
df = titanic.loc[ : , ['age', 'fare']] 코드는 titanic 데이터 프레임에서 agefare 열의 데이터만 추출한 데이터 프레임 객체를 df에 저장합니다.
df.head()에서 쓰인 head()메소드는 데이터 프레임의 처음 5행만 데이터 프레임 객체로 만들어 반환하는 객체입니다.

이제 원래 목표였던 데이터 프레임과 숫자의 사칙연산에 대한 코드를 살펴봅시다.
addition = df + 10에서 df 객체에 10을 더하는 것으로 모든 원소에 10이 더해집니다.
print(addition.head())으로 addition 객체의 첫 5행만 확인하는 것으로 연산이 잘 실행되었음을 확인할 수 있습니다.

2. 데이터 프레임과 데이터 프레임

데이터 프레임 끼리의 연산은 각 객체의 같은 행, 같은 열에 있는 원소끼리 연산됩니다. 이처럼 동일한 위치의 원소끼리 연산한 결과 값을 원래 위치에 다시 입력하여 새로운 데이터 프레임 객체를 만듭니다.
만약 어느 한쪽 객체에 원소가 존재하지 않거나 NaN이면 결과 값도 NaN이 됩니다.

다음 코드는 df10을 더해서 addition 객체를 만들고 addition 객체에서 df객체를 빼는 과정입니다.

titanic = sns.load_dataset('titanic')
df = titanic.loc[ : , ['age', 'fare']]
print(df.tail()) 
print('\n')
addition = df + 10
print(addition.tail())
print('\n')

#데이터프레임끼리 연산하기
subtraction = addition - df
print(subtraction.tail())

tail() 메소드는 데이터 프레임의 마지막 5행만 데이터 프레임 객체로 만들어 반환하는 객체입니다.
subtraction = addition - df에서 df 객체보다 모든 원소가 10만큼 큰 addition 객체에서 df객체를 뺍니다.
따라서 모든 결과는 10이 됩니다.
하지만 889번째 행에서(행 인덱스 888) NaN이 출력되는데 원본 데이터가 NaN이기 때문입니다.

Reference

도서 [파이썬 머신러닝 판다스 데이터 분석]을 공부하며 작성했습니다.