Tools/Python (38)

반응형

Pandas (Python Data Analysis Library)


파이썬을 통해 데이터 분석을 할 때, Pandas를 빼놓고 이야기할 수 없다. 온전히 통계 분석을 위해 고안된 R 과는 다르게 python은 일반적인 프로그래밍 언어(general purpose programming language) 이며, 데이터 분석을 하기 위해서는 여러가지 라이브러리를 사용할 수 밖에 없다. 이 패키지들 중 R의 dataframe 데이터 타입을 참고하여 만든 것이 바로 pandas dataframe이다. pandas는 dataframe을 주로 다루기 위한 라이브러리이며, dataframe을 자유롭게 가공하는 것은 데이터 과학자들에게 중요하다. 물론 pandas의 문법을 외우지 않고, 필요할 때마다 책이나 웹에서 찾아가면서 해도 좋지만 자주 사용하는 조작법을 외운다면 안 그래도 귀찮은 데이터 핸들링 작업을 빠르게 할 수 있다.


그래서 본 포스팅에서는 pandas dataframe을 다루는 법을 간단하게 정리해보고자 한다. 

본 포스팅은 이 튜토리얼을 참고하였다. 



Tabular Data type


Pandas Dataframe은 테이블 형식의 데이터 (tabular, rectangular grid 등으로 불림)를 다룰 때 사용한다. pandas dataframe의 3요소는 컬럼, 데이터(로우), 인덱스가 있다. 그리고 파이썬의 기본 데이터 타입으로 list, tuple, dictionary가 있다는 것도 다시 한 번 떠올리고 바로 튜토리얼을 해보자. 본 튜토리얼은 jupyter notebook, python3 환경에서 작성되었다.


1. Pandas Dataframe 만들기


pandas dataframe은 다양한 데이터 타입으로부터 만들 수 있다. ndarray, dictionary, dataframe, series, list의 예를 들고 있다.(IPython의 display 함수는 IPython 쉘 환경에서 pandas dataframe을 테이블 형식으로 표현해준다.)


# 1. Create Pandas Dataframe
from IPython.display import display
# Take a 2D array as input to your DataFrame 
my_2darray = np.array([[1, 2, 3], [4, 5, 6]])
display(pd.DataFrame(my_2darray))

# Take a dictionary as input to your DataFrame 
my_dict = {"a": ['1', '3'], "b": ['1', '2'], "c": ['2', '4']}
display(pd.DataFrame(my_dict))

# Take a DataFrame as input to your DataFrame 
my_df = pd.DataFrame(data=[4,5,6,7], index=range(0,4), columns=['A'])
display(pd.DataFrame(my_df))

# Take a Series as input to your DataFrame
my_series = pd.Series({"United Kingdom":"London", "India":"New Delhi", "United States":"Washington", "Belgium":"Brussels"})
display(pd.DataFrame(my_series))


01

1

abc
0112
1324
A
04
15
26
37
BelgiumBrussels
IndiaNew Delhi
United KingdomLondon
United StatesWashington


Series의 경우 pandas에서 제공하는 데이터타입인데, index가 있는 1차원 배열이라고 생각하면 좋다. 문자, 논리형, 숫자 모든 데이터타입이 들어갈 수 있다. dataframe의 한 컬럼, 한 컬럼이 series이다.


Dataframe 간단하게 살펴보기


df.shape를 통해 dataframe의 row와 column 수를 알 수 있다. .index를 통해 index를 알 수 있으며, len을 통해 dataframe의 길이(row의 갯수)를 알 수 있다.


df = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6]]))

# Use the `shape` property
print(df.shape)

# Or use the `len()` function with the `index` property
print(len(df.index))


(2, 3)
2


list(df.columns)


[0, 1, 2]



2. Dataframe에서 특정 컬럼이나 로우(인덱스) 선택하기


실무적으로 가장 많이 사용되는 부분중 하나는 바로 Dataframe에서 특정 컬럼이나 로우를 선택하여 그 값을 보는 것이다. pandas에서는 상당히 다양한 방법들이 있다. 대표적으로 iloc, loc, ix 등을 통해서 할 수 있다. 필자는 column을 조회할때 df['column'], row를 조회할 때는 df.ix[index]를 많이 사용한다. 가장 짧고 기억하기 쉽다.


우선 파이썬 기본 데이터 타입인 dictionary 데이터 타입을 통해 dataframe을 만든다. 


df = pd.DataFrame({"A":[1,4,7], "B":[2,5,8], "C":[3,6,9]})


# Use `iloc[]` to select a row
display(df.iloc[0])
display(df.loc[0])
display(df.ix[0])

# Use `loc[]` to select a column
display(df.loc[:,'A'])
display(df['A'])

# 특정 row, column을 선택하기
display(df.ix[0]['A'])
display(df.loc[0]['B'])


A    1
B    2
C    3
Name: 0, dtype: int64

A 1 B 2 C 3 Name: 0, dtype: int64

A 1 B 2 C 3 Name: 0, dtype: int64

0 1 1 4 2 7 Name: A, dtype: int64

0 1 1 4 2 7 Name: A, dtype: int64

1

2


3. Dataframe에 컬럼, 로우, 인덱스 추가하기


2에서는 Dataframe의 특정 컬럼, 로우에 접근하는 방법을 알아보았고, 이제 데이터를 추가하거나 수정, 삭제하는 실제 작업 방법을 알아보자.


인덱스 설정하기


pandas는 기본적으로 row에 인덱스를 0부터 차례대로 자연수를 부여한다. 이를 변경하는 방법은 set_index 함수를 이용하는 것이다. 아래의 df.set_index('A')는 A 컬럼을 인덱스로 지정하는 것을 뜻한다. 그러면 3개의 row에 대하여 인덱스가 1,4,7이 부여된다. 


# Print out your DataFrame `df` to check it out
df = pd.DataFrame({"A":[1,4,7], "B":[2,5,8], "C":[3,6,9]})
display(df)

# Set 'C' as the index of your DataFrame
df = df.set_index('A')
display(df)


 

A

B
 0 1 2 3
 1 4 5 6
 2 7 8 9
BC
A
123
456
789

인덱스 접근하기 (ix와 iloc의 차이점)

인덱스를 접근하는 방법에 여러가지가 있다. ix, loc, iloc 등을 쓸 수 있다. 필자는 ix를 주로 쓴다. ix와 iloc의 차이점은 iloc은 인덱스와 상관 없이 순서를 보고 row를 불러온다. 아래 코드에서 ix[7]은 index가 7인 로우를 불러오는 것이며, iloc[1]은 1번째 로우를 불러오는 것이다. (0번째 로우부터 시작) 근데 ix의 경우 주의할점은 index가 integer로만 이루어진 경우에는 index로 접근하지만, index에 문자가 껴있으면 순서로 접근한다는 점이다.  

print(df.ix[7])
print(df.iloc[1])

B    8
C    9
Name: 7, dtype: int64
B    5
C    6
Name: 4, dtype: int64


예를 들어, 아래 코드를 보면, 인덱스를 문자와 숫자가 혼합된 형태로 주었다. 이 때 ix[2]로 로우를 부르면 인덱스가 아니라 순서로 로우를 불러오게된다. 


df = pd.DataFrame(data=np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), index= [2, 'A', 4], columns=[48, 49, 50])

display(df)
# Pass `2` to `loc`
print(df.loc[2])

# Pass `2` to `iloc`
print(df.iloc[2])

# Pass `2` to `ix`
print(df.ix[2])



48

49

50 

 2

 1 2 3
 A 4 5  6
 4 7 8 9
48    1
49    2
50    3
Name: 2, dtype: int64
48    7
49    8
50    9
Name: 4, dtype: int64
48    7
49    8
50    9
Name: 4, dtype: int64


로우 추가하기


ix의 경우 df.ix[2]를 입력하면 index=2인 곳의 row를 교체한다. 만약 index=2인 row가 없다면 position=2에 row를 추가하게 된다. loc을 사용하면 새로운 index=2인 row를 만들고, 그 곳에 row를 추가하게 된다. 


df = pd.DataFrame(data=np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), index= [2.5, 12.6, 4.8], columns=[48, 49, 50])
display(df)

# There's no index labeled `2`, so you will change the index at position `2`
df.ix[2] = [60, 50, 40]
display(df)

# This will make an index labeled `2` and add the new values
df.loc[2] = [11, 12, 13]
display(df)


Append를 이용해 로우 추가하기


때론 인덱스를 신경쓰지 않고 그냥 데이터의 가장 뒤에 row를 추가하고 싶을 수도 있다. 이 경우에는 append를 사용하면 좋다. 아래는 df 데이터프레임에 a를 추가하여 row를 추가하는 코드를 보여준다. row를 추가한 후에 reset index를 통해 index를 0부터 새롭게 지정한다. 이는 실제 작업할 때 많이 쓰는 테크닉이다. 


df = pd.DataFrame(data=np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=[48, 49, 50])
display(df)

a = pd.DataFrame(data=[[1,2,3]], columns=[48,49,50])
display(a)

df = df.append(a)
df = df.reset_index(drop=True)
display(df)




48 

4950
 0  1 2 3
 1 4 5 6
 2 7 8 9
484950
0123



48 4950
 0  1 2 3
 1 4 5 6
 2 7 8 9
 3 1 2 3



컬럼 추가하기


컬럼을 추가하는 방법도 여러가지가 있다. 아래는 loc을 통해 추가하거나, df['column']을 통해 추가하는 방법이다.


df = pd.DataFrame(data=np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=['A', 'B', 'C'])

# Study the DataFrame `df`
display(df)

# Append a column to `df`
df.loc[:, 'D'] = pd.Series(['5', '6', '7'], index=df.index)

# Print out `df` again to see the changes
display(df)

df['E'] = pd.Series(['5', '6', '7'], index=df.index)
display(df)



 A BC
 0 1 2 3
 1 4 5 6
 2 7 8

ABCD
01235
14566
27897

ABCDE
012355
145666
278977



4. Dataframe의 인덱스, 컬럼, 데이터 삭제하기


인덱스 삭제


인덱스를 지워야할 경우는 그렇게 많지 않을 것이다. 주로 reset_index를 이용해서 index를 리셋하는 것을 많이 사용한다. 혹은 index의 이름을 삭제하고 싶다면 del df.index.name을 통해 인덱스의 이름을 삭제할 수 있다. 


컬럼 삭제


drop 명령어를 통해 컬럼 전체를 삭제할 수 있다. axis=1은 컬럼을 뜻한다. axis=0인 경우, 로우를 삭제하며 이것이 디폴트이다. inplace의 경우 drop한 후의 데이터프레임으로 기존 데이터프레임을 대체하겠다는 뜻이다. 즉, 아래의 inplace=True는 df = df.drop('A', axis=1)과 같다.


df = pd.DataFrame(data=np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=['A', 'B', 'C'])
display(df)

# Drop the column with label 'A'              
# drop axis의 경우 column이면 1, row이면 0이다.
df.drop('A', axis=1, inplace=True)
display(df)




A

B

 0 1 2
 1 4

6

 2 7 8
BC
023
156
289


로우 삭제


- 중복 로우 삭제


drop_duplicate를 사용하면 특정 컬럼의 값이 중복된 로우를 제거할 수 있다. keep 키워드를 통해 중복된 것들 중 어떤 걸 킵할지 정할 수 있다.


df = pd.DataFrame(data=np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [40, 50, 60], [23, 35, 37]]), 
                  index= [2.5, 12.6, 4.8, 4.8, 2.5], 
                  columns=[48, 49, 50])

display(df)

df = df.reset_index()
display(df)

df = df.drop_duplicates(subset='index', keep='last').set_index('index')
display(df)




48

49 50
 2.5 1 2 3

12.6 

 5 6
 4.8 7

8

 4.840 50 60 
 2.523 35 37 

index484950
02.5123
112.6456
24.8789
34.8405060
42.5233537

484950
index
12.6456
4.8405060
2.5233537


- 인덱스를 통한 로우 삭제


drop 명령어를 통해 특정 index를 가진 row를 삭제할 수 있다. df.index[1] 명령어는 1번 째 위치에 있는 index를 가져온다. 가져온 이 index를 drop에 인풋으로 넣어주면 해당 index를 가진 row를 삭제할 수 있다.


# Check out your DataFrame `df`
df = pd.DataFrame(data=np.array([[1, 2, 3], [1, 5, 6], [7, 8, 9]]), columns=['A', 'B', 'C'])
display(df)

# Drop the index at position 1
print(df.index[1])
print(df.drop(df.index[1]))
print(df.drop(0))



A

 B

C
 0 1 
 1 1 5 6
 2 7


   A  B  C
0  1  2  3
2  7  8  9
   A  B  C
1  1  5  6
2  7  8  9

데이터 수정하기


특정 컬럼, 로우의 데이터를 수정하고 싶으면 ix 를 이용하면 편하다. 아래 코드는 인덱스=0, 컬럼=A의 데이터를 0으로 수정한다. 


df = pd.DataFrame(data=np.array([[1, 2, 3], [1, 5, 6], [7, 8, 9]]), columns=['A', 'B', 'C'])
display(df)

df.ix[0]['A'] = 0
display(df)




A

 B

C
 0 1 
 1 1 5 6
 2 7
ABC
0023
1156
2789


반응형
반응형


Python 중고급 - 정규표현식, 클래스



정규 표현식


파이썬에서 정규표현식을 이용하는 것은 re 라이브러리를 이용하면 된다. import re 구문으로 re 라이브러리를 임포트할 수 있다. 


print(all([not re.match("a", "cat"), # cat은 a로 시작하지 않는다.
          re.search("a", "cat"), # cat에 a가 존재하기 때문에 
          not re.search("c", "dog"), # c가 dog에 존재하지 않기 때문에
          3 == len(re.split("[ab]", "carbs")), # a,b로 나누면 'c', 'r', 's' 를 원소로 하는 list가 생성된다.
          "R-D-" == re.sub("[0-9]", "-", "R2D2")])) # sub를 통해 숫자를 -로 대체


객체 지향 프로그래밍


Stack 자료구조를 파이썬의 객체 지향을 이용해서 간단하게 구현하였다. add 함수는 stack에 데이터를 저장하고, pop 함수는 stack의 가장 위에 있는 데이터를 삭제한다. stack은 파이썬의 기본 자료구조인 list를 이용하여 구현하였다. 


class stack : 
    def __init__(self) : 
        "이것은 생성자이다."
        self.list = []
        self.length = 0
        
    def add(self, value) :
        self.list.append(value)
        self.length += 1
    
    def pop(self) : 
        del self.list[self.length-1]
        
    def __repr__(self) : 
        """ 파이썬 프롬프트에서 이 함수를 입력하거나 str()으로 보내주면
            Set 객체를 문자열로 표현해줌 """
        return "Stack : " + str(self.list)


my_stack = stack()

my_stack.add(value=3)
print(my_stack)


Stack : [3]


my_stack.add(value=5)

print(my_stack)


Stack : [3, 5]


my_stack.pop()

print(my_stack)


Stack : [3]


반응형
반응형


Python “SSL: CERTIFICATE_VERIFY_FAILED” Error 해결법


Keras에서 ResNet의 weight를 다운 받다가 이러한 에러가 났다. 환경은 리눅스, 파이썬 3 버전이다.


base_model = ResNet50(weights='imagenet', pooling=max, include_top = False) 


이 코드를 실행시키다가 에러가 났는데 h5 파일을 다운 받아야하는데, SSL certificate 문제가 있다면서 다운을 받지 못하는 문제이다. 

http://blog.pengyifan.com/how-to-fix-python-ssl-certificate_verify_failed/


위 링크를 보고 해결하였는데, 


첫번째 해결법은 PYTHONHTTPSVERIFY 환경변수를 0으로 설정하는 방법이다.


export PYTHONHTTPSVERIFY=0
python your_script


두 번재 해결법은 대안적인 방법으로 문제가 있는 코드 앞에 아래 코드를 넣는 방법이다. 


import os, ssl
if (not os.environ.get('PYTHONHTTPSVERIFY', '') and
    getattr(ssl, '_create_unverified_context', None)):
    ssl._create_default_https_context = ssl._create_unverified_context


반응형
반응형



Python - Pandas isin 구문


Python에서 테이블 형식의 데이터를 읽고 처리할 때 가장 많이 쓰이는 pandas 라이브러리에서는 다양한 데이터 처리 기능을 구현하고 있다. 이 중에 isin 구문은 열이 list의 값들을 포함하고 있는 모든 행들을 골라낼 때 주로 쓰인다. 


예를 들어, 아래 예제를 보면


df = DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})
df.isin([1, 3, 12, 'a'])


이와 같이 이진값을 반환한다. 

       A      B
0   True   True
1  False  False
2   True  False

이를 그대로 쓰는 경우보다 Dataframe의 컬럼에서 어떤 list의 값을 포함하고 있는것만 걸러낼 때 isin 구문이 유용하다.


이러한 데이터프레임이 있을 때

df = pd.DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})

AB
01a
12b
23f


A 컬럼의 값이 [1,3,12]를 포함하는 것만 골라낸다.

df[df['A'].isin([1, 3, 12])]
AB
01a
23f


반응형
반응형

Python - sklearn LabelEncoder, OnehotEncoder 사용


python에서 범주형 변수를 인코딩 하기 위하여 더미변수를 만들거나, one hot encoding을 합니다. 선형회귀 같은 기본적인 통계 모형에서는 더미변수를 많이 쓰지만, 일반적인 머신러닝/딥러닝 접근법에서는 one hot encoding을 많이합니다. one hot encoding을 하기위해서는 직접 함수를 만들어 할 수도 있지만 패키지를 사용하면 편합니다. 가장 편하다고 생각하는 방법이 바로 sklearn 패키지를 통한 one hot encoding 인데요. 예를 들어 아래와 같은 info라는 이름의 pandas dataframe 이 있을 때, class2를 예측변수 y라고 생각하여 one hot encoding 하는 방법을 알아보겠습니다.



id tissue class class2 x y r
0 mdb001 G CIRC B 535 425 197.0
1 mdb002 G CIRC B 522 280 69.0
2 mdb003 D NORM N NaN NaN NaN
3 mdb004 D NORM N NaN NaN NaN
4 mdb005 F CIRC B 477 133 30.0
5 mdb005 F CIRC B 500 168 26.0


Code

from sklearn import preprocessing label_encoder = preprocessing.LabelEncoder() onehot_encoder = preprocessing.OneHotEncoder() train_y = label_encoder.fit_transform(info['class2']) train_y = train_y.reshape(len(train_y), 1) train_y = onehot_encoder.fit_transform(train_y)

LabelEncoder 결과


[0 0 2 2 0 0 2 2 2 2 0 2 0 0 2 0 2 0 2 0 2 0 2 1 2 0 2 2 1 2 0 2 0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 0 2 2 2 0 2 2 2 2 2 0 2 2 1 2 2 1 2 2 2 2 0 0 2 0 2 2 2 2 2


OnehotEncoder 결과 - 최종 train_y

(0, 0) 1.0 (1, 0) 1.0 (2, 2) 1.0 (3, 2) 1.0 (4, 0) 1.0 (5, 0) 1.0 (6, 2) 1.0 (7, 2) 1.0 (8, 2) 1.0 (9, 2) 1.0 (10, 0) 1.0 (11, 2) 1.0 (12, 0) 1.0 (13, 0) 1.0

몇 줄 되지 않는 코드로 이처럼 one hot encoding을 구현할 수 있습니다. one hot encoding을 하기 전에 label encoding을 하는 이유는 one hot encoder의 인풋으로 숫자형만 올 수 있기 때문입니다. label encoder의 결과로 문자형 변수가 숫자형 변수 범주형으로 변경되게 되고 이를 one hot encoder에 fit_transform 해주면, 이와 같이 one hot encoding된 결과를 얻을 수 있습니다. 이 때, train_y 변수는 sparse matrix가되어 프린트하면 위와같이 나타납니다. 이는 matrix의 인덱스와 그에 해당하는 value를 나타낸건데 매트릭스에 값을 대입해보면 labelencoder 결과에 onehot encoding이 적용된 것을 확인할 수 있습니다.





반응형

'Tools > Python' 카테고리의 다른 글

Python - SSL 에러 해결  (1) 2018.03.04
Python - Pandas isin 구문  (0) 2018.02.25
Python - 폴더 파일 리스트 가져오기  (4) 2017.10.31
Python - Pandas 변수 정렬하기  (0) 2017.10.24
Python - Pandas 그룹별 평균 구하기  (2) 2017.10.24
반응형

Python - 폴더 파일 리스트 가져오기


python에서 운영체제 폴더 아래의 파일들을 불러올 때는 os 패키지를 이용한다. 아래 코드에서 filepath 부분에 운영체제 상에 폴더 path를 적으면 폴더 내부의 파일 이름을 가져올 수 있다.

from os import listdir
from os.path import isfile, join
files = [f for f in listdir('filepath') if isfile(join('filepath', f))]
['Info.txt',
 'Licence.txt',
 'mdb001.pgm',
 'mdb002.pgm',
 'mdb003.pgm',
 'mdb004.pgm',
 'mdb005.pgm',
 'mdb006.pgm',
 'mdb007.pgm',
 'mdb008.pgm',


코드를 실행하면 폴더 내부의 파일들의 이름이 files 리스트에 저장된다. 만약 여기서 특정 문자열을 포함한 파일들만 남기고 싶으면 아래와 같이 문자열의 기본함수인 find함수를 이용한다. -1을 리턴하면 해당 문자열이 없는 것이기 때문에 아래의 if문은 해당 문자열을 포함한 원소만 가져오게 한다.

files = [x for x in files if x.find("mdb") != -1] files

['mdb001.pgm',
 'mdb002.pgm',
 'mdb003.pgm',
 'mdb004.pgm',
 'mdb005.pgm',
 'mdb006.pgm',
 'mdb007.pgm',
 'mdb008.pgm'


반응형
반응형

Pandas 변수 정렬하기


Python에서 데이터 핸들링시 가장 많이 이용하는 Pandas 패키지를 이용하여 변수를 정렬하는 예제입니다. 예를 들어 아래와 같은 데이터셋이 있다고 합시다.


cluster  org      time
   1      a       8
   1      a       6
   2      h       34
   1      c       23
   2      d       74
   3      w       6 
cluster org time 1 a 8 1 a 6 2 h 34 1 c 23 2 d 74 3 w 6

출처: http://3months.tistory.com/195 [Deep Play]
import pandas as pd
data = pd.DataFrame({"cluster" : [1,1,2,1,2,3], "org":['a','a','h','c','d','w'], "time":[8,6,34,23, 74,6]})


출처: http://3months.tistory.com/195 [Deep Play]
import pandas as pd
data = pd.DataFrame({"cluster" : [1,1,2,1,2,3], "org":['a','a','h','c','d','w'], "time":[8,6,34,23, 74,6]})


출처: http://3months.tistory.com/195 [Deep Play]


이를 pandas DataFrame 객체로 읽기 위해서는 아래와 같은 구문으로 읽으면 됩니다.

import pandas as pd
data = pd.DataFrame({"cluster" : [1,1,2,1,2,3], "org":['a','a','h','c','d','w'], "time":[8,6,34,23, 74,6]})


이후에는 DataFrame 객체에 있는 sort_values를 호출하면 해당 변수에 대해 정렬을 할 수 있습니다. ascending 파라미터는 오름차순으로 정렬할지 여부를 결정합니다. 또한 여러개의 변수에 대해서 정렬하고 싶으면 list 자료구조에 변수를 넣어주기만 하면 됩니다.

data = data.sort_values(["time"], ascending=[False])

cluster org time
4 2 d 74
2 2 h 34
3 1 c 23
0 1 a 8
1 1 a 6
5 3 w 6


그러면 이와같이 결과가 나오는데 인덱스가 뒤죽박죽이 되어있다는 것을 알 수 있습니다. 기존 데이터셋의 인덱스를 그대로 갖고 있는 것입니다. 이로인해 plot을 할 때 문제가 생길 수 있으므로 인덱스를 초기화 하는 작업을 해줍니다. default는 drop=False인데 이렇게 하게 되면 기존의 인덱스가 하나의 컬럼으로 남게 됩니다. 많은 경우 기존의 인덱스는 필요없으므로 drop=True로 설정해줍니다.


data = data.reset_index(drop=True)

cluster org time
0 2 d 74
1 2 h 34
2 1 c 23
3 1 a 8
4 1 a 6
5 3 w 6


반응형
반응형

PANDAS 그룹별 평균 구하기



통계분석에서 전체 평균을 구하는 것뿐만 아니라, 그룹간의 평균을 구하고 이를 비교하는 것은 매우 중요한 주제중 하나라고 할 수 있습니다. sas에서는 proc means by 구문을 통해 구할 수 있고, R에서는 aggregates 함수 등을 이용해 구할 수 있는데요. 파이썬에서는 R의 Data.Frame 과 비슷한 형태로 자료를 핸들링 할 수 있는 pandas라는 패키지가 있습니다. 이 패키지 함수를 통해 그룹별 평균을 구하는 방법을 알아보겠습니다.


cluster  org      time
   1      a       8
   1      a       6
   2      h       34
   1      c       23
   2      d       74
   3      w       6 


예를 들어, 위와 같은 데이터가 있다고 가정합시다. 참고로 이걸 파이썬에서 읽어오는 방법은 아래와 같이 하시면 됩니다.


import pandas as pd
data = pd.DataFrame({"cluster" : [1,1,2,1,2,3], "org":['a','a','h','c','d','w'], "time":[8,6,34,23, 74,6]})


아래 구문은 'cluster' 변수를 그룹으로 하여 모든 숫자형 변수의 평균을 계산해 줍니다. as_index=False 구문은 이 그룹을 인덱스로 지정할 것인지 여부인데, 인덱스로 지정하면 두 번째 테이블처럼 그룹이 인덱스로 들어가게됩니다. 


data.groupby(['cluster'], as_index=False).mean()


cluster time
0 1 12.333333
1 2 54.000000
2 3 6.000000



time
cluster
1 12.333333
2 54.000000
3 6.000000

아래 구문은 cluster와 org를 그룹으로 하여 평균을 계산해줍니다. 예를 들어, cluster가 지역, org가 성별이라고 생각해볼 수 있습니다. 그러면 이 구문은 지역과 성별 별로 변수들의 평균을 구하는 구문이 됩니다.

data.groupby(['cluster', 'org'], as_index=False).mean()

cluster org time
0 1 a 7
1 1 c 23
2 2 d 74
3 2 h 34
4 3 w 6


반응형
반응형

Python으로 빈도표 만들기 (Pandas Crosstab)



파이썬에서 빈도표(Frequency Table)를 만드는 방법은 여러가지가 있지만, 그 중 하나가 pandas의 crosstab 함수를 이용하는 방법이다. 아래처럼 dataframe의 컬럼(Series 데이터타입)을 파라미터로 넘겨주면 빈도표를 만들어준다.

import pandas as pd

raw_data = {'regiment': ['Nighthawks', 'Nighthawks', 'Nighthawks', 'Nighthawks', 'Dragoons', 'Dragoons', 'Dragoons', 'Dragoons', 'Scouts', 'Scouts', 'Scouts', 'Scouts'], 'company': ['infantry', 'infantry', 'cavalry', 'cavalry', 'infantry', 'infantry', 'cavalry', 'cavalry','infantry', 'infantry', 'cavalry', 'cavalry'], 'experience': ['veteran', 'rookie', 'veteran', 'rookie', 'veteran', 'rookie', 'veteran', 'rookie','veteran', 'rookie', 'veteran', 'rookie'], 'name': ['Miller', 'Jacobson', 'Ali', 'Milner', 'Cooze', 'Jacon', 'Ryaner', 'Sone', 'Sloan', 'Piger', 'Riani', 'Ali'], 'preTestScore': [4, 24, 31, 2, 3, 4, 24, 31, 2, 3, 2, 3], 'postTestScore': [25, 94, 57, 62, 70, 25, 94, 57, 62, 70, 62, 70]} df = pd.DataFrame(raw_data, columns = ['regiment', 'company', 'experience', 'name', 'preTestScore', 'postTestScore']) df


2x2 테이블


regiment를 기준으로 하여 company의 빈도를 구한다.

pd.crosstab(df.regiment, df.company, margins=True)


company cavalry infantry All
regiment


Dragoons 2 2 4
Nighthawks 2 2 4
Scouts 2 2 4
All 6 6 12



변수 3개 테이블


company, experience를 기준으로하여 regiment의 빈도를 구한다.

pd.crosstab([df.company, df.experience], df.regiment,  margins=True)



regiment Dragoons Nighthawks Scouts All
company experience



cavalry rookie 1 1 1 3
veteran 1 1 1 3
infantry rookie 1 1 1 3
veteran 1 1 1 3
All
4 4 4 12



만들어진 crosstab에 접근하는법


crosstab을 통해 생성한 객체는 dataframe 타입이고, regiment를 제외한 company와 experience는 multi index로 지정되어있다. 따라서 인덱스 값으로 해당 인덱스의 원소값을 얻는 loc 함수를 통해 crosstab 원소에 접근할 수 있다.


cross_tab = pd.crosstab([df.company, df.experience], df.regiment, margins=True)
cross_tab.loc[[('cavalry', 'rookie')]]


참고

https://chrisalbon.com/python/pandas_crosstabs.html

반응형
반응형

강화학습 Q-learning on non-deterministic worlds



출처



Frozen Lake 게임이 non-deterministic인 경우 Q를 어떻게 학습하는지 알아보겠습니다. 이 포스팅은 Frozen Lake 게임과 강화학습의 기본 개념을 안다는 전제로 김성훈 교수님의 강화학습 강의를 제 나름대로 정리한 포스팅입니다. 우선 non-deterministic이 무슨 의미인지부터 살펴보면 non-deterministic 이라는 것은 원하는대로 되지 않는다는 의미입니다. (stochastic이라고도 합니다.) 이런 경우에는 무조건 Q가 가라는 대로 가는 것보다는 "기존의 믿음" 을 차근 차근 업데이트 해나가는 것이 Q 학습이 더 잘 된다고 합니다. 이는 현실 세계와도 많이 닮아있습니다. 이를 멘토에 비교해볼 수 있는데, 무조건 멘토가 하라는 대로 하기보다는 결국 무언가를 하기 위해서는 타인의 조언 보다는 자기 자신의 신념이 더 중요하다고 할 수 있습니다.


이를 식으로 표현하면 기존 알고리즘은  


Q(state, action) = R + λmax(Q(new state)) (λ < 1)


이었는데


Q(state, action) = (1-a)Q(state, action) + a(R+λmax(Q(new state)) (a = learning rate)

Q(state, action) = R + max(Q(new state))

출처: http://3months.tistory.com/173 [Deep Play]


사용하게 됩니다. learning rate 개념을 통해 Q를 한 번에 업데이트 하지 않고, 기존에 믿음을 토대로 조금씩 업데이트 해나가는 것입니다. 이를 구현하는 코드를 보겠습니다. 기존 코드에서 Q 업데이트 하는 부분만 달라지기 때문에 크게 다르지는 않습니다.



라이브러리 로드

import gym
import numpy as np
import matplotlib.pyplot as plt 
from gym.envs.registration import register
import random as pr


environment 생성 및 하이퍼 파라미터 초기화

env = gym.make('FrozenLake-v0')
# Q-table 초기화
Q = np.zeros([env.observation_space.n, env.action_space.n])

# Learning Rate
learning_rate = 0.85

# discount factor
dis = .99
    
# learning 횟수
num_episodes = 2000

# 학습 시 reward 저장
rList = []


Q-learning 알고리즘

for i in range(num_episodes):
    
    # env 리셋
    state = env.reset()
    rAll = 0
    done = False
    
    #decaying E-greedy
    e = 1./((i//100)+1)
    
    # Q-table Learning algorithm
    while not done:
        
        # Choose an action by e greedy
        '''
        if np.random.rand(1) < e:
            action = env.action_space.sample()
        else:
            action = np.argmax(Q[state, :])
        '''
        
        # add Random noise
        action = np.argmax(Q[state, :]+ np.random.randn(1, env.action_space.n)/(i + 1))
        
        # new_state, reward 업데이트 
        new_state, reward, done, _ = env.step(action)
        
        # update Q-table
        Q[state, action] = (1-learning_rate) * Q[state, action] + learning_rate*(reward + dis*np.max(Q[new_state, :]))
        
        rAll += reward
        state = new_state

    rList.append(rAll)

action을 선택하는 부분에서 e-greedy 방법을 사용하는 방법과 random noise를 사용하는 방법이 있는데 둘 다 exploit & exploration을 구현한 것으로 둘 중 하나를 사용하면 됩니다. 밑에 #update Q-table 부분에 Q를 업데이트하는 코드를 볼 수 있습니다. learning rate를 통해 기존의 믿음을 얼마나 받아들일지, Q의 판단을 얼마나 받아들일지를 조정합니다.

print('success rate: ', str(sum(rList)/num_episodes))
print('Final Q-table values')
print(Q)
plt.bar(range(len(rList)), rList, color = 'blue')
plt.show()

('success rate: ', '0.4135')
Final Q-table values
[[  6.05216575e-01   4.77802714e-03   7.66890982e-03   1.14402756e-02]
 [  1.89070559e-04   2.71412272e-05   2.94641678e-03   6.06539650e-01]
 [  6.20782244e-03   3.96037865e-03   2.02160738e-03   5.88158391e-01]
 [  1.38851811e-04   1.81853506e-04   1.08700028e-03   3.36662917e-01]
 [  5.63057417e-01   1.35053120e-03   4.64530097e-04   1.81633578e-03]
 [  0.00000000e+00   0.00000000e+00   0.00000000e+00   0.00000000e+00]
 [  8.64124213e-05   2.51760080e-04   7.21585211e-02   3.41902605e-05]
 [  0.00000000e+00   0.00000000e+00   0.00000000e+00   0.00000000e+00]
 [  3.70706358e-05   1.37044981e-03   2.40643636e-04   7.95889822e-01]
 [  1.09162680e-04   5.60870413e-01   9.16914837e-04   2.64997619e-04]
 [  9.20012820e-01   5.54630225e-05   7.32392792e-05   0.00000000e+00]
 [  0.00000000e+00   0.00000000e+00   0.00000000e+00   0.00000000e+00]
 [  0.00000000e+00   0.00000000e+00   0.00000000e+00   0.00000000e+00]
 [  4.37606936e-04   4.03103644e-04   9.16837079e-01   3.65822303e-04]
 [  0.00000000e+00   0.00000000e+00   2.34205607e-03   9.98477546e-01]
 [  0.00000000e+00   0.00000000e+00   0.00000000e+00   0.00000000e+00]]

success rate는 0.4135인데, 이는 0.4135의 확률로 Goal에 도착한다는 것입니다. non-deterministic world 에서는 상당히 높은 성공률입니다. 또 이 부분에서 중요한 점은 이 non-deterministic world에서의 강화학습 알고리즘의 성공률은 사람의 성공률 보다 높을 수 있다는 것입니다. 왜냐하면 deterministic world에서는 사람이 한 눈에 게임의 rule을 알 수 있고, 매우 쉽게 Goal을 찾을 수 있는 반면, non-deterministic world에서는 사람에게는 Goal을 찾아가는 것이 쉽지 않습니다. 하지만 non-deterministic world에서도 확률적으로 패턴이 존재하고, 이 사람이 이해하기 힘든 패턴속에서 강화학습 알고리즘은 에러를 최소화할 최적의 경로를 찾는다는 것입니다. 이 부분이 진정한 강화학습의 강점이 아닐까 생각해보았습니다.



반응형
반응형