02. 자료구조 - 데이터프레임(Data Frame)
Python version : 3.7.10
Pandas version : 1.1.5
데이터 프레임(Data Frame)
Data Frame은 R의 데이터프레임에서 유래했다고 알려져 있습니다.
엑셀, 관계형 데이터베이스 등 분야에서 사용되는 2차원 배열 구조입니다.
데이터 프레임의 행은 가로 줄, 열은 세로 줄을 의미합니다.
데이터 프레임의 열은 각각 시리즈 객체입니다.
시리즈를 열 벡터(column vector)라고 하면 데이터프레임은 2차원 벡터 또는 행렬(matrix)입니다.
열은 공통 속성을 갖는 데이터 행은 개별 관측 대상에 대한 속성 데이터들의 모음인 레코드가 됩니다.
또한 데이터 프레임을 만들기 위해서는 같은 길이의 1차원 배열(시리즈)이 여러 개 필요합니다.
데이터 프레임 만들기
1. 딕셔너리 이용하기
딕셔너리의 key와 val에서
val가 list 형식으로 되어 있을 때 데이터 프레임을 만들 수 있습니다.
key는 열 이름(column name or column label), value는 그 열의 원소 값이 됩니다.
이 때 행 인덱스(row index)의 기본 값은 0부터 시작하는 정수 값이고
index=[]옵션을 통해 지정이 가능합니다.
dict_data = {'c0': [0,1,2], 'c1': [4,5,6], 'c2' : [7,8,9]}
df_dict = pd.DataFrame(dict_data)
만약 행 인덱스를 지정하고 싶다면 df_dict = pd.DataFrame(dict_data, index=['row0', 'row1', 'row2'])
처럼 index 옵션을 사용하여 행 인덱스를 지정할 수 있습니다.
2. 리스트 이용하기
리스트를 이용하여 데이터 프레임을 만들 경우 2차원 배열을 사용해야 합니다.
하지만 리스트는 행 인덱스와 열 이름 모두 없기 때문에 지정해주지 않으면 모두 기본 값이 됩니다.
list_data = [['남성', '43', '가수'], ['여성', '42', '가수']]
df_list = pd.DataFrame(list_data, index=['개리', '정인'], columns=['성별', '나이', '직업'])
데이터 프레임 다루기(Handling)
1. 행 인덱스, 열 이름에 변경하기(rename())
데이터 프레임 객체의 index, columns 속성을 이용하여 변경이 가능합니다.
df_list.index = ['가수1', '가수2']
new_df_list = df_list.rename(columns={'성별' : '남녀', '나이' : '연세', '직업' : '생업'})
이 때 index
는 바로 수정이 가능하지만 colunms
는 rename()
메소드를 이용해야합니다.rename()
메소드의 옵션 inplace=True
값을 이용하면 원본 데이터를 변경할 수 있으며 기본 값은 False
입니다.
2. 행, 열 삭제(drop())
행 또는 열을 삭제하고 싶을 때에는 drop()
메소드를 이용하면 됩니다.drop()
메소드는 삭제하려는 행 또는 열의 key
값과 축을 선택하는 axis
옵션을 정해야합니다.
기본 값은 0이며, 열을 삭제하고 싶을 땐 axis=1
, 행을 삭제하고 싶을 땐 axis=0
으로 설정하면 됩니다.
TIP) `axis=1`은 사실 행을 의미합니다. 그런데 왜 열을 삭제할 때 `axis=1`으로 설정하는 걸까요?
열을 삭제하기 위해서는 각 행에서 해당 열의 값들을 지워야 하는데 여러 행을 참조 해야하기 때문입니다.
여담으로 axis는 번역했을 때 '축'이라는 뜻이기 때문에 'axis가 0이면 행을 삭제, 1이면 첫 번째 열 2이면 두 번째 열일까?' 라고 추측했지만 전혀 아니었습니다.
한편 drop()
메소드에도 inplace
옵션이 있습니다.
exam_data = {'수학' : [90, 80, 70],
'영어' : [95, 89, 90],
'음악' : [85, 95, 100],
'체육' : [100, 90, 90]
}
exam_df = pd.DataFrame(exam_data, index=['서준', '예린', '지은'])
위와 같은 데이터 프레임에서 행 삭제와 열 삭제를 시행해 보겠습니다.
먼저 행 삭제입니다.
#행 삭제 하기 axis=0
#eaxm_df에서 row 한개 삭제 된 객체가 exam_df2에 반환됨.
exam_df2 = exam_df.drop('서준')
print(exam_df2)
print('\n')
행을 삭제하기 위해 행의 index를 전달인자로 하고 axis=0
이 default 이기 때문에 생략했습니다.
위와 같은 코드를 실행하면 첫 번째 행이 삭제되고 두 개의 행만 출력됩니다.
#동시에 여러 개 삭제를 위해 리스트 입력
print("행 여러 개 삭제")
exam_df2 = exam_df.drop(['서준', '예린'])
print(exam_df2)
print('\n')
동시에 여러 개의 행 삭제를 위해서는 전달인자로 리스트를 넣어야 합니다.
마찬가지로 axis=0
이 default 이기 때문에 생략했습니다.
위와 같은 코드를 실행하면 마지막 행을 제외한 두 행이 삭제되고 한 행만 출력됩니다.
다음은 열 삭제입니다.
하나의 열만 삭제할 때,
#열 삭제하기
print("열 삭제")
exam_df2 = exam_df.drop('영어', axis=1)
print(exam_df2)
print('\n')
열을 삭제하기 위해 열 이름을 전달인자로 하고 axis=1
를 입력해줍니다.
'영어' 열이 삭제되고 나머지 열이 출력됩니다.
여러 열을 삭제할 때,
print("열 여러 개 삭제")
exam_df2 = exam_df.drop(['수학', '영어'], axis=1)
print(exam_df2)
print('\n')
행을 여러 개 삭제했을 때와 같은 방식으로 리스트를 전달해주고 axis=1
를 입력해줍니다.
'수학', '영어' 두 열이 삭제되고 한 열만 출력됩니다.
3. 행 선택(DF 객체 속성 loc[], iloc[])
행을 선택하기 위해서는 데이터 프레임 객체 속성 loc
또는 iloc
를 사용하면 됩니다.
이 때 인덱스 이름으로 선택할 때는loc
, 정수형 위치 인덱스로 선택할 때는 iloc
속성을 이용합니다.
exam_data = {'수학' : [90, 80, 70],
'영어' : [95, 89, 90],
'음악' : [85, 95, 100],
'체육' : [100, 90, 90]
}
exam_df = pd.DataFrame(exam_data, index=['서준', '예린', '지은'])
위와 같은 데이터 프레임에서 하나의 행을 선택할 때,
하나의 행만 선택할 때,
print("행 선택")
print(exam_df.loc['서준'])
print('\n')
print(exam_df.iloc[1])
'서준'
이라는 인덱스 이름으로 선택하기 위해 exam_df.loc['서준']
loc
속성을 사용했고,1
이라는 정수형 위치 인덱스로 선택하기 위해 exam_df.iloc[1]
iloc
속성을 사용했습니다.
행을 하나만 선택하면 시리즈 객체로 반환됩니다.
여러 행을 선택할 때,
print('\n')
print("행 여러 줄 선택")
print(exam_df.iloc[[1, 2]])#[[]]을 이용해야한다.
print(exam_df.loc[['서준', '예린']])
print('\n')
print(exam_df.iloc[1, 2]) # []를 이용하면 1행 2열(0부터 카운트)의 데이터가 나온다
print('\n')
위 코드는 여러 행을 한 번에 선택하는 방법입니다.loc
와 iloc
의 사용법은 하나를 선택할 때와 같지만 []
를 중첩해서 써야하는 부분이 헷갈릴 수 있습니다.
여러 행을 선택할 경우 데이터 프레임으로 반환하게 됩니다.
만약 exam_df.iloc[1, 2]
처럼 []
를 하나만 쓸 경우 1행 2열의 데이터가 선택됩니다.
행 선택과는 전혀 다른 결과 값이 반환되기 때문에 주의해야 합니다.
행 범위를 선택할 때,
print("행 범위 선택")
print(exam_df.iloc[0 : 2]) #2는 포함x
print(exam_df.loc['서준' : '지은'])
위 코드는 슬라이싱 기법을 이용한 것입니다.[]
안에 0:2
가 들어가 있는데, 이것은 0이상 2미만을 의미합니다.
만약 최소에서 최대 범위까지를 원하면 0:
을 입력하면 됩니다.
슬라이싱 기법은 인덱스 이름으로도 가능합니다.
4. 열 선택
데이터 프레임은 행 선택에서와 같은 데이터를 사용하겠습니다.
한 개의 열을 선택할 때,
#열 선택
print("열 선택") #열을 하나만 선택할 경우 시리즈로 반환된다.
print(exam_df['수학'])
print('\n')
print(exam_df.수학)
print('\n')
열을 선택하는 방법은 두 가지가 있습니다.exam_df['수학']
처럼 []
안에 열 이름을 넣는 방법exam_df.수학
처럼 객체 속성으로 열 이름을 넣는 방법이 있습니다.
이 때 두 번째 방법은 열 이름이 문자열인 경우만 가능 ex) df.2 불가능
여러 개의 열을 선택할 때,
print("열 여러 개 선택")
print(exam_df[['수학', '음악']])
print('\n')
print(exam_df[['수학']])# [[]] 이중 괄호를 사용하면 열 하나도 데이터프레임으로 반환 가능
print('\n')
열을 여러 개 선택하기 위해서는 exam_df[['수학', '음악']]
[]
괄호를 이중으로 사용해야 합니다.
열 하나를 선택할 때에도 이중괄호를 사용하면 데이터 프레임으로 반환이 가능합니다.
5. 원소선택(loc[], iloc[])
행 선택을 했을 때와 마찬가지로 loc
, iloc
속성을 사용합니다.
exam_data2 = {
'수학' : [90, 80, 70],
'영어' : [95, 89, 90],
'음악' : [85, 95, 100],
'체육' : [100, 90, 90]
}
exam_df2 = pd.DataFrame(exam_data2, index=['서준', '예린', '지은'])
단일 원소를 선택할 때,
print("단일 원소 선택")
selected_data = exam_df2.loc['서준', '음악']
print(selected_data)
selected_data = exam_df2.iloc[0, 1] #[]안 값은 n행, m열을 의미함
print(selected_data)
단일 원소를 선택할 때 전달인자에 따라 loc
또는 iloc
를 사용해서 선택하면 된다.
이 때 []
안의 값은 n행 m열의 원소를 의미한다.
복수 원소를 선택할 때,
print("복수 원소 선택")
selected_data = exam_df2.loc['서준', ['음악', '수학']] #1개 행 2개 열 이므로 시리즈로 반환
print(selected_data)
selected_data = exam_df2.iloc[1, [2, 3]]
print(selected_data)
복수 개의 원소를 선택하는 방법은 []
에서 0번째는 행, 1번째는 열을 의미하므로
여러 행 또는 열을 선택하기 위해 리스트를 사용하면 됩니다.
2개 이상의 원소를 선택하는 경우 시리즈로 반환합니다.
print('\n')
print("범위 지정")
selected_data = exam_df2.iloc[0, 2:]
print(selected_data)
슬라이싱 기법을 사용하여 범위를 지정할 수 있습니다.[]
리스트에서 0번째는 행, 1번째 열은 고정이기 때문에 적절히 사용하면 표기가 간단해 보입니다.
열을 기준으로 선택할 때,
print('\n')
print("열을 기준으로 선택")
selected_data = exam_df2.iloc[ 0: , 1] # 0: => 0~끝까지 즉 1번 열의 모든 인덱스 다 조사
print(selected_data)
예를 들어 영어 열을 기준으로 모든 학생들의 점수가 궁금하다면
위 코드와 같이 iloc[]
에서 1번째 값은 1로 고정하고 0번째 값은 0:
으로 모든 행을 참조하게 하면 됩니다.
6. 행 추가(loc[])
행을 추가할 때 특이한 점이라고 하면 정수형 위치 인덱스를 사용해도 loc[]
를 사용한다는 점입니다.
exam_data2 = {
'수학' : [90, 80, 70],
'영어' : [95, 89, 90],
'음악' : [85, 95, 100],
'체육' : [100, 90, 90]
}
exam_df2 = pd.DataFrame(exam_data2)
행 인덱스를 문자로 정할 때,
exam_df2.loc['행3'] = [95, 80, 75, 95]
print(exam_df2)
print('\n')
'행3'
이라는 인덱스로 행을 추가하고 싶을 때 loc[]
안에 원하는 인덱스를 넣고 각 열에 들어갈 값들을 리스트로 입력해줍니다.
이 때 입력해주는 리스트의 길이와 열의 갯수가 같아야합니다.
행 인덱스를 정수로 정할 때,
print("행을 숫자로 정할 때")
exam_df2.loc[3] = [95, 100, 95, 80] #정수형인데 loc를 쓰는 점이 특이함.
print(exam_df2)
print('\n')
행 인덱스를 정수를 사용하는데 loc[]
를 사용하는 것이 특이합니다.
다른 행의 값을 복제해서 새로운 행을 만들고 싶을 때,
print("다른 행의 값을 복제")
exam_df2.loc[8] = exam_df2.loc[3] #다른 행의 값을 복제 가능, 꼭 인덱스를 순서대로 안 써도 됨
print(exam_df2)
print('\n')
exam_df2.loc[3]
에 index가 3인 행의 값 들이 들어있고 그걸 index가 8인 행에 대입합니다.
7. 열 추가
열을 추가하는 방법은 아주 간단합니다.
exam_df2['국어'] = [90, 95, 80]#이때 값을 한 개만 적으면 열의 모든 값이 동일하게 된다.
print(exam_df2)
exam_df2['국어']
에 행 길이와 맞는 리스트를 대입하면 바로 추가할 수 있습니다.
8. 원소 값 변경
원소 값을 변경하는 방법또한 간단합니다.
exam_data2 = {
'수학' : [90, 80, 70],
'영어' : [95, 89, 90],
'음악' : [85, 95, 100],
'체육' : [100, 90, 90]
}
exam_df2 = pd.DataFrame(exam_data2)
예를 들어 1행 3열의 데이터를 변경하고 싶을 때,
print("특정 원소를 변경")
exam_df2.iloc[0, 2] = 90
print(exam_df2)
print('\n')
위 코드와 같이 정수를 사용해서 선택하고 싶다면 iloc[]
, 이름을 통해 변경하고 싶다면 loc[]
를 사용하면 됩니다.
여러 원소 값을 변경하고 싶을 때,
print("복수 개의 원소 변경")
exam_df2.iloc[1, 0:] = 90
#슬라이싱, 인덱싱 모두 사용 가능.
#직접 선택하고 싶으면 0: 대신 []를 이용하면 됨.
print(exam_df2)
print('\n')
여러 원소 값을 한 번에 바꾸고 싶다면 위 코드 처럼 슬라이싱 방법을 사용하거나 직접 선택하고 싶다면 행 또는 열 부분에 리스트 요소로 선택하면 됩니다.
9. 행, 열 위치 바꾸기
선형대수학의 전치행렬과 같은 개념으로 행과 열을 서로 바꾸는 것입니다.
이 때 새로운 객체를 반환하는 것에 주의해야 합니다.
exam_data2 = {
'수학' : [90, 80, 70],
'영어' : [95, 89, 90],
'음악' : [85, 95, 100],
'체육' : [100, 90, 90]
}
exam_df2 = pd.DataFrame(exam_data2)
전치행렬을 하는 방법은 메소드를 이용하는 방법과 데이터프레임 객체 속성을 이용하는 방법이 있습니다.
메소드를 활용하는 방법으로는,
print("메소드를 활용하여 바꾸기")
transed_df = exam_df2.transpose()
print(transed_df)
print('\n')
위 코드와 같이 transpose()
메소드를 활용하면 가능합니다.
객체 속성을 사용하는 방법으로는,
print("클래스를 활용하여 바꾸기")
orgin_df = transed_df.T #DF 클래스 중 T라는 속성
print(transed_df.T)
T
라는 속성으로 transed_df.T
처럼 사용할 경우 바꿀 수 있습니다.
Reference
도서 [파이썬 머신러닝 판다스 데이터 분석]을 공부하며 작성했습니다.