pandas apply 함수와 lambda 설명

 

데이터프레임을 조작하다보면 내가 정의해놓은 함수에 따라서 전체 데이터프레임이나 특정한 column의 값들이 일괄적으로 변경하기를 원할 수 있습니다.

이럴 경우에 어떤 pandas 메소드를 활용하여 실질적으로 구현해볼지 알아봅시다.

 


 

pandas에서는 특정 행 혹은 전체 데이터프레임에 함수를 적용할 수 있습니다.

예를 들어 def (x): 처럼 함수로 나타낸 코드의 return 값을 모든 데이터프레임에 적용하고 싶은겁니다.

그렇다면 우리는 pandas 의 apply 함수를 써서 적용할 수 있습니다.

 

apply 함수 적용! 코드를 보면서 이해해봅시다

 

numpy와 pandas를 불러온 뒤,

간략한 테스트용 데이터프레임을 생성합니다.

import numpy as np
import pandas as pd

df = pd.DataFrame([[4, 9], [1, 4], [5, 6]], columns=['A', 'B'])

데이터프레임 생성


데이터프레임 생성이 궁금하다면 아래의 링크를 참고해보세요.

 

파이썬 판다스 데이터프레임 생성 - 비전공자도 이해하는 설명, python pandas DataFrame and pip list dict n

판다스 데이터프레임 쉽게 생성하기 비전공자 입장에서 판다스 데이터프레임을 생성하는 것조차 이해가 잘 되지 않아요. 저 같은 경우엔 단순히 코딩만 따라치는게 전부였습니다. 저는 조금 쉽

koreadatascientist.tistory.com


 

우리가 원하는 것은 아래의 두가지입니다.

  1. A컬럼의 값에 내가 정해놓은 함수 return 값을 일괄적으로 적용하기 (컬럼 일괄 변경)
  2. df라는 데이터프레임 전체에 내가 정해놓은 함수 return 값을 일괄적으로 적용하기 (데이터프레임 일괄 변경)

 

위의 두가지는 파이썬의 기본적인 함수 정의 구문(def)을 통해서 함수를 정의 한 뒤에,

pandas의 apply를 활용하여 일괄 적용 할 수 있습니다.

뿐만 아니라, 간단한 함수는 lambda라는 방식을 활용하여 더욱 간편하게 쓸 수 있습니다.

 

우선 첫번째(컬럼 일괄변경)를 시행해봅시다.

우리는 특정 컬럼에 대해서 내가 정의한 함수를 적용하고 싶습니다.

그렇다면 우선 함수를 정의해야 겠지요?

모든 값에 1을 더하는 코드를 작성해봅시다

 

그래서 아래와 같은 함수(plus_one)을 정의하였습니다.

def plus_one(x):
    x += 1
    return x

 

해당 함수를 우리가 기존에 정의한 데이터프레임 중 A컬럼에 대해 적용하려면 아래와 같이 pandas의 apply 함수를 적용합니다.

코딩 표기방법은 "데이터프레임["컬럼"].apply(함수명)" 입니다.

df['A'].apply(plus_one)

물론 해당 결과는 시리즈로 나올 겁니다.

왜냐면 특정 컬럼만을 적용하였으니 데이터프레임이 아닌 시리즈로 나오는게 정상이기 때문입니다.

(시리즈와 컬럼은 둘 다 같은 개념이라고 보면 편합니다.)

그러므로 기존의 데이터프레임은 아직 바뀐게 아닙니다.

이것을 기존에 데이터프레임에 적용하고 싶으면 다시 객체를 해당 컬럼에 할당시키면 됩니다.

 

df['A'] = df['A'].apply(plus_one)

이제 기존의 데이터프레임과 바뀐 데이터프레임의 두 결과를 비교해봅시다

기존
바뀐 데이터프레임

A컬럼의 값이 1씩 증가된것을 알 수 있습니다.

 

자 여기서 조금 이 과정을 간편하게 하는 방법이 없을까요?

바로 apply(함수) 대신 apply(lambda)를 활용하는 방법입니다.

 

lambda에 대한 설명

lambda는 def와 같은 함수와 동일한 기능을 합니다.

다만 한 줄 내에 간편하게 사용할 수 있습니다.

기존에 def 함수이름(변수): return 결과값 처럼 길고 복잡하게 할 필요가 없습니다.

물론 복잡한 함수라면 lambda보다는 기존 함수를 권합니다.

단순한 사칙연산이라든가, 간단한 문자열 추출이라든지 이러한 것들에는 lambda를 적용한 apply 함수가 더욱 좋습니다.

 

표현방법은 "lambda 입력변수 : 리턴값" 으로 나타내면 됩니다.

방금 만들었던 plus_one 함수와 동일하게 lambda로 표현해보겠습니다.

 

데이터프레임을 초기화합니다.

df = pd.DataFrame([[4, 9], [1, 4], [5, 6]], columns=['A', 'B'])

 

파이썬 기본 함수기능과 동일한 lambda를 적용하려면 아래와 같이 입력합니다.

def로 만드는 것 대신 lambda로 만들려면 'lambda 입력값 : 결과값' 순으로 입력합니다.

이 자체가 어떤 기능을 할 순 없고 apply(lambda 입력값 : 결과값)으로 적용시켜줘야 합니다.

# lambda를 활용한 apply
df['A'].apply(lambda x : x+1)

# 기존 데이터프레임 변경
df['A'] = df['A'].apply(lambda x : x+1)

 


 

자 이제 데이터프레임 전체 값을 일괄적으로 바꾸는 두번째 방법을 생각해봅시다.

재밌는건, 컬럼의 값들을 바꿔주는 방법과 크게 다르지 않다는 겁니다.

위에서는 "데이터프레임['컬럼'].apply(함수)" 를 했다면, 이제는 단순히 "데이터프레임.apply(함수)" 를 하면 됩니다.

 

새로운 데이터프레임을 생성해봅시다.

df = pd.DataFrame([[2, 4, 9], [3, 1, 4], [9, 5, 6]], columns=['A', 'B', 'C'])

 

위에서 배웠던 방식대로 기존 def를 적용하는 방식과 lambda를 활용하는 방식을 모두 나타내보겠습니다.

# 정의한 함수를 apply에 적용하는 방식
df.apply(plus_one)

# lambda를 정의하여 apply에 적용하는 방식
df.apply(lambda x : x+1)

두 결과 모두 동일하게 나타났습니다.

주의해야 될 점은, 아직까지 기존에 있는 데이터프레임 자체가 변하지는 않았다는 겁니다.

기존 데이터프레임에 적용하고자 한다면, df에 다시 할당해줘야함을 잊어서는 안됩니다 !

 

apply를 적용한 다른 예시

여기에 추가로, A컬럼과 C컬럼에만 plus_one 함수를 적용하고 싶다면 어떻게 해야될까요?

그렇다면 두가지 방법을 생각해볼 수 있겠네요.

  1. A컬럼을 apply해서 할당하고, C컬럼을 apply해서 할당한다. 즉 Series(column)마다 할당하는 방식
  2. A컬럼과 C컬럼을 동시에 데이터프레임으로 만든 상태에서 전체를 할당한다. 즉 DataFrame을 적용하는 방식

어느방법이든 좋지만 저같은 경우에는 2번 방법이 조금 더 편할 것 같습니다.

df[['A', 'C']] = df[['A', 'C']].apply(plus_one)

기존 데이터프레임에서 A와 C컬럼에 대해서만 함수가 적용되었네요.

해당 방식은 lambda 함수를 적용해도 동일한 결과가 나옵니다.

 

다른 모듈의 함수와 apply를 적용하는 방법

재밌는거 하나 더 알려드리자면,

numpy 함수나 다른 라이브러리의 연산함수들도 모두 apply를 적용할 수 있다는 겁니다.

df = pd.DataFrame([[2, 4, 9], [3, 1, 4], [9, 5, 6]], columns=['A', 'B', 'C'])

df.apply(np.sqrt) # 모두 제곱근으로 바꾸기

np.sqrt는 numpy라는 라이브러리에서 제곱근으로 바꿔주는 함수입니다.

보통 np.sqrt(값) 형태로 씁니다. 

그런데 이것을 apply와 적용시키면 해당 데이터프레임 혹은 컬럼이 제곱근을 생성합니다.

 

이처럼 apply 함수는 내가 정의한 함수 외에도 기존 다른 라이브러리의 함수들도 적용시킬 수 있습니다.

 


 

apply 함수는 사용자의 방식에 따라 다양한 결과를 이끌어낼 수 있습니다.

하지만 큰 뼈대는 제가 오늘 알려드린 것들이라는 것을 잊지 마시기 바랍니다.

마지막으로 우리가 한 내용을 줄기로 분류해서 다시 정리해보겠습니다.

 

[핵심요약]

  • 함수를 적용하는 방법
    • apply를 적용
      • def로 정의한 함수를 적용
      • lambda로 정의한 함수를 적용
  • 시리즈, 데이터프레임 모두 동일하게 적용 가능하다
    • 다만, 해당 결과가 실제로 그 데이터프레임과 시리즈를 바꾼것이 아니므로 다시 할당시켜줘야 한다.
  • 다른 라이브러리의 함수를 적용시킬수도 있다.
    • ex. numpy의 sqrt 함수

 

데이터프레임과 시리즈에 일괄적인 함수 적용하기

apply와 lambda를 활용한 핵심적인 내용은 여기까지입니다.

감사합니다.

판다스 데이터프레임 쉽게 생성하기

 

비전공자 입장에서 판다스 데이터프레임을 생성하는 것조차 이해가 잘 되지 않아요.

저 같은 경우엔 단순히 코딩만 따라치는게 전부였습니다.

저는 조금 쉽게 설명하고자 했어요.또한  최대한 알맹이만을 요약해서 전달하고자 합니다.

이것을 보시고 나면 적어도 정해진 포맷을 이해하고 이러한 범위 내에서 스스로 데이터프레임을 만들 수 있을 겁니다.


기초개념

우선 데이터프레임을 생성하기 전에 생각해야 할 것이 3가지가 있습니다.

  • row index
  • column index ( = column name )
  • value

 

1. row index

row 인덱스는 가로줄로 나타난 row와 그들을 고유하게 지정할 index를 의미합니다.

0번은 철수이고, 1번은 영희, 2번은 맹구일때, 0, 1, 2 가 row index입니다.

row 인덱스는 주로 0으로부터 데이터 갯수까지로 나타냅니다. 각 숫자들은 중복이 없어야 합니다. (SQL의 PK를 의미한다고 보면 됩니다)

 

2. column index (=column name)

column 인덱스는 세로줄에 나타나는 속성들을 의미합니다.

'나이' '성별' '잔고' 등에 대한 다양한 사람들의 특징을 뽑을 수 있는 것들로 구분합니다.

 

 

3. value

마지막으로 value는 row와 column이 만나는 지점에 생기는 값을 의미합니다.

0번의 나이, 성별, 잔고 같은 경우에는 

0번은 철수이고 그는 5살, 남자, 잔고는 100원 이라는 식으로 만들 수 있습니다.

 

위의 3가지를 반드시 기억하고 데이터프레임을 만들어봅시다.

 

row인덱스는 별도의 인덱스 이름을 붙여주지 않습니다. 데이터프레임을 생성하면 row 인덱스는 자동으로 생성됩니다.

row 인덱스는 1씩 늘어나는 정수형으로 생성됩니다.

최대한 중복없는 많은 이름을 하기 위해선 정수형인 숫자 형태가 이상적이기 때문입니다.

주의할점은 0부터 시작된다는 점입니다. 1000개의 행이 있다면 0부터 999까지의 인덱스가 있음을 인지해야 합니다.

 

다음으로 컬럼들을 정의해봅시다.

컬럼을 정의한다는 것은 컬럼 인덱스의 이름들을 설정해준다는 것입니다. (ex.이름, 나이,성별, 잔고 등)

별도의 설정을 해주지 않는다면 컬럼 인덱스도 0으로부터 시작되는 숫자가 됩니다. 

그러나 컬럼이름은 row인덱스와 다르게 이름을 꼭 붙여줘야 합니다.

그렇지 않으면 값이 무슨 의미를 갖는지 알기가 어렵습니다.

 

예를 들어 0번째 row 인덱스와 0번째 column 인덱스를 갖는 값 13이 있습니다. 이게 무슨 의미일까요? 이렇듯 column name을 설정해주지 않는다면 문제가 됩니다.

그러면 row index를 0이 아니라 의미있게 설정해주는것은 어떨까요? 

아까 말했다시피 row index는 고유의 값으로 지정해야 되기 때문에 중복의 문제성이 있으면 안됩니다. 따라서 row는 중복되지 않도록 정수형으로 지정하고, column이름은 중복을 고려하지 않고 특징을 나타내는 이름으로 설정해주는게 좋습니다.

 

이제 파이썬 코드로 직접 작성해보죠.

파이썬 코드를 작성해서 데이터프레임을 만들 때에도 3가지 조건을 꼭 염두하고 만들어야 합니다.

row 인덱스는 정수형의 숫자로 생성이 된다고 하니 상관하지 않아도 됩니다. (1번째 조건)

column 이름을 설정해주어야 합니다.(2번째 조건)

생성할 데이터프레임의 컬럼 이름은 주로 리스트에 넣어줍니다. (순서 고려)

# 2번째 조건: 컬럼이름 만들기
new_column_name = ['나이', '성별', '잔고', '결혼여부', '출생지', '나이대']

 

데이터프레임 설정의 3가지 조건 중 2가지가 완료되었습니다.

남은 한가지는 value입니다.

 

value를 지정하는 방법은 크게 3가지로 전달할 수 있습니다.

  • pip의 list
  • pip의 dict
  • numpy의 list

 

pip의 리스트를 적용한 데이터프레임

리스트 안의 리스트를 통해서 row에 삽입한다고 생각하고 리스트 객체를 생성해줍니다. (가로로 생성한다 생각)

생성한 객체(리스트)를 pd.DataFrame()이라는 판다스의 함수에 input값으로 넣어주면 데이터프레임의 형태로 리턴합니다.

여기서 pd.DataFrame() 안에는 옵션 파라미터를 설정할 수 있습니다. columns= 라는 값에 위에서 설정해주었던 리스트 객체를 지정해줍니다. (new_column_name)

결론적으로 데이터프레임 생성을 위해서는 아래와 같은 형태를 입력해야 합니다.

pd.DataFrame(데이터값, columns=컬럼이름리스트)

이 데이터프레임은 자동으로 각각의 row 별로 unique한 정수형의 row index를 만들어줍니다.

# list
# array_to_df.tolist()

list_to_df = list([['20', '남자', '2000', '미혼', '서울', '사회초년생'],
                 ['50', '여자', '15000', '결혼', '서울', '은퇴예정자'],
                 ['48', '남자', '20000', '결혼', '서울', '은퇴예정자'],
                 ['32', '여자', '800', '미혼', '서울', '사회생활 1~10년차'],
                 ['28', '남자', '1200', '결혼', '서울', '사회생활 1~10년차'],
                 ['38', '여자', '3600', '결혼', '서울', '관리자 역할']])

# np.array(list_to_df)

pd.DataFrame(list_to_df, columns=new_column_name)

리스트로 만든 데이터프레임 결과

 

위와 같은 결과물은 다양한 방법으로 만들 수 있습니다.


pip dictionary를 적용한 데이터프레임

우선 dict형태는 key값과 value값이 있습니다.

데이터프레임을 만들때 dict를 넣어주면, key값은 column명이 되고, value값은 각각의 값이 됩니다.

여기서 value값들은 각 column에 대한 row들의 값이므로 리스트로 묶어서 적어줍니다.

# dict
dict_to_df = {'나이': [20, 50, 48, 32, 28, 38],
             '성별': ['남자', '여자', '남자', '여자', '남자', '여자'],
             '잔고': [2000, 15000, 20000, 800, 1200, 3600],
             '결혼여부': ['미혼', '결혼', '결혼', '미혼', '결혼', '결혼'],
             '출생지': ['서울', '서울', '서울', '서울', '서울', '서울'],
             '나이대': ['사회초년생', '은퇴예정자', '은퇴예정자', '사회생활 1~10년차', '사회생활 1~10년차', '관리자 역할']}

pd.DataFrame(dict_to_df)

pd.DataFrame({키1:[값1], 키2:[값2]})

 

value를 리스트로 적어도 되지만, row index마다 맞춰서 만들수도 있습니다. dict 안의 dict 구조로 적으면 됩니다.

첫번째 큰 dict의 키값은 column값이고, 그 안에 있는 dict의 키값은 row index값입니다.

# dict
dict_to_df = {'나이': {0: 20, 1: 50, 2: 48, 3: 32, 4: 28, 5: 38},
             '성별': {0: '남자', 1: '여자', 2: '남자', 3: '여자', 4: '남자', 5: '여자'},
             '잔고': {0: 2000, 1: 15000, 2: 20000, 3: 800, 4: 1200, 5: 3600},
             '결혼여부': {0: '미혼', 1: '결혼', 2: '결혼', 3: '미혼', 4: '결혼', 5: '결혼'},
             '출생지': {0: '서울', 1: '서울', 2: '서울', 3: '서울', 4: '서울', 5: '서울'},
             '나이대': {0: '사회초년생',
              1: '은퇴예정자',
              2: '은퇴예정자',
              3: '사회생활 1~10년차',
              4: '사회생활 1~10년차',
              5: '관리자 역할'}}

pd.DataFrame(dict_to_df)

pd.DataFrame({키1:{인덱스0:값1, 인덱스1:값2}, 키2:{인덱스0:값3, 인덱스1:값4}})


데이터프레임 생성은 numpy의 ndarray 구조로도 가능합니다.

numpy의 ndarray와 pip의 list는 비슷한 형태입니다. 다만 장단점이 있는데요.


이에 대해서는 이전 블로그에 게시해두었으니 부담없이 보고 오셔도 좋습니다.
 

파이썬 판다스 데이터프레임 예제 반드시 알아야 하는 함수들, python pandas Series and DataFrame # 1

pandas Series DataFrame 함수의 기본적인 모든 것 파이썬 판다스에서는 기본적으로 알아야 하는 개념들이 있습니다. 특히 2차원의 데이터 조작을 하기 위해서 pandas의 기본적인 함수는 숙지하고 있어

koreadatascientist.tistory.com


ndarray는 키값이 따로 없기 때문에, pip list에서 만들었던 것처럼 columns= 라는 파라미터로 컬럼값을 지정해줘야 합니다.

그 외에는 pip list로 만든 데이터프레임과 생성방법이 동일합니다.

# ndarray
array_to_df = np.array([[20, '남자', 2000, '미혼', '서울', '사회초년생'],
                       [50, '여자', 15000, '결혼', '서울', '은퇴예정자'],
                       [48, '남자', 20000, '결혼', '서울', '은퇴예정자'],
                       [32, '여자', 800, '미혼', '서울', '사회생활 1~10년차'],
                       [28, '남자', 1200, '결혼', '서울', '사회생활 1~10년차'],
                       [38, '여자', 3600, '결혼', '서울', '관리자 역할']])

pd.DataFrame(array_to_df, columns=new_column_name)

pd.DataFrame(ndarray형태, columns=컬럼이름리스트)


 

이번 시간은 집중적으로 #데이터프레임을생성 하는 방법에 대해서 다뤄봤습니다.

다음 시간에는 데이터프레임을 갖고 다시 list, dict, ndarray로 뽑아내는 방법을 알아보겠습니다.

추가로 데이터프레임에 관련된 핵심적인 함수들도 다뤄볼 것입니다.

이정도는 기본으로 알고 있어야 데이터분석하는데 요긴하게 적용할 수 있을 것입니다.

 

 

+ Recent posts