대부분의 데이터는 구조화가 되어 있지 않다. 간혹가다 구조화된 데이터를 얻을 수 있겠지만, 이는 경제적으로 매우 높은 가치를 가지고 있는 데이터 일 것이다.
import pandas as pd
import numpy as np
pandas를 사용하기 위한 라이브러리를 불러와준다.
x = {'a':1,'b':2,'c':3}
s = pd.Series(x)
s.index() # array(['a', 'b', 'c'])
s.values() # array([1, 2, 3])
s['a'] # ( =a[0]) 1
Series를 Dict형으로 만들었다. 사전은 원래 순서가 없으나, Series는 순서가 중요하다.
인덱스에 이름을 넣어서 배열을 만든것과 같다. 값을 얻기 위해서 인덱스나 순서로 검색할 수 있다.
x = np.array([111, 222, 333])
s = pd.Series(x)
s # 0 111 = / 1 222 / 2 333
my_index = ['a', 'b', 'c']
s = pd.Series(x, index=my_index)
s # 'a' 111 / 'b' 222 / 'c' 333
인덱스를 명시하지 않으면 원래 우리가 아는 인덱스가 자동 생성된다.
인덱스를 따로 지정하여 넣어줄 수 있다.
리스트 인덱싱하는 것과 같은 방법을 인덱싱이 가능하다. (ex) s['a':'c'] => a 111 / b 222 / c 333, s['a', 'c'] => 111, 333)
type(s.values)
numpy.ndarray
Series는 numpy배열의 확장형이라고 생각하면 된다.
s = pd.Series(data=[111, 222, 333, 444], index=['a', 'b', 'c', 'd'], name='MySeries', dtype='float64')
s
a 111.0/b 222.0/c 333.0/d 444.0/ Name:MySeries, dtype:float64
이름과 데이터 타입을 선언해줄 수 있다. 특히 이름은 Series에만 있는 속성이다. name을 확인하기 위해서는 s.name을 사용한다.
s1 = pd.Series(data=[1, 2, 3, 4])
s2 = pd.Series(data=[1, 2, 3, 4])
s1 * 2 # 0 2/ 1 4/ 2 6/ 3 8
s1 + s2 # 0 2 / 1 4 / 2 6 / 3 8
인덱스가 같은 Series끼리의 연산은 numpy배열의 연산과 같은 방식으로 진행된다.
s1 = pd.Series(data=[1, 2, 3, 4], index=['d' 'b', 'c', 'a'])
s2 = pd.Series(data=[1, 2, 3, 4], index=['a', 'b', 'd', 'e'])
s1 + s2 # a 5.0 / b 4.0 / c NaN / d 4.0 / e NaN
인덱스가 다른 Series끼리의 사칙연산을 하면 인덱스가 같은 값끼리 연산을 한 후, 한쪽에만 있는 인덱스의 값은 NaN으로 결측치 처리가 된다. 결측치가 생기는 경우 데이터타입이 floa64로 바뀐다.
s1.sum() # 10
s1.mean() # 2.5
s1.median() # 2.5
s1.std() # 1.290944...
s1.var() # 1.666666...
s1.sort_values() # d 1 / b 2/ c 3/ d 1
s1.sort_index() # a 4 / b 2 / c 3 / d 1
s.value_counts() # 도수표 생성
s.nunique() # 4 unique한 요소가 몇개인지
기본적인 통계 메소드가 존재하며, 특이한 것으로는 value기준 또는 index기준으로 나눠서 sort가 가능하다
value_counts()는 각각의 요소가 배열에 몇개가 있는지를 나타내준다.(도수표를 생성)
import pandas as pd
import numpy as np
import os
os.chdir(r"../data")
df = pd.read_csv('data_studentlist_en.csv', header='infer', encoding='ms949')
df.head(3) # df.tail(3) : 하단 3행
data_studentlist_en파일을 불러와서 상위 3개만 출력(head(3)).
한글이 있을 경우, utf-8이 잘 작동하지 않을 수 있으므로, encoding을 'ms949'로 작성해주어야한다. header에 infer라는 것은 파일 안에 있는 제일 첫줄을 헤더라고 지칭해준다. 만약 header가 없는 경우는 header=None이라고 입력하면 0, 1, 2...로 대체해준다.
df.columns # 컬럼의 이름들을 출력
df.index # 인덱스의 이름들을 출력
df.shape() # (17, 8) 행의 수와 열의 수를 출력
df.size # 138 (= 17 * 8) 총 데이터의 개수(셀의 수)
df.ndim # 2 차원의 수
df.info() # 자료형을 보여줌
데이터 프레임의 정보를 알 수 있는 메소드들.
인덱스는 Series와 마찬가지로 내가 원하는 값으로 바꿀 수 있다.
np.round(df.describe(), 1) # 수치형 변수에 대한 기술 통계량를 제공.
수치형 변수에 대한 개수, 평균, 표준편차, 최소값, 4분위수, 최대값이 데이터 프레임으로 출력된다.
df['bloodtype'] # Series로 컬럼 하나를 출력가능 ( =df.bloodtype)
df[['bloodtype']]
df[['bloodtype', 'gender']] # 여러개의 값도 추출 가능
출력한 한 컬럼의 이름은 'bloodtype'이 된다. df['blooltype']과 df.bloodtype은 같은 결과를 출력한다. 하지만 이름에 공백이나 특수문자가 있는 경우는 df.---이 안된다.
출력물을 대괄호로 묶어주면 다시 DataFrame으로 출력된다.
df.loc[:, 'name'] # 모든 행의 name열만 출력
df.loc [0:5, ['name', 'gender']] # 데이터 프레임으로 0~4번째 행의 name, gender를 출력
df.iloc[:, 2] # 숫자로만 열과 행의 위치를 나타내어 출력가능
loc은 이름으로 값을 추출해오는 것이고, iloc은 숫자(위치)로 값을 추출해오는 것이다.
또한 loc는 처음과 끝 모두를 포함시키지만, iloc은 뒤에 (숫자 -1)까지 포함이다.
loc[3:5] => 3, 4, 5 / iloc[3:5] => 3, 4
my_index = 'a b c d e f g h i j k l m n o p q'.split() # 공백으로 잘라서 리스트에 저장
df.index = my_index # 인덱스 값을 지정
df.drop(columns=['name']) # 특정 컬럼 제거, 항구적으로 사라지지는 않음
df.drop(columns=['name'], inplace=True) # 제거하고 남은 내용을 항구적으로 저장
np.round(df['BML'] = 10000 * df['wdight'] / df['height'] ** 2, 1) # 특정 컬럼 생성
인덱스 값은 원하는 값으로 지정해주었다. 이때의 loc('a', 'name')이런식으로 사용해줘야한다.
drop을 이용하여 필요없는 컬럼을 제거할 수 있따. 하지만 항구적이지 않아 변수에 저장이 필요하다.
df['df.GENDER == 'M'] # 성별이 M인경우만 가져옴
df[{df.GENDER == 'M') & ((df.HEIGHT < 160) | (df.HEIGHT > 180))] # 남자중 키가 160~180사이인 경우만 가져옴
numpy의 fancy인덱싱과 같은 방식으로 사용가능하다.
df.to_csv('data_new.csv', index=False) # 외부에 save
수정한 데이터를 외부의 파일로 저장하는 방법.
dfx = read_excel('data_studentlist_en.xlsx', sheet_name = 'Sheet1')
dfx.to_excel('data_studentlist_en2.xlsx', s) # 읽은 파일을 출력
엑셀 파일을 읽고 이 내용을 출력하는 코드.
data = {'name':['jake', 'john', 'david', 'sarah'], 'age':[23, 20, 15, 29], 'gender':['M', 'M', 'M', 'F']} #dict 생성
df = pd.DataFrame(data = data, index=['a', 'b', 'c', 'd'])
사전을 이용하여 데이터 프레임을 생성했다. 이 때, index를 별도로 지정해주었다.
x = np.round(np.random.randn(16), 2) # 100개의 랜덤 숫자 생성
x = x.reshape(4, 4)
df = pd.DataFrame(data = x, columns=['First', 'Second', 'Third', 'Fourth'], index=['a', 'b', 'c', 'd'])
데이터프레임을 생성해주었는데 그냥 넣으면 단순 숫자로만 데이터가 이루어져있어 컬럼이름이 없다. 따라서 원하는 이름을 columns로 넣어주었다.
df = pd.read_csv('data_studentlist_en.csv', header='infer', encoding='ms949')
df_left = df[['name', 'age', 'gender', 'absence']] # ( =df.loc[:, ['name', 'age', 'gender', 'absence']])
df_right = df[['name', 'bloodtype', 'weight', 'height']]
df_left_small = df_left.loc[:10,]
df_right_small = df_right.loc[7:,] # 좀 더 직관적으로 보기 위해
pd.merge(df_left_small, df_right_small, left_on='name', right_on='name', how='inner') # name을 가지고 두 데이터를 inner join한다
왼쪽의 key를 name, 오른쪽의 key를 name으로 inner조인을 시행한다. 이 경우 겹치는 7, 8, 9, 10행만이 출력된다. how의 left, right, inner, outer를 입력함으로써 조인 방법을 바꿀 수 있다.
조인은 왼쪽, 오른쪽만 조인이 가능하다.
조인이 아닌 다른 합치는 방법이 있다.
pd.concat([df_left_small, df_right_small], ignore_index=True, axis=0)
concat을 사용하면 내용을 위아래로 이어붙일수 있다. ignore_index가 True이면 원래 있던 인덱스를 무시한다. axis가 0이 default로 들어가 있으므로, 세로방향으로 합쳐진다.
axis가 1이면 그냥 이어붙인 결과이므로 같은 컬럼이 두개 생긴다(예시에서는 키로 사용한 name이 두개가 된다)