Python Library/Pandas

[Pandas - Python] 지금까지의 예시 + 코드에 대한 설명

바보1 2022. 6. 16. 01:40
s = pd.Series(np.random.randn(6))		
s[::2] = np.nan		
s

0         NaN
1    0.050009
2         NaN
3    0.852965
4         NaN
5   -0.023493
dtype: float64

랜덤으로 6개의 숫자를 생성한 후, s에 Series로 할당했고,
2배 간격으로 0, 2, 4의 row에 NaN을 넣었습니다.

 

s.fillna(s.mean())


0    0.293160
1    0.050009
2    0.293160
3    0.852965
4    0.293160
5   -0.023493
dtype: float64

s의 평균을 fillna를 통해 넣었습니다.

 

또 다른 예시를 봅시다.

states = ['Ohio', 'New York', 'Vermont', 'Florida',
          'Oregon', 'Nevada', 'California', 'Idaho']
group_key = ['East'] * 4 + ['West'] * 4
data = pd.Series(np.random.randn(8), index=states)
data


Ohio         -2.304234
New York     -0.652469
Vermont      -1.218302
Florida      -1.332610
Oregon        1.074623
Nevada        0.723642
California    0.690002
Idaho         1.001543
dtype: float64

index에 states를 넣은 모습입니다.

 

data[['Vermont', 'Nevada', 'Idaho']] = np.nan
data


Ohio         -2.304234
New York     -0.652469
Vermont            NaN
Florida      -1.332610
Oregon        1.074623
Nevada             NaN
California    0.690002
Idaho              NaN
dtype: float64

이후 Vermont, ~~~ 에 NaN 데이터를 넣었습니다.

 

data.groupby(group_key).mean()


East   -1.429771
West    0.882312
dtype: float64

그 다음 group_key를 통해 각각 east, west를 4개씩 할당했고,

할당을 기준으로 그룹화 했습니다.

이후 그룹화된 그룹으로 평균을 출력하는 모습입니다.

 

fill_mean = lambda g: g.fillna(g.mean())
data.groupby(group_key).apply(fill_mean)


Ohio         -2.304234
New York     -0.652469
Vermont      -1.429771
Florida      -1.332610
Oregon        1.074623
Nevada        0.882312
California    0.690002
Idaho         0.882312
dtype: float64

아예 람다 함수를 만들어서 적용하는 모습입니다.

이때는 group_key를 기준으로 그룹화 했으므로, NaN 값에는 각 east, west의 인덱스에 해당하는 평균 값이 들어갑니다.

 

fill_values = {'East': 0.5, 'West': -1}
fill_func = lambda g: g.fillna(fill_values[g.name])
data.groupby(group_key).apply(fill_func)


Ohio         -2.304234
New York     -0.652469
Vermont       0.500000
Florida      -1.332610
Oregon        1.074623
Nevada       -1.000000
California    0.690002
Idaho        -1.000000
dtype: float64

# Hearts, Spades, Clubs, Diamonds
suits = ['H', 'S', 'C', 'D']
card_val = (list(range(1, 11)) + [10] * 3) * 4
base_names = ['A'] + list(range(2, 11)) + ['J', 'K', 'Q']
cards = []
for suit in ['H', 'S', 'C', 'D']:
    cards.extend(str(num) + suit for num in base_names)

deck = pd.Series(card_val, index=cards)
deck[:13]


AH      1
2H      2
3H      3
4H      4
5H      5
6H      6
7H      7
8H      8
9H      9
10H    10
JH     10
KH     10
QH     10
dtype: int64

우선 card_val에는 [1, 2, 3, 4, ,,,, 10, 10, 10, 10]이 4개나 들어가있고,

base_names에는 A, 1, 2, 3, ,,, 10, J, Q, K가 들어가 있습니다.

이후 for loop를 통해 card에 값을 넣어줍니다.

 

마지막으로 생성된 card를 인덱스로 하고, card_val을 데이터로 하는 Series를 생성했습니다.

def draw(deck, n=5):
    return deck.sample(n)
draw(deck)


AD     1
8C     8
5H     5
KC    10
2C     2
dtype: int64

무작위로 5개를 뽑았습니다.

 

get_suit = lambda card: card[-1] # last letter is suit
deck.groupby(get_suit).apply(draw, n=2)


C  2C     2
   3C     3
D  KD    10
   8D     8
H  KH    10
   3H     3
S  2S     2
   4S     4
dtype: int64

우선 get_suit는 마지막 문자를 대상으로 그룹화 하는 함수입니다.

이후, draw를 적용한 모습입니다.

 

deck.groupby(get_suit, group_keys=False).apply(draw, n=2)


KC    10
JC    10
AD     1
5D     5
5H     5
6H     6
7S     7
KS    10
dtype: int64

group_keys = False로 하니까 위의 계층적 인덱싱이 사라졌습니다.


df = pd.DataFrame({'category': ['a', 'a', 'a', 'a',
                                'b', 'b', 'b', 'b'],
                   'data': np.random.randn(8),
                   'weights': np.random.rand(8)})
df



       category		data		weights
0	a		1.561587	0.957515
1	a		1.219984	0.347267
2	a		-0.482239	0.581362
3	a		0.315667	0.217091
4	b		-0.047852	0.894406
5	b		-0.454145	0.918564
6	b		-0.556774	0.277825
7	b		0.253321	0.955905
grouped = df.groupby('category')
get_wavg = lambda g: np.average(g['data'], weights=g['weights'])
grouped.apply(get_wavg)


category
a    0.811643
b   -0.122262
dtype: float64

카테고리로 그룹화 했고, weight를 통해 가중치를 주고, 평균을 구한 모습입니다.

 

close_px = pd.read_csv('examples/stock_px_2.csv', parse_dates=True,
                       index_col=0)
close_px.info()
close_px[-4:]


<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 2214 entries, 2003-01-02 to 2011-10-14
Data columns (total 4 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   AAPL    2214 non-null   float64
 1   MSFT    2214 non-null   float64
 2   XOM     2214 non-null   float64
 3   SPX     2214 non-null   float64
dtypes: float64(4)
memory usage: 86.5 KB

		AAPL	MSFT	XOM	SPX
2011-10-11	400.29	27.00	76.27	1195.54
2011-10-12	402.19	26.96	77.16	1207.25
2011-10-13	408.43	27.18	76.37	1203.66
2011-10-14	422.00	27.27	78.11	1224.58

데이터를 불러왔습니다.

spx_corr = lambda x: x.corrwith(x['SPX'])
rets = close_px.pct_change().dropna()

get_year = lambda x: x.year
by_year = rets.groupby(get_year)
by_year.apply(spx_corr)


	AAPL		MSFT		XOM		SPX
2003	0.541124	0.745174	0.661265	1.0
2004	0.374283	0.588531	0.557742	1.0
2005	0.467540	0.562374	0.631010	1.0
2006	0.428267	0.406126	0.518514	1.0
2007	0.508118	0.658770	0.786264	1.0
2008	0.681434	0.804626	0.828303	1.0
2009	0.707103	0.654902	0.797921	1.0
2010	0.710105	0.730118	0.839057	1.0
2011	0.691931	0.800996	0.859975	1.0

자세히는 모르겠지만, rets는 close_px에 데이터를 퍼센트화 시키고, 결측치를 없앤 것 같습니다.

이후 이 데이터를 year을 기준으로 그룹화 시키고, 거기에 'SPX'와의 상관관계에 따라 정렬한 것 같습니다.

 

by_year.apply(lambda g: g['AAPL'].corr(g['MSFT']))


2003    0.480868
2004    0.259024
2005    0.300093
2006    0.161735
2007    0.417738
2008    0.611901
2009    0.432738
2010    0.571946
2011    0.581987
dtype: float64

 

 

 

 

여기서는 AAPL에 있어서, MSFT의 상관관계를 나타낸 것 같습니다.


import statsmodels.api as sm
def regress(data, yvar, xvars):
    Y = data[yvar]
    X = data[xvars]
    X['intercept'] = 1.
    result = sm.OLS(Y, X).fit()
    return result.params
    
by_year.apply(regress, 'AAPL', ['SPX'])



   	 SPX		intercept
2003	1.195406	0.000710
2004	1.363463	0.004201
2005	1.766415	0.003246
2006	1.645496	0.000080
2007	1.198761	0.003438
2008	0.968016	-0.001110
2009	0.879103	0.002954
2010	1.052608	0.001261
2011	0.806605	0.001514

음...