[자기주도 TIL] 10 minutes to pandas (1)

임종우·2022년 9월 22일
0

ai_school_TIL

목록 보기
3/34

매주 목요일 오후에는 자기주도 학습 시간에 학습한 내용을 적는 TIL을 작성하고, 링크를 제출하여야 한다고 한다!

시간이 부족해서 중간까지 밖에 못했지만 일단 정리하고 제출한 후 마저해야겠다.


근데 TIL이 이렇게 진행하는 게 맞는건지 모르겠다.
velog에 옮기는데 시간이 너무 걸리는거 같은데..?
안해봐서 어색해서 그렇겠지..!


10 Minutes to Pandas

python 공식 문서에 있는 초보자용 가이드!
코드와 간단한 설명이 나와있어, 해당 코드를 따라쳐보며 판다스에 대한 감을 잡아보기로 했다.
직접 jupyter에 쳐보며 실습하였고, 모르는 내용은 검색하며 정리하였다!

import numpy as np
import pandas as pd

numpypandas를 함께 import 하여 사용한다.

Object Creation

pandas의 data structre 인 SeriesDataFrame을 만들어본다.

s = pd.Series([1,3,5,np.nan,6,8])
s
>>>
0    1.0
1    3.0
2    5.0
3    NaN
4    6.0
5    8.0
dtype: float64

Seriesindexdata를 가진 1차원 벡터형 자료형임을 알 수 있다.

dates = pd.date_range("20130101",periods = 6)
dates
>>>
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
               '2013-01-05', '2013-01-06'],
              dtype='datetime64[ns]', freq='D')

Numpy array를 전달하여 DataFrame을 생성한다.
이때, date_range()를 이용해 datetime index를 가진 df를 만든다.
pandas의 date_range()는 날짜와 periods를 인자로 받아 해당 일자의 리스트를 만들어 주는 듯 하다.

df = pd.DataFrame(np.random.randn(6,4), index = dates, columns = list("ABCD"))
df
>>>
	A	B	C	D
2013-01-01	1.397870	1.781252	-0.181087	0.096765
2013-01-02	-0.797328	0.518531	-1.973643	-2.018436
2013-01-03	0.981060	0.731136	0.286162	-1.494021
2013-01-04	-0.293389	1.593434	1.016599	0.050886
2013-01-05	-0.242990	0.827032	-0.050350	-0.766830
2013-01-06	-0.587438	1.721439	0.258103	-0.264088

DataFrame을 만들었다. 전달해준 데이터는 np.random.randn(6,4)로,
numpy의 random.randn(가우시안 표준정규분포 생성)을 사용해 shape가 (6,4)인 nparray를 만들었다.

df2 = pd.DataFrame({
    "A" : 1.0,
    "B" : pd.Timestamp("20130102"),
    "C" : pd.Series(1, index = list(range(4)), dtype = "float32"),
    "D" : np.array([3]*4, dtype = int),
    "E" : pd.Categorical(["test","train","test","train"]),
    "F" : "foo",
})

df2
>>>

A	B	C	D	E	F
0	1.0	2013-01-02	1.0	3	test	foo
1	1.0	2013-01-02	1.0	3	train	foo
2	1.0	2013-01-02	1.0	3	test	foo
3	1.0	2013-01-02	1.0	3	train	foo

앞에서는 행렬 형태의 nparray를 전달해 DataFrame을 만들고, indexcolumn을 정해주었다면,
여기서는 직접 각 column에 들어갈 데이터들을 전달해 주어 df를 만들었다.
이때, df의 column에 들어갈 수 있는 여러 데이터 형식들로 series, nparray, float, str, Categorical이 있었다.

Categorical이란? 판다스에 존재하는 범주형 자료형. categories, codes 라는 속성을 가지며,
해당 속성을 이용하기 위해서는 .cat 접근자(accessor)를 사용해 주어야 한다.
.set_categories()등을 이용해 여러 카테고리의 이름을 지정해 줄 수 있다.
나중에 더 공부할 것 같으니 일단 여기까지!

아 그리고, 대체 foo가 뭐지..? 엥 홍길동 같이 의미 없는 문자열을 그냥 "foo"라고 쓴단다.

df2.dtypes
>>>
A           float64
B    datetime64[ns]
C           float32
D             int32
E          category
F            object
dtype: object

.dtypes 의 메소드로 각각 column 들의 dtype을 알아볼 수 있다.

Viewing Data

df.head()
>>>

A	B	C	D
2013-01-01	1.397870	1.781252	-0.181087	0.096765
2013-01-02	-0.797328	0.518531	-1.973643	-2.018436
2013-01-03	0.981060	0.731136	0.286162	-1.494021
2013-01-04	-0.293389	1.593434	1.016599	0.050886
2013-01-05	-0.242990	0.827032	-0.050350	-0.766830

상위 및 하위의 자료들만 보기 위해서는 .head()또는 .tail()을 사용한다.

df.columns
>>>
Index(['A', 'B', 'C', 'D'], dtype='object')

df.index 또는 df.columns 를 이용해 index 와 column을 살펴볼 수 있다.

df.to_numpy()
>>>
array([[ 1.39786968,  1.78125156, -0.18108725,  0.09676474],
       [-0.79732826,  0.5185311 , -1.97364305, -2.01843616],
       [ 0.98105995,  0.73113614,  0.28616178, -1.4940211 ],
       [-0.29338913,  1.59343441,  1.01659911,  0.05088553],
       [-0.24299026,  0.82703222, -0.05034992, -0.7668296 ],
       [-0.58743795,  1.72143897,  0.25810274, -0.26408754]])

df.to_numpy 를 사용하면, dataframe을 numpy array로 변환시켜 줄 수 있다.
이때, column 내에 다양한 dtype이 존재하면 실행이 오래 걸릴 수 있다.

df.describe()
>>>
	A	B	C	D
count	6.000000	6.000000	6.000000	6.000000
mean	0.076297	1.195471	-0.107369	-0.732621
std	0.895268	0.563517	1.004331	0.866661
min	-0.797328	0.518531	-1.973643	-2.018436
25%	-0.513926	0.755110	-0.148403	-1.312223
50%	-0.268190	1.210233	0.103876	-0.515459
75%	0.675047	1.689438	0.279147	-0.027858
max	1.397870	1.781252	1.016599	0.096765

df.describe()를 사용해 데이터의 기술 통계 값을 볼 수 있다.
이때, include = "object" 를 사용해 범주형 자료의 기술통계 값도 볼 수 있다.

df.T
>>>
	2013-01-01	2013-01-02	2013-01-03	2013-01-04	2013-01-05	2013-01-06
A	1.397870	-0.797328	0.981060	-0.293389	-0.242990	-0.587438
B	1.781252	0.518531	0.731136	1.593434	0.827032	1.721439
C	-0.181087	-1.973643	0.286162	1.016599	-0.050350	0.258103
D	0.096765	-2.018436	-1.494021	0.050886	-0.766830	-0.264088

.T 를 이용해 transpose 할 수 도 있다.

df.sort_index(axis=1, ascending = False)
>>>

D	C	B	A
2013-01-01	0.096765	-0.181087	1.781252	1.397870
2013-01-02	-2.018436	-1.973643	0.518531	-0.797328
2013-01-03	-1.494021	0.286162	0.731136	0.981060
2013-01-04	0.050886	1.016599	1.593434	-0.293389
2013-01-05	-0.766830	-0.050350	0.827032	-0.242990
2013-01-06	-0.264088	0.258103	1.721439	-0.587438

.sort_index() 또는 .sort_values를 통해 정렬할 수도 있다.
axis = 1 이므로 열 방향으로 정렬하는 모습이다.
기본값이 axis = 0, ascending = True 이다.

Selection

Getting

df["A"]
>>>
2013-01-01    1.397870
2013-01-02   -0.797328
2013-01-03    0.981060
2013-01-04   -0.293389
2013-01-05   -0.242990
2013-01-06   -0.587438
Freq: D, Name: A, dtype: float64

single column을 select 하기 위해서는 [](__getitem__)을 사용한다.
. 도 쓸 수 있지만, 컬럼 명에 특수문자가 들어갈 경우 오류가 생길 수 있으니 권장하지 않는다.

df["20130102":"20130104"]
>>>

A	B	C	D
2013-01-02	-0.797328	0.518531	-1.973643	-2.018436
2013-01-03	0.981060	0.731136	0.286162	-1.494021
2013-01-04	-0.293389	1.593434	1.016599	0.050886

한편, [] 를 이용해 slicing을 할 때에는, 열이 아닌 행이 slicing 된다.

selection by label

df.loc[dates[0]]
>>>
A    1.397870
B    1.781252
C   -0.181087
D    0.096765
Name: 2013-01-01 00:00:00, dtype: float64

.loc을 통해 selection by label을 할 수 있다.
index에 대해 선택한다고 생각할 수 있다.
이때 인자 값으로는 명시적이고 정확한 값이 사용된다.

df.loc[:,["A","B"]]
>>>

A	B
2013-01-01	1.397870	1.781252
2013-01-02	-0.797328	0.518531
2013-01-03	0.981060	0.731136
2013-01-04	-0.293389	1.593434
2013-01-05	-0.242990	0.827032
2013-01-06	-0.587438	1.721439

을 전체에 대해 slicing하고 에 대해 loc을 사용할 수 도 있다.
이때, 여러 column이나 index 에 대해 사용할 때에는 해당 이름으로 된 list를 만들어 사용한다.

df.loc["20130102":"20130104", ["A", "B"]]
>>>
	A	B
2013-01-02	-0.797328	0.518531
2013-01-03	0.981060	0.731136
2013-01-04	-0.293389	1.593434

loc의 slicing은 endpoints가 included 되어 실행된다.

df.loc["20130102",["A","B"]]
>>>
A   -0.797328
B    0.518531
Name: 2013-01-02 00:00:00, dtype: float64

만약 선택한 값이 Series로 표현되는 형태 일 경우, 자료형이 Series로 바뀌는 reduction in the dimensions 가 일어난다.

selection by position

df.iloc[3]
>>>
A   -0.293389
B    1.593434
C    1.016599
D    0.050886
Name: 2013-01-04 00:00:00, dtype: float64

명시적 방법이 아닌, selection by position 을 위해서는 iloc을 사용한다.

df.iloc[3:5,0:2]
>>>
	A	B
2013-01-04	-0.293389	1.593434
2013-01-05	-0.242990	0.827032

iloc 에서의 slicing은 end point가 포함되지 않고 진행된다.

df.iloc[[1,2,4],[0,2]]
>>>
	A	C
2013-01-02	-0.797328	-1.973643
2013-01-03	0.981060	0.286162
2013-01-05	-0.242990	-0.050350

다음과 같이 fancy indexing을 사용할 수도 있다.

boolean indexing

df[df["A"]>0]
>>>
	A	B	C	D
2013-01-01	1.39787	1.781252	-0.181087	0.096765
2013-01-03	0.98106	0.731136	0.286162	-1.494021

특정 조건에 만족하는 자료들만 select 하기 위해서는 boolean indexing을 사용한다.
[] 안에 조건식을 넣어주면 된다.

df[df>0]
>>>
	A	B	C	D
2013-01-01	1.39787	1.781252	NaN	0.096765
2013-01-02	NaN	0.518531	NaN	NaN
2013-01-03	0.98106	0.731136	0.286162	NaN
2013-01-04	NaN	1.593434	1.016599	0.050886
2013-01-05	NaN	0.827032	NaN	NaN
2013-01-06	NaN	1.721439	0.258103	NaN

전체 df에서, 각 value의 값이 조건을 충족하는 것만 select하기 위해서는 다음과 같이 할 수 있다.

df2 = df.copy()
df2["E"] = ["one", "one", "two", "three", "four", "three"]
df2
>>>

A	B	C	D	E
2013-01-01	1.397870	1.781252	-0.181087	0.096765	one
2013-01-02	-0.797328	0.518531	-1.973643	-2.018436	one
2013-01-03	0.981060	0.731136	0.286162	-1.494021	two
2013-01-04	-0.293389	1.593434	1.016599	0.050886	three
2013-01-05	-0.242990	0.827032	-0.050350	-0.766830	four
2013-01-06	-0.587438	1.721439	0.258103	-0.264088	three

df2[df2["E"].isin(["two","four"])]
>>>
	A	B	C	D	E
2013-01-03	0.98106	0.731136	0.286162	-1.494021	two
2013-01-05	-0.24299	0.827032	-0.050350	-0.766830	four

filtering을 위해서 .isin() method를 사용한다.
.isin() method는 다음과 같이 사용할 수 있다. .isin([포함될 값들의 list]) -> 각 자료별로 T/F를 반환한다.

Setting

s1 = pd.Series([1, 2, 3, 4, 5, 6], index=pd.date_range("20130102", periods=6))
df["F"] = s1
df
>>>
A	B	C	D	F
2013-01-01	1.397870	1.781252	-0.181087	0.096765	NaN
2013-01-02	-0.797328	0.518531	-1.973643	-2.018436	1.0
2013-01-03	0.981060	0.731136	0.286162	-1.494021	2.0
2013-01-04	-0.293389	1.593434	1.016599	0.050886	3.0
2013-01-05	-0.242990	0.827032	-0.050350	-0.766830	4.0
2013-01-06	-0.587438	1.721439	0.258103	-0.264088	5.0

새로운 column을 추가하기 위해서는 df["new"] = data와 같이 정의해주기만 하면 된다.

df.loc[dates[0], "A"] = 0
df.iloc[0, 1] = 0
df
>>>
A	B	C	D	F
2013-01-01	0.000000	0.000000	-0.181087	0.096765	NaN
2013-01-02	-0.797328	0.518531	-1.973643	-2.018436	1.0
2013-01-03	0.981060	0.731136	0.286162	-1.494021	2.0
2013-01-04	-0.293389	1.593434	1.016599	0.050886	3.0
2013-01-05	-0.242990	0.827032	-0.050350	-0.766830	4.0
2013-01-06	-0.587438	1.721439	0.258103	-0.264088	5.0

특정 위치의 값을 바꾸어주기 위해서는 그 위치로 접근하여 바꾸어주면 된다.

df.loc[:, "D"] = np.array([5] * len(df))
df
>>>

A	B	C	D	F
2013-01-01	0.000000	0.000000	-0.181087	5	NaN
2013-01-02	-0.797328	0.518531	-1.973643	5	1.0
2013-01-03	0.981060	0.731136	0.286162	5	2.0
2013-01-04	-0.293389	1.593434	1.016599	5	3.0
2013-01-05	-0.242990	0.827032	-0.050350	5	4.0
2013-01-06	-0.587438	1.721439	0.258103	5	5.0

행이나 열 전체를 바꾸어 줄 수도 있다. len(df)는 행의 개수를 의미한다.

df2 = df.copy()
df2[df2>0] = -df2
df2
>>>
A	B	C	D	F
2013-01-01	0.000000	0.000000	-0.181087	-5	NaN
2013-01-02	-0.797328	-0.518531	-1.973643	-5	-1.0
2013-01-03	-0.981060	-0.731136	-0.286162	-5	-2.0
2013-01-04	-0.293389	-1.593434	-1.016599	-5	-3.0
2013-01-05	-0.242990	-0.827032	-0.050350	-5	-4.0
2013-01-06	-0.587438	-1.721439	-0.258103	-5	-5.0

다음과 같이 사용할 수도 있다.

Missing data

결측값을 표시하기 위해서는 주로 np.nan을 사용한다.

df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ["E"])
df1.loc[dates[0]:dates[1],"E"] = 1
df1
A	B	C	D	F	E
2013-01-01	0.000000	0.000000	-0.181087	5	NaN	1.0
2013-01-02	-0.797328	0.518531	-1.973643	5	1.0	1.0
2013-01-03	0.981060	0.731136	0.286162	5	2.0	NaN
2013-01-04	-0.293389	1.593434	1.016599	5	3.0	NaN
>>>

.reindex은 index를 추가, 변경, 삭제 할 수 있는 메소드로, data의 copy를 제공한다.
결측값이 존재하는 df를 만들어주었다. (F의 0, E의 2,3)

df1.dropna(how = "any")
>>>

A	B	C	D	F	E
2013-01-02	-0.797328	0.518531	-1.973643	5	1.0	1.0

결측값 삭제
df.dropna()를 사용하면 결측값이 있는 모든 행을 삭제한다.(기본)
axis인자로 열을 삭제하게 바꿀 수 도 있다.
how = "any" 또는 all로 지정하여 한 값이라도 결측값일때, 혹은 모든 값이 결측값일때 삭제해주도록 변경한다.

df1.fillna(value=5)
>>>

A	B	C	D	F	E
2013-01-01	0.000000	0.000000	-0.181087	5	5.0	1.0
2013-01-02	-0.797328	0.518531	-1.973643	5	1.0	1.0
2013-01-03	0.981060	0.731136	0.286162	5	2.0	5.0
2013-01-04	-0.293389	1.593434	1.016599	5	3.0	5.0

결측값 메꾸기
.fillna()를 사용하면 결측값을 메꾸어 준다.
이때 값으로 평균이나 중간값을 사용할 수도 있겠다.

df.isna()
>>>
	A	B	C	D	F
2013-01-01	False	False	False	False	True
2013-01-02	False	False	False	False	False
2013-01-03	False	False	False	False	False
2013-01-04	False	False	False	False	False
2013-01-05	False	False	False	False	False
2013-01-06	False	False	False	False	False

.isna() 는 모든 df에 대해 nan인지 여부를 boolean으로 표현해준다. 아까의 isin과 비슷하다!

Operations

Stats

df.mean()
>>>
A   -0.156681
B    0.898595
C   -0.107369
D    5.000000
F    3.000000
dtype: float64

df.mean() 으로 column 별 평균을 계산한다.

df.mean(1)
>>>
2013-01-01    1.204728
2013-01-02    0.749512
2013-01-03    1.799672
2013-01-04    2.063329
2013-01-05    1.906738
2013-01-06    2.278421
Freq: D, dtype: float64

다른 axis에 대해 수행해줄 수도 있다.

s = pd.Series([1, 3, 5, np.nan, 6, 8], index=dates).shift(2)
s
>>>
2013-01-01    NaN
2013-01-02    NaN
2013-01-03    1.0
2013-01-04    3.0
2013-01-05    5.0
2013-01-06    NaN
Freq: D, dtype: float64


df.sub(s, axis="index")
>>>
A	B	C	D	F
2013-01-01	NaN	NaN	NaN	NaN	NaN
2013-01-02	NaN	NaN	NaN	NaN	NaN
2013-01-03	-0.018940	-0.268864	-0.713838	4.0	1.0
2013-01-04	-3.293389	-1.406566	-1.983401	2.0	0.0
2013-01-05	-5.242990	-4.172968	-5.050350	0.0	-1.0
2013-01-06	NaN	NaN	NaN	NaN	NaN

만약 다른 차원의 값이거나 정렬이 필요하면, 판다스가 자동으로 broadcasting 하여 진행한다.

index 별로 series s를 빼주는 연산. 이때, nan이 모두 nan이 된다.

Apply

df.apply(np.cumsum)
>>>
A	B	C	D	F
2013-01-01	0.000000	0.000000	-0.181087	5	NaN
2013-01-02	-0.797328	0.518531	-2.154730	10	1.0
2013-01-03	0.183732	1.249667	-1.868569	15	3.0
2013-01-04	-0.109657	2.843102	-0.851969	20	6.0
2013-01-05	-0.352648	3.670134	-0.902319	25	10.0
2013-01-06	-0.940086	5.391573	-0.644217	30	15.0

df.apply() 를 사용하여 data에 user defined function을 적용시킬 수 있다.
함수를 정의하여서도, lambda 함수와도 많이 사용한다.
np.cumsum 은 축적된 합(cumulative sum)을 구한다.
column 에 대해 적용된다.

df.apply(lambda x : x.max() - x.min())
>>>
A    1.778388
B    1.721439
C    2.990242
D    0.000000
F    4.000000
dtype: float64

lambda 함수와 함께 사용한다.

Histogramming

s = pd.Series(np.random.randint(0, 7, size=10))
s.value_counts()
>>>
3    2
1    2
2    2
0    2
5    1
6    1
dtype: int64

.value_counts()를 사용해 도수를 구할 수 있다.
normalize = True를 인자로 주어 상대도수를 알 수도 있다.(비율)

String Methods

s = pd.Series(["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"])
s.str.lower()
>>>
0       a
1       b
2       c
3    aaba
4    baca
5     NaN
6    caba
7     dog
8     cat
dtype: object

.str 접근자를 사용하여 다양한 string method를 사용한다.
pattern matching 에 대해 정규표현식을 사용하기도 한다.


오늘은 이렇게 python의 operation 기능까지 10 minutes to pandas를 통해 알아보았다.
기본을 파악했으니, 자세히 공부하고 실습을 진행하며 다져나가자!

[참고] 10 minutes to pandas

profile
ai school 기간 동안의 TIL!

0개의 댓글