220929 Day25

유예지·2022년 9월 29일

[0928 복습]

1

>>> import pandas as pd
>>> import numpy as np

>>> data = pd.Series([1., -999., 2., -999., -1000., 3.]) 
	data
    
>>> data.replace([-999, -1000], np.nan)

>>> np.where(data <= -999, np.nan, data)

2

>>> df = pd.DataFrame({'A' : ['a5', 'a6'], 'B' : ['b5', 'b6'],
					   'C' : ['c5', 'c6']})
	df
    
>>> new_row = pd.DataFrame([['aaa', 'bbb', 'ccc']], columns = df.columns)
	new_row
    
>>> pd.concat([df, new_row])
>>> pd.concat([df, new_row], ignore_index = True)

3

>>> df = pd.DataFrame({'A' : ['a1', 'a2', 'a3', 'a4'],
                  'B' : ['b1', 'b2', 'b3', 'b4'],
                  'C' : [1, 2, 3, 4]})
	df
    
>>> df.melt(id_vars = ['A'], value_vars = ['B','C'])
>>> df.melt(id_vars = ['A'])
>>> df.melt(['A'])

>>> df.melt(['A'], ['B', 'C'], var_name = 'New')

4

>>> np.random.seed(1234)
>>> a = pd.DataFrame(np.random.randn(1000, 5))
	a
    
>>> a[(np.abs(a) > 3).any(1)]
>>> a[(np.abs(a) > 3)].any(axis = 1)
>>> a[(np.abs(a) > 3)].any(axis = 1).sum()

5

>>> import pydataset
>>> movies = pydataset.data('movies')
	movies
>>> movies.info()

>>> movies[['title', 'year', 'length']]    #또는 movies.iloc[:, :3]
>>> m = movies[['title', 'year', 'length']]
	m
    
>>> m['length']
>>> bins = [1, 60, 100, 180]
	pd.cut(m['length'], bins, labels = ['short', 'mid', 'long'])
    
>>> movies['time'] = pd.cut(m['length'], bins, labels = ['short', 'mid', 'long'])
	movies.head()

6

>>> df = pd.read_excel('excel_exam.xlsx')
	df
    
>>> df.melt(id_vars = 'class', value_vars = ['math', 'science'],
			var_name = '과목', value_name = '점수')

* 긴 형식(long)에서 넓은(wide) 형식으로 .pivot(index = , columns = , values = )

>>> df = pd.DataFrame({'key': ['foo', 'bar', 'baz'],
                   'A': [1, 2, 3],
                   'B': [4, 5, 6],
                   'C': [7, 8, 9]})
	df

#melt
>>> df.melt(id_vars = ['key'], value_vars = ['A','B'])  
>>> df1 = df.melt(id_vars = ['key'], value_vars = ['A','B','C'])
	df1[:4]

#pivot
>>> df1.pivot(index = 'key', columns = 'variable', values = 'value')
>>> df1.pivot(columns = 'variable', values = 'value')
>>> df1.pivot(index = 'key', columns = 'variable',
		      values = 'value').reset_index()        

https://raw.githubusercontent.com/wesm/pydata-book/3rd-edition/examples/macrodata.csv

>>> data = pd.read_csv('macrodata.csv')
	data.head()
    
>>> periods = pd.PeriodIndex(year=data.year, quarter=data.quarter,
                             name='date')
    columns = pd.Index(['realgdp', 'infl', 'unemp'], name='item')
    data = data.reindex(columns=columns)
    data.index = periods.to_timestamp('D', 'end')
    ldata = data.stack().reset_index().rename(columns={0: 'value'})  
    
>>> ldata    #긴 형식의 데이터이다
>>> ldata.pivot(index = 'date', columns = 'item', values = 'value')

>>> ldata['value2'] = np.random.randn(len(ldata))
	ldata
    
>>> ldata.pivot(index = 'date', columns = 'item')
>>> ldata.pivot(index = 'date', columns = 'item',
				values = ['value', 'value2'])[:4]
>>> ldata.pivot(index = 'date', columns = 'item',
				values = ['value', 'value2']).reset_index()[:4]
                
>>> ldata.set_index(['date', 'item'])                
>>> ldata.set_index(['date', 'item']).unstack('item')                

8. 그래프와 시각화

(1) matplotlib

matplotlib에서 그래프는 Figure 객체 내에 존재한다
그래프를 위한 새로운 figure는 'plt.figure' 를 입력하여 생성할 수 있다

빈 figure 로는 그래프를 그릴 수 없으므로, 'add_subplot' 을 사용해서 최소 하나 이상의 'subplots'를 생성해야 한다

>>> fig.add_subplot(2,2,1)
#figure의 크기가 2x2 이고, 4개의 subplot 중에서 첫번째를 선택한다는 의미
  • 눈금, 라벨, 범례
    pyplot 인터페이스를 사용해서 xlim, xticks, xticklabels 와 같은 메서드로 표의 범위를 지정하거나 눈금 위치, 눈금 이름 등을 조절할 수 있다
    범례 추가는 plt.legend 를 이용해서 할 수 있다 (축에 대한 범례 : ax.legend)

  • 도형 추가하기
    matplotlib 은 일반적인 도형을 표현하기 위한 patches 라는 객체를 제공한다
    전체 모음은 matplotlib.patches 에 있다

  • 그래프를 파일로 저장하기
    활성화된 figure 는 plt.savefig 메서드를 이용해서 저장할 수 있다

>>> plt.savefig('figpath.png', dpi = 400, bbox_inches = 'tight')
  • matplotlib 설정
    rc 메서드를 사용해서 설정한다
>>> plt.rc('figure', figsize = (10,10))

(2) pandas 에서 seaborn 으로 그래프 그리기

① 선그래프 : .plot()

Series와 DataFrame은 둘다 plot 메서드를 이용해 다양한 형태의 그래프를 생성할 수 있다
기본적으로 plot 메서드는 선그래프를 생성한다

>>> import matplotlib.pyplot as plt
>>> import seaborn as sns

#Series
>>> s = pd.Series(np.random.randn(10).cumsum(), index = np.arange(0,100,10))
	s
    
>>> s.plot() 

Series 객체의 색인은 matplotlib에서 그래프를 생성할 때 'x축' 으로 해석되며 'use_index = False' 옵션을 넘겨서 색인이 그래프의 축으로 사용되는 것을 막을 수도 있다
x축의 눈금과 한계는 'xticks'와 'xlim' 옵션으로 조절할 수 있다 (y축도 마찬가지)

#DataFrame
>>> df = pd.DataFrame(np.random.randn(10,4).cumsum(0),
                 columns=['A', 'B', 'C', 'D'],
                  index=np.arange(0, 100, 10))
	df
    
>>> df.plot()

>>> df.plot(kind = 'bar')
    df.plot(kind = 'hist')
    df.plot(kind = 'box')
    df.plot(kind = 'kde')

② 막대 그래프 : .plot.bar() , .plot.barh()

누적 막대 그래프는 'stacked=True' 옵션을 사용해서 생성할 수 있는데, 각 로우의 값들이 하나의 막대에 누적되어 출력된다

>>> df = pd.DataFrame(np.random.randn(10,4).cumsum(0),
                 columns=['A', 'B', 'C', 'D'],
                  index=np.arange(0, 100, 10))
                  
>>> df.plot.bar()
	df.plot.barh()                  
>>> tips = pydataset.data('tips')
	tips
    
>>> pd.crosstab(tips['day'], tips['size'])    
>>> party_counts = pd.crosstab(tips['day'], tips['size'])

#각 로우의 합이 1이 되도록 정규화
>>> party_counts.div(party_counts.sum(axis = 1), axis = 0)
>>> party_pcts = party_counts.div(party_counts.sum(axis = 1), axis = 0)

>>> party_pcts.plot.bar(rot = 0)
	party_pcts.plot.barh()

파티의 규모가 주말에 커지는 경향이 있음을 알 수 있다
그래프를 그리기 전에 요약을 해야하는 데이터는 seaborn 패키지를 이용하면 간단하게 처리할 수 있다

>>> tips['tip_pct'] = tips['tip']/(tips['total_bill'] - tips['tip'])
	tips.head()
    
>>> tips['tip_pct'].plot.bar()
>>> sns.barplot(data = tips, x = 'day', y = 'tip_pct')
>>> sns.barplot(data = tips, x = 'tip_pct', y = 'day', orient = 'h')

seaborn 플로팅 함수의 data 인자는 pandas의 DataFrame을 받는다
막대 그래프 위에 덧그려진 검은 선은 95%의 신뢰구간을 나타낸다

③ 히스토그램

>>> tips['tip_pct'].plot.hist(bins = 50)

seaborn 라이브러리의 distplot 메서드를 이용해서 히스토그램과 밀도 그래프를 한번에 손 쉽게 그릴 수 있다

#두개의 다른 표준정규분포로 이루어진 양봉분포
>>> comp1 = np.random.normal(0,1,size =200)
>>> comp2 = np.random.normal(10,2,size =200)
>>> values = pd.Series(np.concatenate([comp1, comp2]))
>>> sns.distplot(values, bins = 100, color = 'k')

④ 패싯 그리드

다양한 범주형 값을 가지는 데이터를 시각화하는 방법
seaborn은 factorplot 이라는 내장 함수를 제공하여 다양한 면을 나타내는 그래프를 쉽게 그릴 수 있게 해준다

>>> sns.factorplot(data = tips[tips.tip_pct < 0.5], x = 'tip_pct', y = 'day', kind = 'box')
>>> sns.factorplot(data = tips[tips.tip_pct < 1], x = 'day', y = 'tip_pct', hue = 'time', col = 'smoker', kind = 'bar')
>>> sns.catplot(data = tips[tips.tip_pct < 0.5], x = 'tip_pct', y = 'day', kind = 'box')
                   
>>> tips[:5]
>>> tips.pivot(index = 'total_bill', columns = 'day', values = 'tip_pct')
>>> df = pd.read_excel('excel_exam.xlsx')
	df

>>> melted = df.melt(id_vars = 'class', value_vars = ['math', 'science', 'english'], var_name = '과목', value_name = '점수')
	melted
    
>>> melted.pivot(index = 'class', columns = '과목', values = '점수')

데이터 내에 같은 값을 가지는(같은 값이 있어 겹치는) 칼럼을 인덱스로 설정하려 해서 에러
melt 한 후 pivot 으로 다시 되돌리는 것이 안될 수도 있다

>>> pip install plotly
>>> import plotly.express as px

>>> g = px.data.gapminder()
	g[:3]
>>> g.info()   #RangeIndex: 1704 entries, 0 to 1703 -> 1704개의 로우가 있다    

>>> pd.pivot(data = g, index = 'country', columns = 'continent',
			values = 'year')    #같은 에러가 발생한다
            
#year, country, gdpPercap 을 이용하여 pivot 해 봅시다
>>> pd.pivot(data = g, index = 'year', columns = 'country', values = 'gdpPercap')
>>> pd.pivot(data = g, index = 'year', columns = 'country', values = ['gdpPercap', 'pop'])

>>> df1 = pd.pivot(data = g, index = 'year', columns = 'country', values = 'gdpPercap')
	df1
    
>>> df1.reset_index(inplace = True)
	df1    
>>> df1.columns[1:]    #df1의 column의 개수 확인

>>> df1.melt(id_vars = 'year', value_vars = df1.columns[1:], var_name = 'country', value_name = 'gdpPercap')

9. 데이터 집계와 그룹 연산

(1) groupby

① Series, DataFrame 같은 pandas 객체나, 다른 객체에 들어있는 데이터를 하나 이상의 '키' 를 기준으로 '분리' 한다
(하나의 축(로우 또는 칼럼)을 기준으로 분리할 수 있다)
② 함수를 각 그룹에 '적용' 시켜 새로운 값을 얻어낸다
③ 함수를 적용한 결과를 하나의 객체로 '결합' 한다

>>> df = pd.DataFrame({'key1': ['a', 'a', 'b',' b', 'a'],
                      'key2': ['one', 'two', 'one', 'two', 'one'],
                      'data1': np.random.randn(5),
                      'data2': np.random.randn(5)})
    df
    
#key1과 key2로 그룹짓고, min() 구하기
>>> df.groupby(['key1', 'key2']).min()
>>> df.groupby(['key1', 'key2']).mean()
>>> df.groupby(['key1', 'key2'])[['data2']].mean()

(2) 데이터 집계

배열로부터 스칼라값을 만들어내는 모든 데이터 변환 작업
mean, count, min, sum 등을 이용해서 스칼라 값을 구할 수 있다
직접 만든 함수를 사용할 수도 있다

  • 내부적으로 groupby는 Series를 효과적으로 잘게 자르고 각 조각에 대해 .quantile(0.9)를 호출한다. 그리고 이 결과들을 모두 하나의 객체로 합쳐서 반환한다
>>> df.groupby(['key1', 'key2']).quantile()
>>> df.groupby(['key1', 'key2'])[['data1']].quantile()

① 칼럼에 여러가지 함수 적용하기

  • 사용자 정의 함수 적용하기 : .agg()
>>> def peak_to_peak(arr):
    	return arr.max() - arr.min()
#.max() 와 .min() 은 전체 데이터 중에 max값과 min값 '하나'를 돌려준다

>>> df.groupby(['key1']).min()
>>> df.groupby(['key1']).apply(min)

>>> df.groupby(['key1']).apply(peak_to_peak)
#apply 로는 사용자 정의 함수를 적용할 수 없다

>>> df.groupby(['key1']).agg(peak_to_peak)
>>> list(df.groupby(['key1']))
  • 칼럼마다 다른 함수 적용하기 -> .agg() 에 칼럼 이름에 대응하는 함수가 들어있는 '사전' 을 입력한다
>>> tips = pydataset.data('tips')
    tips
    
>>> tips['tip_pct'] = tips['tip'] / tips['total_bill']
	tips.head()
    
>>> grouped = tips.groupby(['day', 'smoker'])
>>> grouped.agg({'tip' : np.max, 'size' : sum})
  • 여러 개의 함수를 모든 칼럼에 적용하기 -> .agg() 에 함수가 들어있는 '리스트' 를 입력한다
>>> grouped.agg(['count', 'mean', 'max'])
#함수 이름을 칼럼으로 하는 DataFrame 을 얻게 된다
  • 이름과 함수가 담긴 (name, function) 튜플의 리스트를 넘기면 칼럼의 이름을 변경할 수 있다
>>> gg = grouped.agg(['count', 'mean', 'max'])
>>> gg.agg([('ct', 'count'), ('mn', 'mean'), ('mx', 'max')])

(3) Apply : 일반적인 분리-적용-병합

apply 메서드는 객체를 여러 조각으로 나누고, 전달된 함수를 각 조각에 일괄 적용한 후 이를 다시 합친다

#그룹별 상위 5개의 tip_pct 값을 구해보자
>>> tips

>>> def top(df, n=5, column = 'tip_pct'):
		return df.sort_values(by = column)[-n:]
        
>>> top(tips)
>>> top(tips, n=10)

>>> def top(df, n=5, column = 'tip_pct'):
    	return df.sort_values(by=column, ascending = False)[:n]
        
>>> top(tips)
>>> tips.groupby(['day', 'smoker']).apply(top)

#apply 메서드로 넘길 함수가 추가적인 인자를 받는다면 함수 이름 뒤에 붙여서 넘겨준다
>>> tips.groupby(['day', 'smoker']).apply(top, n=2)
>>> tips.groupby(['day', 'smoker']).apply(top, n=2, column = 'tip')

① 변위치 분석과 버킷 분석

>>> tips['tip']

>>> pd.cut(tips['tip'], 4)
#균등한 간격의 4그룹으로 cut -> dtype는 'category', Categories는 '4'

#cut 에서 반환된 Categorical 객체는 바로 groupby로 넘길 수 있다
>>> grouping = pd.cut(tips['tip'], 4)
>>> grouped1 = tips.groupby(grouping)
>>> list(grouped1)

>>> grouped1.apply(top)
>>> grouped1.apply(top, n=2)

>>> def get_stats(group):
        return {'min' : group.min(), 'max' : group.max(),
               'count' : group.count(), 'mean' : group.mean()}
               
>>> grouped1.agg(get_stats)
>>> grouped1.apply(get_stats)

>>> grouped1 = tips['tip'].groupby(grouping)
	grouped1.apply(get_stats).unstack() 
>>> def test(a, b, c=3):
		return a + b+ c
        
>>> test(a=1, b=2, c=4)
7

>>> d = {'a' : 1, 'b' : 2, 'c' : 4}
	test(**d)    # ** : 입력되는 값이 dictionary 라는 의미
7    

② 예제1 그룹에 따른 값으로 결측치 채우기 : .fillna()

  • 누락된 값을 평균값으로 대체
>>> s = pd.Series(np.random.randn(6))
	s
    
>>> s[::2]
>>> s[::2] = np.nan
	s
    
>>> s.fillna(s.mean())    
  • 그룹별로 채워 넣고 싶은 값이 다른 경우 -> 데이터를 그룹으로 나누고, apply 함수를 사용해서 각 그룹에 대해 fillna 를 적용한다
>>> states = ['Ohio', 'New York', 'Vermont', 'Florida', 'Oregon', 'Nevada', 'California', 'Idaho']

>>> group_key = ['East'] * 4 + ['West'] * 4
	group_key
#['East'] * 4 는 ['East'] 리스트 안에 있는 네 벌의 원소를 이어붙인다

>>> data = pd.Series(np.random.randn(8), index = states)
	data
    
>>> data[['Vermont', 'Nevada', 'Idaho']] = np.nan
	data

>>> list(data.groupby(group_key))
#data가 'East'와 'West'라는 그룹 2개로 나뉘어진 것을 볼 수 있다
>>> data.groupby(group_key).mean()
#East와 West 그룹 각각에 mean() 함수 적용

#누락된 값에 각 그룹의 평균값으로 채운다
>>> data.groupby(group_key).apply(lambda g: g.fillna(g.mean()))

③ 예제2 랜덤 표본과 순열

대용량의 데이터를 다른 애플리케이션에서 사용하기 위해 랜덤 표본을 뽑아낸다고 하자.
Series의 sample 메서드를 사용하자

>>> suits = ['H','S','C','D']
    card_val = (list(range(1, 11)) + [10] *3) *4
    base_names = ['A'] + list(range(2, 11)) + ['J', 'K', 'Q']
    
>>> card_val
>>> base_names

>>> cards = []
    for suit in ['H','S','C','D']:
        cards.extend(str(num) + suit for num in base_names)
>>> cards

>>> deck = pd.Series(card_val, index = cards)
	deck
    
#5장의 코드 뽑기
>>> def draw(deck, n=5):
        return deck.sample(n)   
>>> draw(deck)

#각 세트(H, S, C, D) 별로 2장의 카드를 무작위로 뽑기
#세트는 각 카드 이름의 마지막 글자에 해당된다 -> card[-1]
>>> deck.groupby(lambda card: card[-1]).apply(draw, n=2)
>>> deck.groupby(lambda card: card[-1], group_keys = False).apply(draw, n=2)

0개의 댓글