1. 개념
* python library로 구조화된 데이터를 효과적으로 처리하고 저장한다
- array 계산에 특화된 NumPy를 기반으로 설계한다
- 2차원 데이터 외 대용량 데이터 처리에 효과적임
- 데이터 가공, 변환, 정제, 수집, 전처리, 통계, 시각화 작업 모두 가능
-1- 데이터 수집) 텍스트, CSV, Excel, HTML(BeautifulSoup), XML, Hdfs, db, JSON 여러 형태를 pandas는 읽을 수 있다
-2- 데이터 전처리) 전처리 과정을 반드시 거쳐야 함 - 분석가능한 형태로 변형 (null 처리, 이상치, 정규화 등등)
-3- 데이터 분석) 통계 & 시각화(matplotlib, seaborn)
-4- 예측) pandas에서는 지원하지 않음 - sklearn, Tensorflow, keras, pytorch, statesmodels, scypython 추가 library 이용
** 1차원 데이터 분석 → Series
** 2차원 데이터 분석 → Dataframe
2. Series
[1] 개념
* Series = NumPy의 array가 보강된 형태 (일종 특수한 dictionary)
- data와 index를 가지고 있다.
- numpy의 array에 index가 추가
- Series만을 단독으로 생성하여 사용할 일은 없고, 행 단위/ 컬럼 단위로 접근 시 Series 자료구조 개념으로 접근한다
* pd.Series()
class pandas.Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False)
- tuple, list, dictionary 모두 Series()를 통해서 Series를 만들 수 있다.
(* 이 때, tuple과 list는 index가 0부터 자동으로 생성(zero-based index)이 되고, dictionary의 경우 key가 index로 생성된다)
→ index: 아니면 index 자체를 만들어서 Series 생성이 가능하다 (* pd.Series(data, index=[~]) (같은 값 index 생성 가능)
- index를 통한 접근은 [index]를 통해 Series의 내용을 불러올 수 있다 (그러나 list, tuple과 다르게 음수로는 접근 불가)
→ dtype: Series 내의 dtype 데이터 타입 적용이 가능하다! (* pd.Series(data, dtype=np.~))
(* Series 자체가 numpy의 array가 보강된 형태여서 dtype에 np type을 붙여준다)
→ name: Series의 이름을 붙일 수 있다. (* pd.Series(data, name='~'))
* Series 속성
- ndim (1차원이므로 무조건 1!)
- shape ( (n,)이 나옴!)
- name
- size (행 개수 * 열 개수의 값이 나옴 - 즉 n 나옴)
- dtype
- index
- sort_index (ascending True, False 옵션)
- values (type은 numpy.ndarray 나옴! - 앞에서 말했듯이 numpy의 ndarray를 보강한 형태이므로 :0)
- sort_values (ascending True, False 옵션)
- max
- min
- idxmax (가장 큰 값의 index가 반환된다)
- quantile (원하는 분위의 수가 반환됨)
- std (표준편차)
- unique
- value_counts()
→ **Series.str.contains()
- Series, 또는 주어진 datframe의 한 column에서 원하는 문자가 들어있는 지를 찾아주는 method!
(여기서 중요한 건 str.contains()는 Series형태, 즉 한 column에만 적용할 수 있다는 점이다!)
- contains() 내부에 정규식 표현(regular expression)을 집어넣어 원하는 data 찾을 수 있음!
sr = pd.Series(['2','ewe','32wqa'])
sr.str.contains('e')
(실행결과) - False, True bool값을 리턴해준다
0 False
1 True
2 False
dtype: bool
→ ** Series.str.replace('a','b') = replace 'a' with 'b'
- Series, 또는 주어진 datframe의 한 column에서 기존 data의 글자(또는 문자열 전체)를 원하는 data로 바꿀 때 사용한다
- source) https://pandas.pydata.org/docs/reference/api/pandas.Series.html
[2] Series의 values
* series는 값(values)을 ndarray 형태로 가지고 있다.
* 즉, data자체는 series인데 그 안에 들어가는 value는 ndarray인 배열 형태 - numpy (꼭꼭 기억!)
import pandas as pd
data = pd.Series([1,2,3,4])
print (data)
# 0 1
# 1 2
# 2 3
# 3 4
# dtype: int64
print(type(data))
#<class 'pandas.core.series.Series'>
print(data.values)
# [1 2 3 4]
print(type(data.values))
#<class 'numpy.ndarray'>
[3] indexing(+dtype)
* dtype인자로 데이터 타입을 지정할 수 있다. (위에서 언급함!)
data = pd.Series([1,2,3,4],dtype="float")
print(data.dtype) #float64
* index를 지정할 수 있고 index로 접근(indexing)이 가능하다
- 또한 index로 접근하여 원하는 value로 바꿀 수 있다.
- index를 숫자로 지정하면 헷갈림을 방지하기 위하여 zero-based index는 적용되지 않는다 (iloc은 zero-based로 고정됨!)
data = pd.Series([1,2,3,4],index=['a','b','c','d'])
data['c'] = 5
data[0] #'a'
data[-1] #'d'
[4] dictionary 활용
* Series는 dictionary와 매우 유사
- dictionary를 활용하여 series를 생성할 수 있다. (위에서 잠깐 언급함!)
population_dict = {
'china': 141500,
'japan': 12718,
'korea': 5180,
'usa': 32676
}
population = pd.Series(population_dict)
- 아래와 같이 만들어진 딕셔너리를 series로 변환이 가능하다
(index를 key인 나라이름, values는 딕셔너리 value 값인 인구수)
3. dataframe
* 데이터프레임 = 여러 개의 Series가 모여서 행과 열을 이룬 data
[1] dataframe 생성
{1} Series 합치기 & Series로 변경
- 예시) 앞의 population Series에 이어서 gdp Series를 만들고 dataframe으로 두 series를 합치면
gdp_dict = {
# ~
}
gdp = pd.Series(gdp_dict)
country = pd.DataFrame({
'gdp': gdp,
'population': population
})
- 2차원을 1차원 Series로 변경한다 (변경된 Series는 한 column만 value로 두고, 나머지는 multi-index로 변함)
df.unstack()
{2} Dictionary 활용하여 생성하기
data = {
'country' : ['china', 'japan', 'korea', 'usa'],
'gdp' : ~ ,
'population': ~ ,
}
country = pd.DataFrame(data)
country = country.set_index('country')
- set_index method를 통해 country column이 index로 들어간 것을 확인할 수 있다.
{3} 딕셔너리 & Series & Dataframe 비교
* dictionary는 data = {key:value} 형태로 표현된다.
* series는 배열로 Series() 또는 딕셔너리를 통해 만들 수 있다.
* dataframe은 series의 모음으로 만들 수 있으며 series data + index의 형태이다. 또는 dictionary에서 바로 dataframe으로도 만들 수 있다.
[2] dataframe 속성
- 아래에 다룰 해당 dataframe은 위에서 언급된 dataframe.
* shape & size & ndim & values & T
- shape은 dataframe의 data shape을 뜻함
(즉 해당 데이터프레임인 경우 (4,4)가 아니라 (4,2))
- T는 transpose의 T로 해당 dataframe의 행과 열을 서로 바꿔 뒤집음
print(country.shape) # (4,2)
print(country.size) # 8
print(country.ndim) # 2
print(country.values) # [[1409250000 ~
* nlargest - 특정 column을 기준(2개 이상도 가능)으로 가장 큰 n개의 data만 가져오겠다는 뜻! (꽤 많이 쓰인다! 꼭 기억하자....!!)
- 출력결과는 가장 큰 n개의 data가 포함된 '행' 전체로 구성된 dataframe이 return됨!
- keep인자) default first이며, 동일한 값인 경우 all이면 전체를 보여주고, last이면 index 기준 마지막 index data먼저 보여줌
- (중요) 정렬은 보장 x. 단순히 상위 n개만 가져옴
* nsmallest - nlargest와 반대개념! 내용은 똑같음
df.nlargest(n,'column_name')
df.nsmallest(n,'column_name')
[3] dataframe - index & column에 이름 지정하기
* index & columns에 name 메소드 사용
country.index.name = "Country" #naming index
country.columns.name = "Info" #naming columns
print(country.index)
# Index(['china', 'japan', 'korea', 'usa'], dtype='object', name = 'Country')
print(country.columns)
# Index(['gdp','population'], dtype='object', name = 'Info')
[4] dataframe - save & load
* 엑셀이나 csv(comma separated value) 파일로 불러올 수 있고 저장도 가능하다
country.to_csv("./country.csv")
country.to_excel("country.xlsx")
country = pd.read_csv("./country.csv")
country = pd.read_excel("country.xlsx")
→ Excel) data 전체가 아니라 일부 data만 가져오고 싶을 때 header & usecols 사용 가능
ex) header는 1로 맨 위의 행만 제외하고 아래 행부터 가져올 때 아래와 같이 사용할 수 있다!
df = pd.read_excel("~.xlsx", header = 1)
ex) parse_cols 값에 가져오고 싶은 컬럼명만 지정해서 가져올 수 있다!
df = pd.read_excel("~.xlsx', usecols="column_names(list)")
[4.5] dataframe - pivot table
* 원하는 정보 일부만 모아서 데이터 확인용으로 pivot table을 만들 수 있다!
→ create a spreadsheet-style pivot table as a DataFrame
https://pandas.pydata.org/docs/reference/api/pandas.pivot_table.html
ex)
df.pivot_table(index='a', values='b', aggfunc='mean')
- index와 values(내용물)을 기존 dataframe에 원하는 정보를 선택할 수 있으며, 이 때 집계함수를 기준으로 데이터를 나눠 보여줄 수 있다.
[5] 데이터 선택 및 변경
{1} 데이터 선택 - indexing / slicing
* .loc: 명시적인 index를 참조하는 인덱싱/슬라이싱 (index 값을 알고 있을 때 사용)
country.loc['china'] #indexing
country.loc['japan':'korea', :'population'] #slicing
- indexing) 위의 예의 경우 명시적으로 'china'라는 index에 해당하는 data를 불러오게 하였다.
- slicing) :을 사용하여 원하는 index 범위에 해당하는 data 불러오게 하였다.
(,기준 앞이 index, 뒤가 column)
♣ loc documentation ♣
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html
* .iloc: 암묵적으로, python 스타일의 정수 index indexing & slicing
- 상대적인 data간의 위치를 이용해서 값을 찾아낼 때 사용한다
country.iloc[0] #indexing
country.iloc[1:3,:2] #slicing
{2} 데이터 선택 - column 선택
* 컬럼명을 활용하여 dataframe에서 data 선택이 가능하다
country
country['gdp']
country[['gdp']]
- 대괄호를 한 번 씌우면 구성성분인 series 형태로 나오지만, 대괄호를 두 번 씌우면 dataframe 형태로 나온다.
{3} 데이터 선택 - 조건 활용
* masking 연산이나 query 함수를 활용하여 조건에 맞는 dataframe 행을 추출할 수 있다.
- dataframe 형태로 출력
country[country['population'] < 10000] #masking operation
country.query("population > 100000") #query function
- 조건 사용 시 and 연산자 (&)와 or 연산자 (|)를 사용해서 다양한 조건을 만들 수 있다. (마스킹 연산의 경우)
- query의 경우 영어로 and, or
(+) format string을 이용한 query 연산
- query() 안에 f를 치고 {}안에 format 형태를 넣으면 해당 format에 들어간 식이 query에서 돌아가 원하는 dataframe 형태를 반환!
ex) sepal_length값이 6.0이상인 경우의 dataframe 반환
n = 6.0
df_iris.query(f'sepal_length>{n}')
{4} 데이터 변경 - column 추가
* Series도 numpy array처럼 연산자 활용이 가능하다
- 연산자 활용을 통해 series가 생성되고 이를 집어넣고자 하는 데이터프레임의 한 column으로 추가가 가능하다
gdp_per_capita = country['gdp']/country['population']
country['gdp_per_capita'] = gdp_per_capita
{5} 데이터 변경 - 데이터 추가/수정
* list로 추가 or dictionary로 추가
* index 활용하여 데이터 수정
df = pd.DataFrame(columns = ['이름', '나이', '주소']) #making a dataframe
df.loc[0] = ['길동', '26', '서울'] #add data using a list
df.loc[1] = {'이름':'철수', '나이':'25', '주소':'인천'} #add data using a dictionary
df.loc[1, '이름'] = '영희' #명시적 indexing으로 revising data
{6} 데이터 변경 - NaN column 추가 & 삭제
* NaN값으로 초기화한 새로운 column 추가
- NaN을 추가하고 싶다면 import numpy as np → np.nan 추가
df['전화번호'] = np.nan #add new column and reset
df.loc[0,'전화번호'] = '01012341234' #using index - revise data
* NaN을 포함한 column을 삭제하려면 dropna() 함수를 사용하면 된다
- axis=0이면 NaN을 포함한 row(행)가 삭제되며, axis=1이면 NaN을 포함한 column(칼럼)이 삭제된다
(axis=0이면 행 방향, axis=1이면 열 방향임을 꼭 기억!)
- 특정 NaN만 삭제하고 싶으면 subset=['column_name']을 사용하여 해당 column에의 NaN을 포함한 행, 또는 열이 삭제된다
♠ dropna
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html
(+) isnull.sum() & fillna()를 통해 NaN의 개수를 구하거나 NaN을 원하는 값으로 대체할 수 있다! (아래 집계함수 part에 설명)
{7} 데이터 변경 - column 삭제
* 데이터프레임에서 column 삭제 후 원본 변경
- axis) 1은 열 방향, 0은 행 방향
(여기서는 전화번호 컬럼을 지우기에 열, 즉 위에서 아래 방향으로 지우므로 1임)
- inplace) True는 원본을 변경, False는 원본을 변경하지 않는다는 뜻
(실무적으로 굉장히 중요한 파라미터로, 원본을 지키는 상태에서 변경할 수도 있기에 inplace 값 언제나 고려할 것)
df.drop('전화번호', axis=1, inplace = True) #delete a column
- columns = [~], index = [~]로 원하는 data 삭제가 가능하다
[6] 데이터프레임 정렬
{1} index 값 기준 정렬
* index 방향 & 오름차순, 내림차순
- axis = 0: 행 index 기준 정렬 (default 오름차순)
df = df.sort_index(axis=0)
- axis = 1: 열 index 기준 내림차순 정렬 (ascending = False)
df.sort_index(axis=1,ascending=False)
{2} column 값 기준 정렬
* default = 오름차순
df.sort_values('col1',ascending=True)
- ascending=False하면 그 반대로 정렬
* 여러 column 동시에 정렬도 가능
- (하단) col2 column 기준 오름차순 정렬 후, col1 column 기준 내림차순 정렬
(먼저 정렬된 data 내에서 다시 오름 or 내림차순으로 정렬한다)
df.sort_values(['col2','col1'],ascending=[True,False])
[7] 데이터프레임 분석용 함수
{1} count
* count 메서드를 활용하여 데이터 개수 확인이 가능하다 (default: NaN값 제외)
data = {
'korean' : [50,60,70],
'math' : [10, np.nan, 40]
}
df = pd.DataFrame(data, index = ['a','b','c'])
df.count(axis=0) #열 기준 count
df.count(axis=1) #행 기준 count
{2} max, min
* max, min 메서드를 활용하여 최대, 최소값 확인 가능
* default: 열 기준, NaN값 제외
data = {
'korean' : [50,60,70],
'math' : [10, np.nan, 40]
}
df = pd.DataFrame(data, index = ['a','b','c'])
df.max()
df.min()
{3} sum, mean
* sum, mean 메서드를 활용하여 합계 및 평균 계산
* default: 열 기준, NaN값 제외
data = {
'korean' : [50,60,70],
'math' : [10, np.nan, 40]
}
df = pd.DataFrame(data, index = ['a','b','c'])
df.sum()
df.mean()
* axis, skipna 인자를 활용하여 합계 및 평균을 계산할 수 있다. (행 기준, NaN값 포함할 경우)
- default로 원래 NaN을 포함하기에 False로 두어 NaN을 포함해 결과를 NaN을 출력한다.
data = {
'korean' : [50,60,70],
'math' : [10, np.nan, 40]
}
df = pd.DataFrame(data, index = ['a','b','c'])
df.sum(axis=1)
df.mean(axis=1, skipna=False)
* (NaN 해결) NaN값이 존재하는 column의 평균을 구하여 NaN값을 대체할 수 있다.
- fillna() 사용: 해당값을 NaN 대신 대체하겠다는 의미
B_avg = df['math'].mean()
print(B_avg) # 25.0
#replace NaN
df['math']=df['math'].fillna(B_avg)
#mean
df.mean(axis=1,skipna=False)
[8] 데이터프레임 - 그룹으로 묶기
{1} groupby
* 간단한 집계를 넘어서서 조건부로 집계하고 싶을 때 사용
df = pd.DataFrame({
'data1': range(6),
'data2': [4,4,6,0,6,1],
'key': ['A', 'B', 'C', 'A', 'B', 'C']
})
df.groupby('key').sum() #1번
df.groupby(['key','data1']).sum() #2번
- 첫번째 groupby는 각 key를 그룹으로 하여 각 그룹의 합을 나타내었고
- 두번째 groupby는 key로 그룹으로 묶은 다음 각 그룹에서 data1에 대해서도 그룹을 묶어 만들어진 세부그룹별 합계도 나타낼 수 있다.
{2} + aggregate
* groupby를 통해서 집계를 한 번에 계산할 수 있다.
- aggregate 메서드 활용 (여러 aggregate 함수를 각각 다른 column에 적용하여 원하는 대로 결과 표현 가능!)
df.groupby('key').aggregate(['min', np.median, max]) #1번
df.groupby('key').aggregate({'data1':'min', 'data2':np.sum}) #2번
- 첫번째 groupby의 경우 각 key를 그룹으로 하여 min, median, max 결과를 나타냄
- 두번째 groupby의 경우 집계할 데이터마다 집계방법을 달리 한 결과를 나타낸 것이다.
{3} filter
* groupby를 통해서 그룹 속성을 기준으로 데이터를 filtering할 수 있다.
- filter() 사용
def filter_by_mean(x):
return x['data2'].mean() > 3
df.groupby('key').mean() #1번
df.groupby('key').filter(filter_by_mean) #2번
- 두번째 groupby의 경우 동일 key의 평균이 3보다 큰 경우에 해당하는 원본 데이터만 나타낸다는 뜻이다.
{4} apply, lambda
* groupby를 통해서 묶인 데이터에 함수를 적용한다.
df.groupby('key').apply(lambda x: x.max() - x.min())
- 모든 data에 apply 함수로 계산한 값을 나타내 준다.
→이와 같이 apply(function_name)을 적용하면 function_name 함수가 특정 column에 모두 적용된다! (매우 편리하고 많이 쓰이는 apply! 꼭 기억 :))
{5} get_group
* groupby로 묶인 data에서 key값으로 데이터를 가져올 수 있다.
- get_group("key") 사용
df = pd.read_csv("./univ.csv")
df.head()
df.groupby("시도").get_group("충남")
len(df.groupby("시도").get_group("충남")) # 94
* 출처) 2021 NIPA/AI 기본/응용 교육과정
'Data Science Fundamentals > Pandas&Numpy and Questions' 카테고리의 다른 글
pandas Tricks_02 👉🏻 'Select columns by Data Type' (Kevin by DataSchool) (0) | 2022.03.25 |
---|---|
list comprehension (0) | 2022.03.23 |
pandas functions - cut, qcut (0) | 2022.03.23 |
pandas Tricks_01 👉🏻 'Reverse (row/column) Order' (Kevin by DataSchool) (0) | 2022.03.23 |
NumPy intro. + fundamentals 1/2 (0) | 2022.03.20 |
댓글