Pandas 기초 활용 - 1

haejun-kim·2020년 12월 30일
0

Pandas, DataFrame, Series 알아보기

Pandas

Python 라이브러리로써, 데이터를 수정하고 사용자의 목적에 맞게 가공하기 위해서 상당히 중요하게 사용되는 라이브러리이다.

Series

데이터프레임을 다루다보면 Series라는 단어를 보게 된다. 이 시리즈는 무엇일까? 시리즈란 DataFrame에서 column으로 표현되는 것을 시리즈라고 부른다. 즉, 데이터프레임은 시리즈로 구성되어 있다.

이를 확인하고 싶다면 type() 을 사용하여 확인할 수 있다.

type(data_frame.column)

내가 불러온 data_frame 중 아무 column이나 type을 확인 해 보면 pandas.core.series.Series로 타입이 확인되는 것을 볼 수 있다.

Series 만들기

그렇다면 Series를 어떻게 만들까?

바로 python의 list로 만들 수 있다.

s1 = pd.core.series.Series( [1,2,3] )

이렇게 간단하게 시리즈를 만들 수 있다.

csv를 통한 DataFrame 생성

import pandas as pd 
data_frame = pd.read_csv('data/friend_list.csv')

read_csv()를 활용하여 csv 형식의 file을 데이터프레임 상태로 불러올 수 있다.

그렇다면 엑셀을 놔두고 왜 pandas라는 라이브러리를 사용할까? 그 이유는 여러가지가 있을 수 있다.

  1. 데이터를 파이썬으로 불러와서 변형시키고 싶은데 그 과정을 엑셀에서는 할 수 없다.
  2. pandas는 numpy를 사용한다. 그렇기 때문에 숫자를 계산하고 다루는 것에 있어서 엑셀보다 pandas의 사용이 훨씬 빠르고 효율적이다.

등 많은 이유들이 있겠지만 궁극적으로는 파이썬을 통해 데이터를 계산하고, 나에게 필요한 형태의 데이터로 가공하기 위해서 사용한다.

DataFrame 기본 메소드

DataFrame에 가장 기초적으로 사용되는 메소드를 알아보자.

  • head

head()메소드를 사용하여 내가 불러온 csv file의 가장 위에서부터 다섯번째까지의 row를 불러온다.

data_frame.head()

head()()안에 숫자를 넣어주면 몇개의 row를 불러 올 지를 선택할 수 있다.

data_frame.head(5) # 상위 다섯개의 row만 불러온다.
  • tail

tail() 메소드는 head()와 반대로 하위 n개의 row를 불러온다.

data_frame.tail()

마찬가지로 ()안에 숫자를 넣어 하위 몇개의 row를 가져올 지 지정할 수 있다.

data_frame.tail(5) # 하위 5개의 row를 가져온다.

DataFrame 만들기

데이터 프레임은 시리즈로 구성되어 있다고 하였다. 그렇다면 시리즈를 사용하여 데이터 프레임을 만들어보자.

우선 두개의 시리즈를 만든다.

s1 = pd.core.series.Series( [1,2,3] )
s2 = pd.core.series.Series( ['one', 'two', 'three'] )

이렇게 생성한 시리즈를 데이터 프레임으로 만들어주면 된다.

pd.DataFrame(data = dict(num = s1, word = s2))

파일에서 데이터 불러오기

위에서 설명한 대로 기본 csv 파일은 다음의 명령어로 쉽게 불러올 수 있다.

pd.read_csv('경로/파일이름')

위 명령어는 csv 파일 뿐만 아니라 .txt 파일도 동일한 방식으로 불러올 수 있다.

csv 파일은 ,로 구분되어 있는 파일이다. 그렇다면 ,가 아니라 tab으로 구분되어 있는 파일은 어떻게 불러올 수 있을까?

위와 같은 방법으로 불러온다면 조금은 이상하게 불러와진 데이터를 확인할 수 있다. 이를 정상적으로 불러오기 위해서는 하나의 파라미터를 추가 해 주면 된다.

pd.read_csv('경로/파일이름', delimiter = '\t')

이렇게 delimiter 라는 파라미터에 \t 이라는 파라미터를 줌으로써 이 파일은 탭으로 구분되어져 있는 파일이라는 것을 알려줄 수 있다.

또 다른 파라미터는 어떤 것이 있을까? 주로 많이 사용되는 파라미터로는 header가 있다.

  • header : 어떤 데이터는 column의 header가 없이 데이터만 주어지는 경우가 있다. 이럴 경우 header에 대한 옵션을 따로 지정 해 주지 않으면 첫번째에 있는 row를 column으로 인식하여 원하는 결과가 나오지 않는다. 이럴 때 handling 할 수 있는 옵션이 header 옵션이다.
df = pd.read_csv('경로/파일이름', header = None)

이제 pandas가 header가 없는 것을 인지하였기 때문에 정상적으로 데이터가 출력 될 것이다. 다만 column의 이름이 인덱스로 지정된다.

column name을 지정 해 주고 싶다면?

df.columns = ['name', 'age', 'job']

위와 같이 column명을 list를 통해 지정시킬 수 있다. 하지만 두번의 작업이 번거롭다면 한번에 지정 해 줄 수 있다.

df = pd.read_csv('경로/파일이름', header = None, names = ['name', 'age', 'job'])

데이터프레임 생성하기

python 코드에서 데이터프레임을 생성하는 방법을 알아보도록 하자.

Dictionary를 사용하여 생성하기

파이썬의 Dictionary를 사용하여 하나의 데이터 프레임을 생성할 수 있다. 먼저 하나의 dictionary로 구성 된 list를 만들어보자.

friend_dict_list = [
	{'name' : 'John', 'age' : 25, 'job' : 'student'},
	{'name' : 'Nate', 'age' : 30, 'job' : 'teacher'}
]

이를 pandas를 이용하여 데이터프레임으로 만들어주면 된다.

df = pd.DataFrame(friend_dict_list)

분명 내가 만든 리스트 안의 딕셔너리는 name, age, job 순서대로 입력했으나 생성 된 데이터프레임을 보면 그 순서와 일치하지 않는다.

즉, 딕셔너리같은 경우 key값의 순서를 보장하지 않는다. 따라서 이와 같이 딕셔너리를 이용하여 데이터프레임을 생성한다면 column명을 다시 지정해주어야 한다는 단점이 있다.

df = df[['name', 'age', 'job']]

이렇게 단계적으로 두번의 일을 하는 것은 상당히 효율적이지 못하다. 이런 경우에는 파이썬에서 지원하는 OrderedDict를 사용하는 방법이 있다.

OrderedDict 를 사용할 경우 dict의 key값의 순서를 보장한다. 이를 사용하여 데이터프레임을 사용하면 다음과 같이 할 수 있다.

from collections import OrderedDict

friend_ordered_dict = OrderedDict(
	[
		('name', ['John', 'Nate']),
		('age', [25, 30]),
		('job', ['student', 'teacher'])
	]
)

이렇게 작성 해 준 후 데이터프레임을 만들어주자.

df = pd.DataFrame.from_dict(friend_ordered_dict)

List를 사용하여 생성하기

리스트를 사용하여 데이터프레임을 생성하는 방법도 있다.

friend_list = [
	['John', 20, 'student'],
	['Nate', 30, 'teacher'],
]
column_name = ['name', 'age', 'job']

데이터프레임을 생성 할 데이터와 column명을 지정 할 column_name list를 만들었으니 데이터프레임을 생성해주면 된다.

df = pd.DataFrame.from_records(friend_list, columns = column_name)

column_name이라는 list를 굳이 만들고싶지 않다면?

friend_list = [
	['name', ['John', 'Nate']],
	['age', [20, 30]],
	['job', ['student', 'teacher']]
]

df = pd.DataFrame.from_dict(dict(friend_list))

기존에는 from_items()라는 메소소드를 활용하여 리스트 형태를 바로 데이터프레임으로 생성할 수 있었지만 최신 버전에서는 from_items() 메소드를 지원하지 않는다. 따라서 list를 dict로 캐스팅 해 준 후 from_dict() 메소드를 사용하면 데이터프레임으로 생성할 수 있다.

데이터프레임 파일로 저장하기 (to_csv)

지금까지는 데이터프레임을 불러오고, 생성하는 방법을 알아보았다. 내가 생성 한 데이터프레임을 csv 파일로 저장할 순 없을까? 이번에는 이 방법에 대해서 알아보도록 하자.

다음과 같은 데이터프레임을 생성한다.

friends = [
	{'name' : 'Jone', 'age' : 20, 'job' : 'st'},
	{'name' : 'Jenny', 'age' : 30, 'job' : None},
	{'name' : 'Nate', 'age' : 30, 'job' : 'teacher'}]

df = pd.DataFrame(friends)
df = df[['name', 'age', 'job']]

이를 csv 파일로 저장 해 보자.

df.to_csv('저장 할 파일 이름.csv')

위 명령어를 입력하면 같은 폴더 내에 내가 저장 한 csv 파일이 저장된다.

사실 위 명령어에는 default 값으로 지정 되어 굳이 입력하지 않은 파라미터가 있다.

df.to_csv('파일 이름.csv', index = True, header = True)
  • index : row id(0, 1, 2)를 넣을것인가 말것인가?
  • header : header(column name)를 넣을것인가 말것인가?

위와 같이 원하는 방식으로 csv 파일을 만들 수 있다.

현재 생성 된 csv 파일을 보면 빈칸이 한개 있다. 이는 데이터 프레임을 만들 때, None값을 지정 해 주었기 때문인데, 이 None값은 사실 데이터를 핸들링하는 입장에서는 좋지 않다. 따라서 빈값을 빈값으로 두기보다는 다른 값으로 지정해서 넣어주는 것이 조금 더 권고되는 사항이다. 이는 다음의 파라미터를 추가시켜주면 된다.

df.to_csv('저장 할 파일 이름.csv', na_rep = '-')

이는 None값은 -로 바꿔서 저장해라. 라는 뜻이 된다.

위와 같은 방법으로 csv 파일을 만들고 기본적인 핸들링을 할 수 있다.

데이터프레임 행, 열 선택 및 필터하기

이번에는 데이터프레임에서 row와 column을 선택하고 필터링 하는 방법을 알아보자.

그러기 위해 하나의 데이터프레임을 임의로 생성한다.

friend_list = [
	['name', ['John', 'Jenny', 'Nate']],
	['age', [20, 30, 30]],
	['job', ['student', 'developer', 'teacher']]
]

df = pd.DataFrame.from_dict(dict(friend_list))

행과 열을 선택할 때 슬라이싱 기능을 활용하여 선택할 수 있다.

행 선택

행을 선택하여 출력하는 방법을 먼저 알아보자.

Slicing

df[1:3]

주의해야 할 점은, 슬라이싱은 원래의 값을 바꾸지 않는다. 나는 슬라이싱을 했는데, 다시 df로 데이터프레임을 불러오면 슬라이싱하지 않은 상태의 데이터프레임이 출력된다.

슬라이싱 한 결과를 원래의 df에 적용하고 싶다면 슬라이싱 한 것을 다시 df에 할당시켜주면 된다.

df = df[1:3]

loc

슬라이싱을 사용 할 경우 연속된 인덱스만 가져올 수 있었다. 따라서 어떤 인덱스를 선택적으로 가지고 오기에는 적합하지 않은 방법이다. 이렇듯 선택적으로 인덱스를 가지고 오고 싶다면 loc()를 사용하면 된다.

df.loc[[0, 2]]

위와 같은 명령어로 0과 2의 인덱스를 가진 Row만 선택되어 출력된다.

열 선택

by column condition

열을 선택 할 때는, 각 column의 조건에 따라 열을 선택하여 가지고 올 수 있다. 이를 Boolean Indexing이라고 한다. 이는 데이터 전처리 과정에서 굉장히 많이 사용되는 방법이다.

예를 들어, 위의 데이터프레임에서 나이가 25살 이상인 행만 가지고 오고 싶다면 다음과 같이 조건을 걸어주면 된다.

df[df.age > 25]

같은 결과를 내는 다른 방법은 query를 사용하는 방법이 있다.

df.query('age>25')

조금 더 복잡한 쿼리도 사용할 수 있다. 나이가 25살 이상이며, 이름이 Nate인 행만 불러오고싶다면 다음과 같이 작성할 수 있다.

df[(df.age > 25) & (df.name == 'Nate')]

위와 같이 & , | 등의 조건을 걸어서 원하는 데이터를 프로세싱 할 수 있다.

Filter Column

이번에는 column을 필터링해보자.

by index

인덱스로 필터링 하는 방법은 다음과 같다. row를 필터링 할 때 loc()을 사용했다면 열을 선택 할 때는 iloc을 사용 해 주면 된다.

df.iloc[:, 0:2]

처음 보면 위의 형태가 어색할 수 있다. , 앞 부분은 행을 의미한다. 행을 뜻하는 콤마의 앞부분에 어떠한 인덱스도 지정 해 주지 않았기 때문에 행에 대한 모든 인덱스를 가지고 오겠다는 의미이다. 즉, 행은 슬라이싱 하지 않을것이고 열은 0~1까지의 인덱스만 잘라서 보여줘. 라는 뜻이 되는 것이다.

물론 행도 함께 슬라이싱하여 가지고 올 수 있다.

df.iloc[0:2, 0:2]

numpy와 pandas에서는 위와 같은 형태가 굉장히 많이 사용되니 헷갈리지 않도록 하자.

by column name

column의 이름으로도 필터링이 가능하다. 현재 name, age, job 이라는 세 개의 column이 존재한다고 가정하자. 이 상황에서 job 이라는 column을 제외하고 name, age 두 column만 불러오고 싶다면 다음과 같이 불러올 수 있다.

df_filtered = df[['name', 'age']]

filter() 함수를 사용하여 효율적으로 필터링을 할 수도 있다.

df.filter(items = ['age', 'job'])

만약 column name이 a만 들어가는 column만 가지고 오고 싶다면?

df.filter(like = 'a', axis = 1)

column은 축이 1이기 때문에 위와 같이 작성 해 주면 column 이름에서 a가 들어간 column만 가지고 온다. 즉, name, age만 가지고 온다.

정규표현식을 사용해서 필터링도 가능하다. 정규식을 사용해서 column 이름의 마지막이 b로 끝나는 column. job column만을 가지고 온다면 다음과 같이 작성 할 수 있다.

df.filter(regex = 'b$', axis = 1)

데이터프레임 행, 열 삭제하기

데이터를 가공하다보면 행을 삭제한다던지 열을 삭제한다던지의 처리가 필요한 경우가 발생한다. 이를 대비하여 row와 column을 삭제하는 방법에 대해 알아보자.

행 삭제

by row name

drop() 메소드를 사용하여 삭제하고 싶은 인덱스의 이름을 적어주면 된다.

df.drop(['John', 'Nate']) # 1

위에서 슬라이싱 할 때 배운 것 처럼 이도 원래 기존의 데이터프레임에는 영향을 주지 않는다. 따라서 변수에 할당을 해 주어야 하지만 삭제할 때는 한가지 옵션으로 변수에 할당하는 절차를 없앨 수 있다.

이 기능을 해 주는 파라미터가 inplace 옵션이다.

해당 파라미터는 drop 한 데이터프레임을 따로 변수에 할당 할 필요 없이 바로 적용되도록 해 주는 파라미터이다.

df.drop(['John', 'Nate'], inplace = True) # 2

#1 같은 경우는 변수에 따로 할당을 해야 행을 삭제한 데이터프레임이 적용된다. 하지만 #2와 같이 inplace 옵션을 사용하면 변수에 할당하지 않고 바로 기존의 데이터프레임에 행 삭제가 적용된다.

by row index

위의 예는 행의 인덱스의 이름을 지정하여 삭제시켜주었다. 하지만 실제 데이터는 행의 인덱스에 이름이 지정되지 않고 숫자로 지정되어 있는 경우가 많다. 이럴 경우에는 다음과 같이 행을 삭제시켜주자.

df = df.drop(df.index[[0, 2]])

조건 걸어 삭제

데이터를 처리하는 과정에서는 지정해서 삭제 해 주기보다는 어떤 조건을 걸어 조건에 해당하는 행 또는 열을 삭제해야 하는 경우가 더 많다. 따라서 조건으로 삭제를 할 수 있는 방법을 알아보자.

df = df[df.age > 20]

열 삭제

열을 삭제하는 방법은 행을 삭제하는 방법에 축만 추가해주면 된다.

df = df.drop['age', axis = 1)

axis = 1 즉, column 중에서 age 인 것을 drop 시켜라. 라는 뜻이 된다. 이도 마찬가지로 inplace 옵션을 사용할 수 있다.

행, 열 생성 및 수정

열 생성 및 수정

df['salary'] = 0

데이터프레임에서 추가 할 열 이름을 지정 해 주고 어떤 값을 넣을것인지 값을 지정 해 주면 된다. 이를 조금 더 응용하면 다음과 같이 사용할 수 있다. 예를 들어서 직업이 학생인 경우에는 연봉이 없다. 하지만 학생이 아닌 경우에는 연봉이 있다. 따라서 학생이라면 salary column에 no 라는 값을, 학생이 아니라면 salary column에 yes라는 값을 넣도록 해주자. 이를 위해 numpy를 활용 하자.

df['salary'] = np.where(df['job'] != 'student', 'yes', 'no')

위 명령어는 데이터프레임의 job 이라는 열이 student가 아니면 yes 그게 아니라면 no 의 값을 넣을거고 그 값을 데이터프레임의 salary 라는 열의 값으로 넣어줘! 라는 뜻이 된다.

열의 값을 더할수도 있다. 이를 위해 다음과 같은 데이터프레임을 생성해보자.

friend_dict_list = [
	{'name' : 'Jone', 'midterm' : 95, 'final' : 85},
	{'name' : 'Jenny', 'midterm' : 85, 'final' : 80},
	{'name' : 'Nate', 'midterm' : 30, 'final' : 10}
]

df = pd.DataFrame(friend_dict_list, columns = ['name', 'midterm', 'final'])

이 중간고사와 기말고사 점수의 총 합을 구해보도록 하자.

df['total'] = df['midterm'] + df['final']

비슷하게 평균 점수도 구할 수 있다.

df['average'] = df['total'] / 2

반복문을 사용하여 ㅁㄴㅇ

grades = []

for row in df['average']:
	if row >= 90:
		grades.append('A')
	elif row >= 80:
		grades.append('B')
	else:
		grades.append('F')

df['grade'] = grades

이제 grade라는 열이 추가되었고, 평균의 점수에 따라서 등급이 매겨졌다.

이번에는 등급을 문자가 아닌 단순히 통과를 했는지 하지 못했는지만 나눠보도록 하자. 여기서는 F 등급은 Fail , 나머지는 모두 Pass 할 수 있도록 하는 함수를 만들고, 그 함수를 바로 데이터프레임에 적용시켜주는 apply 함수를 사용할 것이다.

먼저 Pass인지 Fail인지 구분 지어 줄 수 있는 함수를 작성하자.

def pass_or_fail(row):
	if row != 'F':
		return 'Pass'
	else:
		return 'Fail'

그리고 apply 함수를 적용시켜주면 된다.

df.grade = df.grade.apply(pass_or_fail)

이와 같은 방법으로 특징을 뽑아내서 새로운 열을 생성해 줄 수 있다. 굉장히 자주 사용되는 방법이다.

행 생성 및 수정

위에 성적 관련해서 생성 한 데이터프레임에 행을 추가 해 보자.

먼저 하나의 데이터 프레임을 생성한다.

df2 = pd.DataFrame([['Ben', 50, 50]], columns = ['name', 'midterm', 'final'])

여기서 생성 한 df2 와 위에서 생성한 df와 합쳐서 행을 추가시킬 예정이다. 이는 다음처럼 진행할 수 있다.

df.append(df2, ignore_index = True)

여기서 사용 한 ignore_index 옵션은 합칠 예정인 기존의 df에 0번 인덱스가 있기 때문에 인덱스를 무시하고 마지막 행에 추가하기 위해서 추가 한 옵션이다.

0개의 댓글