Tools (126)

반응형


Decorator는 무엇인가? 


- 다른 function의 기능을 조작하여 새로운 function을 만드는 것.

- 이 방법은 코드를 더욱 간결하게 만들며, 더욱 Pythonic 한 코드를 만들 수 있다

- 이러한 형태의 일종의 코드 Refactoring 및 중복 줄이기는 소프트웨어 공학에서 매우 중요하다!


Decoration을 안 한 초보 파이썬 코더의 코드


# 기존의 코드를 사용 안 하고, b_function()을 새롭게 정의함.
# 이렇게 하면 문제가, my foul smell을 삭제하고 싶으면, 함수 2개에서 모두 삭제해야한다. 
# 코드의 중복이 생김.
 
def a_function_requiring_decoration(): 
    print("I am the function which needs some decoration to remove my foul smell") 
 
def b_function(): 
    print("I am doing some boring work before executing a_func()") 
    print("I am the function which needs some decoration to remove my foul smell")   
    print("I am doing some boring work after executing a_func()")
 
b_function()

- 이 방법의 문제점은 코드의 중복이 생겨 수정이 필요할 시에 두 함수 모두를 수정해야한다는 것이다. 


간단한 Decoration의 구현 


# 아래 함수를 기능을 추가해서 decoration 해주는 함수 def a_new_decorator(a_func):


# 함수 안에 함수를 정의하고 함수를 리턴한다 def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()")   return wrapTheFunction   # 이 함수를 decoration (기능을 추가) 하고 싶음 def a_function_requiring_decoration(): print("I am the function which needs some decoration to remove my foul smell")

a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) a_function_requiring_decoration()

결과


I am doing some boring work before executing a_func()

I am the function which needs some decoration to remove my foul smell

I am doing some boring work after executing a_func()


- 이를 해결하는 방법이 바로 decoration 이다. 

- a_new_decorator 함수에 a_function_requiring_decoration 함수를 넘기는 방법을 통해 내용이 한 번만 쓰이게 된다. 

- 이를 통해 코드의 중복을 줄일 수 있다.



@ 키워드를 통한 decoration


# @를 붙임으로써 a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) 이걸 안 해도 된다. @a_new_decorator def a_function_requiring_decoration(): """Hey you! Decorate me!""" print("I am the function which needs some decoration to " "remove my foul smell")   a_function_requiring_decoration()   # 근데 함수명이 이상하게 나옴. wrapTheFunction print(a_function_requiring_decoration.__name__)

- @ 키워드를 통해 a_function_requiring_decoration를 재정의 하지 않아도 된다.

- @ [함수명] 을 decoration 하고 싶은 함수 위에 붙여주면 된다. 

- 근데 함수 명이 wrapTheFunction 으로 decoration 한 함수의 이름이 그대로 나오게 된다. 

- 이를 해결하기 위해 wraps 를 이용한다.


# wraps를 이용해 함수명이 제대로 나오게 할 수 있음
from functools import wraps
# 최종적인 decorator의 일반적인 형태
# a_function_requiring_decoration을 a_new_decorator로 decorating 한다는 것이다. 이 때 decorate 할 함수는 a_func에 지정하고 이를 wraps로 받아서 그 아래 함수로 decoration 함
 
def a_new_decorator(a_func):
    @wraps(a_func)
    def wrapTheFunction(): 
        print("I am doing some boring work before executing a_func()") 
        a_func() 
        print("I am doing some boring work after executing a_func()")
 
    return wrapTheFunction
 
@a_new_decorator 
def a_function_requiring_decoration(): 
    """Hey you! Decorate me!"""
    print("I am the function which needs some decoration to " "remove my foul smell")
 
a_function_requiring_decoration() 
 
print(a_function_requiring_decoration.__name__)  # a_function_requiring_decoration


- 이렇게 decorator에 wraps를 붙여주면, 그 함수를 decoration 해주는 함수로 인식을 하게 된다. 

- 함수명도 기존의 함수 명인 a_function_requiring_decoration 을 따르게 된다.


Decoration 활용의 좋은 예 - Authentication


authentication_check라는 함수를 만들고 이곳에서는 웹어플리케이션서의 사용자 인증을 체크한다고 하자. 만약 다른 함수를 실행할 때, 그 함수의 위에다가 위에다가 @authentication_check 만 붙이면, authentication을 알아서 해주게 된다. 즉, Authentication - function 실행 순으로 알아서 만들어 준다.  이것이 좋은 점은 각 함수마다 authentication check를 안해도되고, authentication check logic을 딱 한 번만 쓰면 된다. 이런건 Java에서는 보통 상속을 이용해서 하는데, python에서는 decorator로 할 수 있다.


""" Use case : Authorization Now let’s take a look at the areas where decorators really shine and their usage makes something really easy to manage. Decorators can help to check whether someone is authorized to use an endpoint in a web application. They are extensively used in Flask web framework and Django. Here is an example to employ decorator based authentication:   """   # decorator 함수 def requires_auth(f): @wraps(f) def decorated(*args, **kwargs): auth = request.authorization if not auth or not check_auth(auth.username, auth.password): authenticate() return f(*args, **kwargs) return decorated

- 위 require_auth 함수는 어떤 함수 f를 받아서 그 전에 authorization 과정을 수행해주는 decorator이다. 



참고 - Intermediate Python

반응형
반응형


Python 중고급 - map, filter, reduce 


파이썬의 기초를 익힌 후, 파이썬의 중고급 문법을 선택적으로 배운다면 기본 문법으로도 구현할 수 있는 로직들을 더욱 쉽고, 간편하게 구현해볼 수 있습니다. 이번 포스팅에서는 list를 다루는 함수인 map, filter, reduce에 대해 간단하게 정리해보겠습니다. 물론 map, filter, reduce를 안 쓰고 코딩하는 것도 가능하며, 그것이 편하시면 그렇게 하셔도 좋습니다. 하지만 이를 사용하는 프로그래머나 데이터 분석가들이 꽤 있기 때문에 이러한 문법들을 알아두면 기존의 코드를 이해하는데 큰 도움이 될 수 있을 것입니다. 


Map


map의 경우, list의 element에 함수를 적용시켜 결과를 반환하고 싶을 때 사용합니다. 만약, 어떤 리스트의 원소를 제곱한 새로운 리스트를 만들고 싶다면, 일반적인 C언어 스타일의 해결법은 아래와 같습니다. 


# Map function
# 문제와 일반적인 해결법
items = [1, 2, 3, 4, 5]
squared = []
for i in items:
    squared.append(i**2)

하지만 map function을 통해 짧게 구현할 수 있습니다. map함수의 구조는 map(function_to_apply, list_of_inputs) 입니다.


items = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, items))

위 코드는 items 리스트의 element 각각에 대해 제곱을 해서 새로운 리스트를 만들어 반환합니다. filter와 reduce도 이와 같은 구조를 갖습니다. 


이 때, map 앞에 list 함수를 통해 list 자료형으로 바꾸는 이유는 map 이 반환하는 것이 실제로는 list 자료형이 아니기 때문입니다. map 함수는 Iterator 를 반환하는데, 이를 list로 변환해서 list 자료형으로 만드는 것입니다. Iterator는 next() 함수를 갖는 파이썬 객체로 꼭 메모리에 올릴 데이터만 올려서 메모리를 효율적으로 이용할 수 있는 파이썬의 대표적인 객체입니다. 바로 list로 반환하는 것이 아니라 Iterator로 보다 상위의 객체를 리턴하는 것은, 다른 map 함수의 리턴값을 리스트가 아닌 다른 자료구조로 변환시킬 수도 있도록 하기 위해서입니다. 예를 들어, set 자료구조로도 변환시킬 수 있습니다. 


map_it = map(lambda x: x**2, items)
next(map_it)

map 함수의 결과는 Iterator 이므로, next 함수를 위와 같이 실행할 수 있습니다. 위 코드의 결과는 1입니다.


Iterator 에 대해서는 다음에 다루어 보도록 하겠습니다. 



Filter


Filter의 경우, list의 element에서 어떤 함수의 조건에 일치하는 값만 반환하고 싶을 때 사용합니다. 


As the name suggests, filter creates a list of elements for which a function returns true.


만약 어떤 리스트에서 '음수만 골라내고 싶다' 라고 할 때, filter 함수를 사용한 코딩 방법은 아래와 같습니다. 


number_list = range(-5, 5)
less_than_zero = list(filter(lambda x: x < 0, number_list))
print(less_than_zero)

이 때, less_than_zero 는 -5, -4, -3, -2, -1 을 갖습니다. 


만약 Map과 Filter를 보고 저거 list comprehension 으로 할 수 있는 거 아니야? 라고 생각하실 수 있습니다. 맞습니다. Map과 Filter가 자신과 맞지 않다고 생각하는 경우 list comprehension 만으로도 위 코드들을 훨씬 더 간결하게 구현할 수 있습니다.


# Map을 list comprehension으로 구현 items = [1, 2, 3, 4, 5] squared = list(map(lambda x: x**2, items)) print(squared)   squared = [x**2 for x in items] print(squared)   # Filter를 list comprehension으로 구현 number_list = range(-5, 5) less_than_zero = list(filter(lambda x: x < 0, number_list)) print(less_than_zero)   less_than_zero = [x for x in number_list if x <0] print(less_than_zero)  

위 코드처럼 list comprehension 만을 통해 map, filter가 하는 것을 할 수 있습니다. 


Filter가 마음에 들지 않는 경우, list comprehension을 쓸 수도 있습니다 하지만, map, filter가 있다는 것을 알아 두면 좋습니다.


Reduce


reduce는 어떤 list에 대해서 computation을 해서 결과를 내보낼 때, 즉 결과를 어떤 함수로 computation해서 결과를 축약하기 위해서 사용됩니다. 이 때, reduce함수에 input으로 들어가는 함수는 두 element를 연산하는 로직을 넣어야 합니다. 이것은 list comprehension으로 하지 못하는 것입니다. 


아래 코드는 reduce함수를 이용하는 것을 포함하여 파이썬으로 1-100 까지의 합을 구하는 총 3가지 방법입니다. 


# 1-100 까지의 합을 구하라   # C 언어 스타일의 해법 sum_value = 0 for i in range(1, 101) : sum_value += i print(sum_value)   # python 스러운 해법 sum_value = reduce((lambda x,y : x+y), [x for x in range(1,101)]) print(sum_value)   # 하지만 Data scientist가 가장 먼저 생각해는 해법 import numpy as np print(np.sum([x for x in range(1,101)])


참고 


Intermediate python (http://book.pythontips.com/en/latest/)

반응형
반응형


PBC 데이터를 통한 생존분석


PBC 데이터 다운받을 수 있는 사이트

http://www4.stat.ncsu.edu/~boos/var.select/pbc.html

http://www4.stat.ncsu.edu/~boos/var.select/pbc.dat.txt


이 데이터셋은 mayo clinic에서 수집된 데이터로 일차성 담즙성 간경화증(primary biliary cirrhosis) 환자들의 생존에 대한 데이터입니다. 


데이터 핸들링

library(survival)

data <- read.table("pbc.dat")

# Column rename
colnames(data) <- c('id', 'futime', 'status', 'drug', 'age', 'sex', 'ascites', 'hepato', 'spiders', 'edema', 'bili', 'chol', 'albumin', 'copper', 'alk_phos', 'sgot', 'trig', 
                   'platelet', 'protime', 'stage')

head(data)


id
futime
status
drug
age
sex
ascites
hepato
spiders
edema
bili
chol
albumin
copper
alk_phos
sgot
trig
platelet
protime
stage
1400212146411111.014.52612.601561718.0137.9517219012.24
24500012061710110.01.13024.14547394.8113.528822110.63
31012212559400000.51.41763.48210516.096.105515112.04
41925211999410110.51.82442.54646121.860.639218310.34
51504121391810110.03.42793.53143671.0113.157213610.93
62503222420110100.00.82483.9850944.093.0063.11.03

생존분석 자료의 기본 자료 구성


1. Survival 데이터에서는 time을 나타내는 변수와 event를 나타내는 변수가 있다. 

2. time은 event 까지의 시간을 나타내며, 

3. event 변수는 우리의 관심 event (예를 들어, 사망) 혹은 censoring을 나타낸다. (이는 주로 0, 1로 나타내어진다.)


PBC 데이터에서는  status = 0=alive, 1=liver transplant, 2=dead 인데,  0,1을 중도 절단된 censoring, 2 를 관심 event로 코딩을 해봅시다.

data$status[(data$status == 1)] = 0
data$status[(data$status == 2)] = 1


drug = 1 : 페니실린

drug = 2 : 플라시보이므로 , 해석상의 이점을 얻기 위해

drug = 1 페니실린, drug = 0은 플라시보로 재코딩해줍니다.


data <- data[data$drug != '.', ]
data$drug <- as.character(data$drug)
data$drug[(data$drug == 2)] = 0
data$drug <- factor(data$drug)


1. KM estimation


우선 Survival function을 추정하는 비모수적인 방법으로 많이 쓰이는 Kaplan-Meier analysis 를 해보겠습니다.


# event, censoring 구분
Y = Surv(data$futime, data$status)

# KM estimation
fit = survfit(Y~data$drug)
summary(fit)


우선 Surv라는 함수를 통해 무엇이 time과 event인지를 알려줍니다. 그리고 drug에 따라 생존을 분석할 것이므로 ~data$drug를 입력하면 아래처럼 lifetable을 만들어줍니다.


Call: survfit(formula = Y ~ data$drug)

                data$drug=0 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   51    154       1    0.994 0.00647        0.981        1.000
   77    153       1    0.987 0.00912        0.969        1.000
  110    152       1    0.981 0.01114        0.959        1.000
  130    151       1    0.974 0.01282        0.949        0.999
  186    150       1    0.968 0.01428        0.940        0.996
  191    149       1    0.961 0.01559        0.931        0.992
  207    148       1    0.955 0.01679        0.922        0.988
  216    147       1    0.948 0.01788        0.914        0.984
  264    146       2    0.935 0.01986        0.897        0.975
  304    144       1    0.929 0.02075        0.889        0.970
  321    143       1    0.922 0.02160        0.881        0.965
  326    142       1    0.916 0.02240        0.873        0.961
  460    141       1    0.909 0.02317        0.865        0.956
  549    140       1    0.903 0.02389        0.857        0.951
  552    139       1    0.896 0.02459        0.849        0.946
  597    138       1    0.890 0.02525        0.841        0.941
  611    137       1    0.883 0.02589        0.834        0.935
  708    136       1    0.877 0.02650        0.826        0.930
  733    135       1    0.870 0.02709        0.819        0.925
  769    134       1    0.864 0.02765        0.811        0.920
  786    133       1    0.857 0.02820        0.804        0.914
  790    131       1    0.851 0.02873        0.796        0.909
  797    130       1    0.844 0.02925        0.789        0.903
  850    128       1    0.837 0.02975        0.781        0.898
  853    127       1    0.831 0.03024        0.774        0.892
  859    126       1    0.824 0.03071        0.766        0.887
  890    125       1    0.818 0.03116        0.759        0.881
  930    124       1    0.811 0.03160        0.751        0.875
  943    123       1    0.804 0.03203        0.744        0.870
  974    122       1    0.798 0.03244        0.737        0.864
 1080    118       1    0.791 0.03286        0.729        0.858
 1165    115       1    0.784 0.03328        0.722        0.852
 1212    114       1    0.777 0.03370        0.714        0.846
 1217    111       1    0.770 0.03411        0.706        0.840
 1356    103       1    0.763 0.03459        0.698        0.834
 1413    101       1    0.755 0.03506        0.690        0.827
 1427     98       1    0.748 0.03554        0.681        0.821
 1444     95       1    0.740 0.03603        0.672        0.814
 1487     93       1    0.732 0.03651        0.664        0.807
 1536     91       1    0.724 0.03698        0.655        0.800
 1786     79       1    0.715 0.03763        0.645        0.792
 1847     76       1    0.705 0.03829        0.634        0.784
 2090     69       1    0.695 0.03908        0.622        0.776
 2419     56       1    0.683 0.04030        0.608        0.766
 2466     53       1    0.670 0.04155        0.593        0.756
 2503     51       1    0.657 0.04276        0.578        0.746
 2769     40       1    0.640 0.04473        0.558        0.734
 2796     38       1    0.623 0.04662        0.538        0.722
 2847     35       1    0.605 0.04857        0.517        0.709
 3090     32       1    0.587 0.05060        0.495        0.695
 3170     29       1    0.566 0.05275        0.472        0.680
 3244     28       1    0.546 0.05460        0.449        0.664
 3358     26       1    0.525 0.05640        0.425        0.648
 3395     24       1    0.503 0.05814        0.401        0.631
 3428     22       1    0.480 0.05983        0.376        0.613
 3445     21       1    0.457 0.06119        0.352        0.595
 3762     15       1    0.427 0.06427        0.318        0.573
 3839     13       1    0.394 0.06719        0.282        0.551
 3853     12       1    0.361 0.06916        0.248        0.526

                data$drug=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   41    158       1    0.994 0.00631        0.981        1.000
   71    157       1    0.987 0.00889        0.970        1.000
  131    156       1    0.981 0.01086        0.960        1.000
  140    155       1    0.975 0.01250        0.950        0.999
  179    154       1    0.968 0.01393        0.941        0.996
  198    153       1    0.962 0.01521        0.933        0.992
  223    152       1    0.956 0.01637        0.924        0.988
  334    151       1    0.949 0.01744        0.916        0.984
  348    150       1    0.943 0.01844        0.908        0.980
  388    149       1    0.937 0.01937        0.900        0.975
  400    148       1    0.930 0.02025        0.892        0.971
  515    147       1    0.924 0.02108        0.884        0.966
  673    145       1    0.918 0.02187        0.876        0.962
  694    144       1    0.911 0.02263        0.868        0.957
  750    141       1    0.905 0.02337        0.860        0.952
  762    140       1    0.898 0.02408        0.852        0.947
  799    139       1    0.892 0.02476        0.845        0.942
  824    138       1    0.885 0.02541        0.837        0.937
  904    134       1    0.879 0.02607        0.829        0.931
  971    132       1    0.872 0.02671        0.821        0.926
  980    131       1    0.866 0.02732        0.814        0.921
  999    130       1    0.859 0.02791        0.806        0.915
 1000    129       1    0.852 0.02848        0.798        0.910
 1012    128       1    0.846 0.02902        0.791        0.904
 1037    127       1    0.839 0.02955        0.783        0.899
 1077    126       1    0.832 0.03005        0.775        0.893
 1083    125       1    0.826 0.03054        0.768        0.888
 1152    124       1    0.819 0.03101        0.760        0.882
 1170    122       1    0.812 0.03148        0.753        0.876
 1191    121       2    0.799 0.03236        0.738        0.865
 1235    117       1    0.792 0.03279        0.730        0.859
 1297    114       1    0.785 0.03323        0.723        0.853
 1350    111       1    0.778 0.03368        0.715        0.847
 1360    110       1    0.771 0.03411        0.707        0.841
 1434    105       1    0.764 0.03456        0.699        0.834
 1492    100       1    0.756 0.03505        0.690        0.828
 1576     97       1    0.748 0.03554        0.682        0.821
 1657     93       1    0.740 0.03606        0.673        0.814
 1682     92       1    0.732 0.03655        0.664        0.807
 1690     91       2    0.716 0.03748        0.646        0.793
 1741     87       1    0.708 0.03794        0.637        0.786
 1827     82       1    0.699 0.03845        0.628        0.779
 1925     78       1    0.690 0.03899        0.618        0.771
 2055     72       1    0.681 0.03960        0.607        0.763
 2081     71       1    0.671 0.04019        0.597        0.755
 2105     70       1    0.661 0.04074        0.586        0.746
 2224     65       1    0.651 0.04137        0.575        0.738
 2256     63       1    0.641 0.04198        0.564        0.729
 2288     61       1    0.630 0.04259        0.552        0.720
 2297     60       1    0.620 0.04315        0.541        0.710
 2386     54       1    0.608 0.04385        0.528        0.701
 2400     53       1    0.597 0.04450        0.516        0.691
 2540     47       1    0.584 0.04533        0.502        0.680
 2583     42       1    0.570 0.04634        0.486        0.669
 2598     41       1    0.556 0.04725        0.471        0.657
 2689     38       1    0.542 0.04822        0.455        0.645
 3086     28       1    0.522 0.05023        0.433        0.631
 3222     24       1    0.501 0.05264        0.407        0.615
 3282     22       1    0.478 0.05495        0.381        0.599
 3574     18       1    0.451 0.05795        0.351        0.580
 3584     17       1    0.425 0.06032        0.322        0.561
 4079      8       1    0.372 0.07247        0.254        0.545
 4191      7       1    0.319 0.07922        0.196        0.519


par(mai=c(1,1,1,1))
plot(fit,main="KM Curve", xlab="Time(Week)", ylab=expression(paste(hat(S),"(t)")))

# Log rank test (difference between groups)
log_rank = survdiff(Surv(data$futime, data$status) ~ data$drug, data)
log_rank

결과를 보시면 플라시보와 페니실린 처방군간에 생존률에 큰 차이가 없는 것을 확인할 수 있습니다.


두 군간에 차이가 있는지 검정하는 방법인 log_rank 테스트에서도 p value > 0.05로 두 군간에 차이가 유의하지 않습니다.


Call:
survdiff(formula = Surv(data$futime, data$status) ~ data$drug, 
    data = data)

              N Observed Expected (O-E)^2/E (O-E)^2/V
data$drug=0 154       60     61.8    0.0513     0.102
data$drug=1 158       65     63.2    0.0502     0.102
 

Chisq= 0.1 on 1 degrees of freedom, p= 0.7



2. Cox regression


생존분석을 다변수로 할 때, Cox regression을 주로 활용합니다. 이는 Cox proportional hazard model로 불리기도 합니다.


Cox regression은 다음과 같은 이유로 많이 쓰입니다.


1. 다양한 변수들의 계수와 hazard ratio를 추정하는데 좋다. -> 이를 통해 변수별 생존에 대한 중요도를 비교하기 쉽다.

2. Cox regression은 robust 하다. (참에 매우 근접한 값을 추정해준다.)

3. 계산된 hazard가 양수이기 때문에 타당한 값이다.

4. baseline hazard를 몰라도 회귀계수, hazard ratio를 추정할 수 있다.


Cox regression의 이론적 배경에 대해서는 다음에 기회가 있을 때 다루어보도록 하겠습니다. 


R에서 Cox regression을 수행하는 것은 매우 간단한데, 앞서 정의한 event, time 변수인 Y를 종속변수로 놓고 분석대상인 변수들을 ~ +로 연결하면 됩니다.  

# Cox regression
cox = coxph(Y~data$drug + data$age + data$sex + data$stage + data$edema + data$bili + data$albumin)
summary(cox) 
Call:
coxph(formula = Y ~ data$drug + data$age + data$sex + data$stage + 
    data$edema + data$bili + data$albumin)

  n= 312, number of events= 125 

                   coef  exp(coef)   se(coef)      z Pr(>|z|)    
data$drug1    2.569e-02  1.026e+00  1.855e-01  0.138 0.889882    
data$age      6.736e-05  1.000e+00  2.651e-05  2.541 0.011057 *  
data$sex     -5.940e-01  5.521e-01  2.550e-01 -2.330 0.019832 *  
data$stage1  -2.248e+00  1.056e-01  1.023e+00 -2.197 0.027992 *  
data$stage2  -8.573e-01  4.243e-01  2.950e-01 -2.906 0.003659 ** 
data$stage3  -4.884e-01  6.136e-01  2.186e-01 -2.234 0.025487 *  
data$stage4          NA         NA  0.000e+00     NA       NA    
data$edema    9.740e-01  2.649e+00  3.148e-01  3.095 0.001971 ** 
data$bili     1.263e-01  1.135e+00  1.529e-02  8.263  < 2e-16 ***
data$albumin -9.288e-01  3.950e-01  2.556e-01 -3.634 0.000279 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

             exp(coef) exp(-coef) lower .95 upper .95
data$drug1      1.0260     0.9746   0.71322    1.4760
data$age        1.0001     0.9999   1.00002    1.0001
data$sex        0.5521     1.8112   0.33497    0.9101
data$stage1     0.1056     9.4656   0.01423    0.7844
data$stage2     0.4243     2.3568   0.23801    0.7564
data$stage3     0.6136     1.6296   0.39979    0.9419
data$stage4         NA         NA        NA        NA
data$edema      2.6486     0.3776   1.42921    4.9083
data$bili       1.1347     0.8813   1.10117    1.1692
data$albumin    0.3950     2.5315   0.23936    0.6519

Concordance= 0.839  (se = 0.029 )
Rsquare= 0.427   (max possible= 0.983 )
Likelihood ratio test= 174  on 9 df,   p=<2e-16
Wald test            = 186.2  on 9 df,   p=<2e-16
Score (logrank) test = 287  on 9 df,   p=<2e-16


그러면 이렇게 회귀계수와 회귀 계수의 exponential을 돌려주게 됩니다. Cox regression이 좋은 점은 회귀계수에 exponential을 취했을 때, 해당 변수가 1단위 증가했을 때의 hazard ratio가 됩니다. 예를 들어, age의 경우, 다른 변수들을 보정하고, 1살 증가했을 때, hazard가 1.0001배 증가한다. 라고 볼 수 있습니다. sex의 경우, 다른 모든 변수를 보정했을 때, 남자에 비해 여자가 hazard가 0.55 배라고 볼 수 있습니다 (이 데이터에서 0=male, 1=female로 코딩이 되어있기 때문에). p-value를 보면 어떠한 변수가 생존에 영향을 크게 끼치는 지를 비교해볼 수 있습니다.  



반응형

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

R igraph 설치 오류 해결  (0) 2018.12.28
R Default library path 바꾸기  (2) 2018.12.28
Jupyter notebook에서 R을 이용하기 (IRkernel)  (6) 2018.10.05
R 패키지 설치시 gfortran 컴파일 오류  (0) 2018.07.06
R 유명한 패키지 정리  (0) 2018.03.19
반응형

Jupyter notebook 에서 R을 이용하기


데이터 분석을 할 때, PythonR을 동시에 이용하시는 분들이 많습니다.

저 같은 경우도 머신러닝, 딥러닝 등을 할 때는 Python을, 데이터 처리, 가공, 통계분석을 할 때는 R을 선호하는데요. 이 경우 Jupyter notebook 등의 Python 개발 환경과 R studio 를 번갈아가면서 이용해야해서 불편한 점이 많았습니다. 


본 포스팅에서는 Jupyter notebook이라는 하나의 개발 환경에서 R과 Python을 같이 이용할 수 있게 해주는 IRkernel을 설치하는 것을 포스팅해보았습니다.


IRkernel을 이용하면 Jupyter notebook에서도 현재 컴퓨터에 설치된 R 커널을 이용할 수 있게 해줍니다.

IRkernel은 R 커널을 Jupyter notebook에서 이용할 수 있게 해주는 패키지입니다. 

https://github.com/IRkernel/IRkernel


우선 당연히 선행적으로 Jupyter가 설치되어있어야하며,


주의할 점은 conda 가상환경 쓰시는 분들은

이걸 jupyter notebook이 설치된 conda 가상환경을 키고 IRkernel 설치를 진행하여야합니다.


먼저 devtools를 설치합니다.

install.packages('devtools')


다음 devtools를 이용해 IRkernel을 설치합니다.


devtools::install_github('IRkernel/IRkernel')

# or devtools::install_local('IRkernel-master.tar.gz')

IRkernel::installspec()  # to register the kernel in the current R installation



이렇게 R kernel이 생기게 됩니다.



저는 R version 3.5.1을 이용중이었는데 동일한 버전을 Jupyter notebook에서도 이용할 수 있습니다.


---- 추가 (2020-09-28)

conda install r-irkernel

위 conda 커맨드로 anaconda 가상환경 밑에 R 과 IRKernel 을 동시에 설치할 수도 있습니다. 


특정 R 버전에 설치하기 위해서는 아래 참고 (2020-10-16 추가)

http://salvatoregiorgi.com/blog/2018/10/16/installing-an-older-version-of-r-in-a-conda-environment/

반응형
반응형


주피터 nbextension 설치


우선 가상환경을 쓰시는 분들은 가상환경을 activate하시기 바랍니다.


source activate [가상환경이름]


pip install jupyter_nbextensions_configurator jupyter_contrib_nbextensions

jupyter contrib nbextension install --user

jupyter nbextensions_configurator enable --user


위 커맨드를 입력하시면 nbextension이 설치됩니다. 원래는 Clusters 옆에 nbextension 탭이 생기게 됩니다.



저의 경우에는 왜 인지는 모르겠지만 자동으로 nbextension 탭이 안 생겼는데

[아이피]:[포트]/nbextensions 로 들어가니까 아래처럼 nbextension 메뉴를 볼 수 있었습니다. 


메뉴에서 사용 가능한 extension 들이 나와있고, 클릭을 통해 enable/disable을 할 수 있습니다.

처음 사용하실 때는 각각의 모듈들을 설치하셔야 합니다.


주피터 테마 설치


주피터 테마

https://github.com/dunovank/jupyter-themes


마찬가지로 가상환경 activate 후에


pip install jupyterthemes


커맨드 옵션은 아래와 같습니다.


jt  [-h] [-l] [-t THEME] [-f MONOFONT] [-fs MONOSIZE] [-nf NBFONT]

    [-nfs NBFONTSIZE] [-tf TCFONT] [-tfs TCFONTSIZE] [-dfs DFFONTSIZE]

    [-m MARGINS] [-cursw CURSORWIDTH] [-cursc CURSORCOLOR] [-vim]

    [-cellw CELLWIDTH] [-lineh LINEHEIGHT] [-altp] [-altmd] [-altout]

    [-P] [-T] [-N] [-r] [-dfonts]


jt -l 로 적용가능한 테마들을 볼 수 있습니다.


저의 경우에는 onedork 테마가 마음에 들어서


jt -t onedork -fs 95 -tfs 11 -nfs 115 -cellw 70% -T

이러한 옵션으로 사용중인데, 폰트 사이즈도 적절하고 화면이 주피터 노트북 default보다 조금 넓은 정도여서 편리하게 사용하고 있습니다.


각각의 옵션이 무엇을 뜻하는지에 대한 설명은

https://github.com/dunovank/jupyter-themes 을 참조하시면 됩니다.


또 테마를 설치한 후, output화면에서 왼쪽이 약간 잘려 나오는 문제가 있었는데

~/.jupyter/custom/custom.css 에서

div.output_area {
display: -webkit-box;
padding-left: 20px;
}

를 추가하여 해결하였습니다. 위 파일을 수정하면 jupyter notebook의 css 설정을 직접 바꾸어 자신만의 테마를 만들어 볼 수도 있습니다.


반응형
반응형

Python으로 하는 탐색적 자료 분석 (Exploratory Data Analysis)


Python을 통해 탐색적 자료분석을 할 때, 무엇을 해야하고, 순서는 어떻게 해야하는지 막막한 경우가 많은데요. 탐색적 자료분석의 기본은 바로 변수 별로 분포를 그려보는 것이겠죠. 수치형 데이터의 경우는 히스토그램을, 명목형 데이터의 경우는 빈도표를 통해 데이터의 분포를 살펴보게 됩니다. 본 포스팅에서는 파이썬을 통해 탐색적 자료 분석을 하는 방법을 유명한 데이터셋인 타이타닉 데이터를 통하여 차근차근 알아보겠습니다. 


titanic.csv



기본적인 탐색적 자료 분석의 순서는 아래와 같이 정리해보았습니다. 


1. 데이터를 임포트하여 메모리에 올린다.

2. 데이터의 모양을 확인 한다.

3. 데이터의 타입을 확인한다.

4. 데이터의 Null 값을 체크한다. 

5. 종속변수의 분포를 살펴본다.

6. 독립변수 - 명목형 변수의 분포를 살펴본다. 

7. 독립변수 - 수치형 변수의 분포를 살펴본다. 

8. 수치형, 명목형 변수간의 관계를 파악한다. 


1. 데이터를 임포트한다.


아래와 같이 패키지와 데이터를 임포트합니다. numpy, pandas, matplotlib, seaborn은 이 4가지의 패키지는 파이썬을 통한 EDA에서 거의 필수적으로 사용하는 라이브러리입니다.


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
 
titanic = pd.read_csv("titanic.csv")


2. 데이터의 모양을 확인한다. 


titanic.head()

PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked
0103Braund, Mr. Owen Harrismale22.010A/5 211717.2500NaNS
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.010PC 1759971.2833C85C
2313Heikkinen, Miss. Lainafemale26.000STON/O2. 31012827.9250NaNS
3411Futrelle, Mrs. Jacques Heath (Lily May Peel)female35.01011380353.1000C123S
4503Allen, Mr. William Henrymale35.0003734508.0500NaNS



3. 데이터의 타입을 체크한다.


titanic.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            891 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          204 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB


데이터의 타입을 체크하는 이유는 해당 변수의 타입을 제대로 맞추어주기 위해서입니다. 범주형 변수의 경우 object 또는 string, 수치형 변수의 경우 int64 혹은 float 64로 맞추어주면 됩니다. 범주형 변수의 경우 값이 문자열로 들어가 있으면 알아서 object 타입이 되지만, 만약의 숫자로된 범주형 변수의 경우 int64 등으로 잘못 타입이 들어가 있는 경우가 있습니다.  


위 데이터의 경우 Survived와 PClass 변수가 범주형 int64로 잘못 되어있으므로 형변환을 합니다.


titanic['Survived'] = titanic['Survived'].astype(object)
titanic['Pclass'] = titanic['Pclass'].astype(object)


4. 데이터의 Null 값을 체크한다. 


Null Check도 매우 중요한 작업 중 하나입니다. 단순히 Tutorial이나 학습을 위해 제작된 데이터셋이아닌 현실의 데이터셋의 경우, 많은 부분이 Null 인 경우가 많습니다. 따라서 이 Null 값을 어떻게 처리하느냐가 매우 중요합니다. 


titanic.isnull().sum()

PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age              0
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64



Cabin 변수가  687 행이 missing이고 Embarked가 2개의 행이 missing인 것을 확인하였습니다.


Null 값이 있는 경우, 크게 그 값을 빼고 하는지, 혹은 결측치를 대치하는지 2개의 방법으로 나눌 수 있습니다. 각각의 방법에 대한 이름이 다르긴한데 보통 첫 번째 방법을 complete data analysis, 두 번째 방법을 Imputation이라고 이름 붙입니다. 


missing_df = titanic.isnull().sum().reset_index()
missing_df.columns = ['column', 'count']
missing_df['ratio'] = missing_df['count'] / titanic.shape[0]
missing_df.loc[missing_df['ratio'] != 0]

columncountratio
10Cabin6870.771044
11Embarked20.002245


위 명령어를 통해 전체의 몇 %가 missing 인지를 확인할 수 있습니다. 




5. 종속변수 체크


titanic['Survived'].value_counts().plot(kind='bar') plt.show()


기본적으로 종속변수의 분포를 살펴봅니다. 종속변수란 다른 변수들의 관계를 주로 추론하고, 최종적으로는 예측하고자 하는 변수입니다. 



6. 명목형 변수의 분포 살펴보기

 


단변수 탐색


category_feature = [ col for col in titanic.columns if titanic[col].dtypes == "object"]
category_feature
['Survived', 'Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked']

앞에서 명목형 변수의 형을 object로 모두 변경했기 때문에 이처럼 컬럼 중에서 object 타입을 가진 컬럼만 뽑아서 명목형 변수의 리스트를 만듭니다. 이 때, 데이터의 기본키(인덱스), 종속변수 등을 제외하고 분석하는 것이 좋습니다. 



category_feature = list(set(category_feature) - set(['PassengerId','Survived']))
category_feature
  ['Cabin', 'Embarked', 'Ticket', 'Sex', 'Name', 'Pclass']



다음으로는 그래프를 통해 명목형 변수의 분포를 살펴보는 것입니다. 


for col in categorical_feature: titanic[col].value_counts().plot(kind='bar') plt.title(col) plt.show()




이렇게 살펴봄으로써 명목형 변수를 어떻게 다룰지를 판단할 수 있습니다. 예를 들어, 카테고리수가 너무 많고, 종속변수와 별로 관련이 없어보이는 독립 변수들은 빼고 분석하는 것이 나을 수도 있습니다.



이변수 탐색



sex_df = titanic.groupby(['Sex','Survived'])['Survived'].count().unstack('Survived')
sex_df.plot(kind='bar', figsize=(20,10))
plt.title('Sex')
plt.show()


성별-생존의 관계 파악처럼 두 변수의 관계를 파악하기 위해서는 위와 같이 확인할 수 있습니다.


7. 수치형 변수의 분포 살펴보기


단변수 탐색


단변수 탐색은 seaborn 패키지의 distplot 함수를 이용하면 매우 편합니다.


우선 이와 같이 전체 변수 중에서 범주형 변수와 기타 인덱스 변수, 종속변수들을 제외하고 수치형 변수만 골라냅니다.

numerical_feature = list(set(titanic.columns) - set(category_feature) - set(['PassengerId','Survived']))
numerical_feature = np.sort(numerical_feature)
numerical_feature

변수별로 for문을 돌면서 distplot을 그립니다


for col in numerical_feature:
    sns.distplot(titanic.loc[titanic[col].notnull(), col])
    plt.title(col)
    plt.show()


이변수, 삼변수 탐색


seaborn 패키지의 pairplot을 통해 종속변수를 포함한 3개의 변수를 한 번에 볼 수 있도록 플로팅합니다.


sns.pairplot(titanic[list(numerical_feature) + ['Survived']], hue='Survived', 
             x_vars=numerical_feature, y_vars=numerical_feature)
plt.show()



pairplot은 어러 변수의 관계를 한 번에 파악할 수 있으며,  hue 파라미터를 통해 종속변수를 지정함으로써 세 변수의 관계를 파악할 수 있습니다.



8. 수치형, 명목형 변수 간의 관계 탐색


앞서서 수치형-수치형  간의 관계, 그리고 명목형-명목형 간의 관계에 종속변수까지 포함해서 보았습니다. 이 번에는 수치형-명목형 간의 관계를 파악해 보는 것입니다. 예를 들어, 성별, 나이, 생존여부 3개의 변수를 동시에 탐색하고 싶을 수 있습니다. 이 경우에 명목형 변수에 따라 수치형변수의 boxplot을 그려봄으로써 대략적인 데이터의 형태를 살펴볼 수 있습니다. 


unique_list = titanic['Sex'].unique()
 
for col in numerical_feature:
    plt.figure(figsize=(12,6))
    sns.boxplot(x='Sex', y=col, hue='Survived', data=titanic.dropna())
    plt.title("Sex - {}".format(col))
    plt.show()


반응형
반응형


문제

/usr/bin/x86_64-linux-gnu-ld: cannot find -lgfortran


Bioconductor를 통해 R 라이브러리를 설치할 때, 위와 같은 컴파일 오류로 인해 제대로 설치되지 않는 현상 발생



해결

https://askubuntu.com/questions/1007591/usr-bin-ld-cannot-find-lopencl


아래 위치에 gfortran 라이브러리가 없어서 문제 발생

/usr/lib/x86_64-linux-gnu/

아래 명령어로 문제 해결

sudo ln -s /usr/lib/x86_64-linux-gnu/libgfortran.so.3 /usr/lib/libgfortran.so

반응형
반응형

Pandas (Python Data Analysis Library)



앞선 포스팅에 이어 Pandas 중고급 문법 튜토리얼입니다. 본 포스팅은 해당 포스팅을 참고하였습니다.


5. 컬럼명, 인덱스명 수정하기


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

# Define the new names of your columns
newcols = {
    'A': 'new_column_1', 
    'B': 'new_column_2', 
    'C': 'new_column_3'
}

# Use `rename()` to rename your columns
df.rename(columns=newcols, inplace=True)

# Rename your index
df.rename(index={1: 'a'})



이번엔 기본기를 넘어 pandas의 고급 문법들을 살펴 보자.



6. 데이터 Formatting


Replace


dataframe의 특정 문자열을 바꾸고 싶을 때는 replace를 이용한다.


df = pd.DataFrame(data=np.array([["Awful", "Poor", "OK"], ["OK", "Acceptable", "Perfect"], ["Poor", "Poor", "OK"]]), columns=['A', 'B', 'C'])
display(df)

display(df.replace("Awful", "Nice"))

# Replace the strings by numerical values (0-4)
display(df.replace(['Awful', 'Poor', 'OK', 'Acceptable', 'Perfect'], [0, 1, 2, 3, 4]))



String의 일부 제거


map function과 lambda를 이용해 특정 컬럼의 모든 데이터에 함수를 적용시킬 수 있다. 


df = pd.DataFrame(data=np.array([[1, 2, "+6a"], [4, 5, "+3b"], [5, 5, "+2C"]]), columns=['A', 'B', 'result'])

# Check out your DataFrame
display(df)

# Delete unwanted parts from the strings in the `result` column
df['result'] = df['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC'))

# Check out the result again
display(df)



7. 열 또는 행에 함수 적용하기


map 또는 apply 함수를 이용한다.

df = pd.DataFrame(data=np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=['A', 'B', 'C'])
doubler = lambda x: x*2
print(df.head())
print(df['A'].map(doubler))
print(df.apply(doubler))
print(df.iloc[1].apply(doubler))
  A  B  C
0  1  2  3
1  4  5  6
2  7  8  9
0     2
1     8
2    14
Name: A, dtype: int64
    A   B   C
0   2   4   6
1   8  10  12
2  14  16  18
A     8
B    10
C    12
Name: 1, dtype: int64



8. 빈 데이터 프레임 만들기 (Creating empty dataframe)


가끔 빈 데이터 프레임을 만들고, 그 곳에 값을 채워야할 경우가 있다. 이것을 하기 위해서는 인덱스와 컬럼을 만든 후, np.nan 을 채워주면 된다.

df = pd.DataFrame(np.nan, index=[0,1,2,3], columns=['A'])
print(df)

그 속에 값을 채워넣고 싶으면 아래처럼 할 수 있다.

df.loc[1, 'A'] = "A"


9. 데이터 임포트시, 날짜, 시간 parsing 하기


만약 날짜 시간으로된 컬럼을 datatime 으로 parsing 하기 위해서는 read_csv 메소드의 parse_dates 를 이용할 수 있다.

import pandas as pd
dateparser = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')

# Which makes your read command:
pd.read_csv(infile, parse_dates=['columnName'], date_parser=dateparse)

# Or combine two columns into a single DateTime column
pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)  


10. 데이터프레임 재구성하기


pivot 함수를 통해 index, column, values 를 지정하여 재구성할 수 있다.

import pandas as pd

products = pd.DataFrame({'category': ['Cleaning', 'Cleaning', 'Entertainment', 'Entertainment', 'Tech', 'Tech'],
        'store': ['Walmart', 'Dia', 'Walmart', 'Fnac', 'Dia','Walmart'],
        'price':[11.42, 23.50, 19.99, 15.95, 55.75, 111.55],
        'testscore': [4, 3, 5, 7, 5, 8]})

print(products)

pivot_products = products.pivot(index='category', columns='store', values='price')
print(pivot_products)
 category    store   price  testscore
0       Cleaning  Walmart   11.42          4
1       Cleaning      Dia   23.50          3
2  Entertainment  Walmart   19.99          5
3  Entertainment     Fnac   15.95          7
4           Tech      Dia   55.75          5
5           Tech  Walmart  111.55          8
store            Dia   Fnac  Walmart
category                            
Cleaning       23.50    NaN    11.42
Entertainment    NaN  15.95    19.99
Tech           55.75    NaN   111.55


Stack & Unstack


pivot 함수를 이용할 수도 있지만, stack 과 unstack 함수를 이용하여 pivoting 을 할 수 있다. stack 은 column index를 raw index로 바꾸어 데이터프레임이 길어지고, unstack 은 raw index를 column index로 바꾸어 데이터프레임이 넓어진다. 


Stack 과 Unstack 의 개념도


본 포스팅에서는 간단한 개념만 설명하며, 테이블 pivoting 관련해서는 이 페이지 (https://nikgrozev.com/2015/07/01/reshaping-in-pandas-pivot-pivot-table-stack-and-unstack-explained-with-pictures/) 가 정리가 잘 되어있으니 참고하시면 좋을 것 같다.


melt 함수


melt 함수는 column 을 row로 바꾸어준다. 녹으면 흘러내리니까 column 이 raw로 흘러려 column 이 짧아지고 raw 는 길어진다고 이해하면 쉽다. 

# The `people` DataFrame
people = pd.DataFrame({'FirstName' : ['John', 'Jane'],
                       'LastName' : ['Doe', 'Austen'],
                       'BloodType' : ['A-', 'B+'],
                       'Weight' : [90, 64]})

print(people)

# Use `melt()` on the `people` DataFrame
print(pd.melt(people, id_vars=['FirstName', 'LastName'], var_name='measurements'))
FirstName LastName BloodType  Weight
0      John      Doe        A-      90
1      Jane   Austen        B+      64
  FirstName LastName measurements value
0      John      Doe    BloodType    A-
1      Jane   Austen    BloodType    B+
2      John      Doe       Weight    90
3      Jane   Austen       Weight    64



11. 데이터 프레임 반복하기


iterrows 함수를 이용하여 iteration 할 수 있다. 매우 유용하다.

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

for index, row in df.iterrows() :
    print(row['A'], row['B'])
1 2
4 5
7 8


반응형
반응형

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


반응형
반응형

유명하고 많이 사용하는 R 패키지 정리

가장 유명하고, 많이 다운로드 되는 R 패키지들을 그 목적에 따라서 정리하였습니다. 본 포스트는 이 포스트를 참고하였습니다.

데이터 로드

RMySQL, RPostgresSQL, RSQLite - 데이터 베이스로부터 직접 데이터를 읽을 때 사용하는 패키지들이다. R[데이터베이스명] RMySQL은 MySQL의 데이터들을 직접 R로 불러올 수 있다.

XLConnect, xlsx - 이 패키지들은 Microsoft사의 엑셀을 R로부터 직접 읽어올 수 있게 한다. 물론, write도 가능하다.

foreign - SAS, SPSS 데이터셋을 읽어올 때 사용한다. 예를 들어, SAS의 경우 sas7bdat 확장자로 되어있는 파일인데, 이를 읽어올 때 foreign 패키지를 활용할 수 있다.


일반적인 텍스트 파일을 로드할 때, R에서는 별다른 패키지가 필요하지 않다. read.csv, read.table, read.fwf를 이용하면 된다. 이외의 독특한 자신만의 데이터셋을 불러오고 싶다면 CRAN guide에 데이터 import, export에 관하여 문의할 수도 있다. 

데이터 핸들링

dplyr - 데이터 subsetting, summarizing, rearranging, joining에 대한 더 쉬운 길을 제공한다. dplyr는 빠른 데이터 핸들링을 위하여 반드시 사용하는 패키지이다.(go to package) 

tidyr - 데이터셋의 레이아웃을 바꿀 때 유용한 툴이다. 데이터를 tidy format으로 바꾸기 위해 gather이나 spread 함수를 사용할 수 있다.

stringr - 문자열 다루는 것과 정규 표현식 관련 패키지이다. 

lubridate - date와 time을 더욱 다루기 쉽게 만드는 툴이다.

데이터 시각화

ggplot2 - R의 매우 유명한 시각화 패키지이다. grammar of graphics 를 활용하여 layered, customizable plot을 만들 수 있다는 장점이 있다.

ggvis grammar of graphics을 기반으로 동작하는, 대화형, 웹베이스의 그래픽 라이브러리이다.

rgl - Interactive 3D 시각화를 위한 라이브러리이다. 

htmlwidgets - 자바스크립트 기반의 interactive 시각화를 위한 툴이다. 이 패키지는 아래와 같은 htmlwidget들을 구현하고 있다.

googleVis - R에서 데이터 시각화를 위해 구글 차트를 이용할 수 있게한다. 구글 차트 툴은 Gapminder라고 불리기도 한다. 이는 시각화 소프트웨어로, Hans Rosling의 TED 출연으로 유명해졌다.


데이터 모델링

car - car 패키지의 Anova 함수는 type2, type3 아노바 테이블을 만드는데 유명하다.

mgcv - Generalized Additive Models

lme4/nlme - Linear, Non-linear 혼합효과모형

randomForest - 머신러닝의 랜덤 포레스트

multcomp - 다중비교를 위한 툴

vcd - 범주형 변수의 시각화와 분석을 위한 툴이다.

glmnet - Lasso, elastic-net 회귀분석을 cross validation과 함께 해준다.

survival - 생존분석

caret - 회귀분석 및 분류 모델의 트레이닝을 위한 툴이다.


데이터 리포트

shiny - 인터랙티브한 웹앱을 쉽게 만들어준다. 프로그래머가 아닌 일반 사람들에게 데이터 exploring과 sharing을 쉽게 만들어준다.

R Markdown - Reproducible reporting을 위한 툴이다. R 코드를  markdown 에 쓰고, render을 하면 R Markdown은 코드를 코드 실행 결과와 함께 HTML, pdf, word 형식으로 export를 해준다. 결과를 정리하는 다른 과정 없이 자동화된 리포팅을 알 수 있게 된다. R Markdown은 RStudio와 통합된다.

xtable - xtable 함수는 R Object(예를 들어, dataframe)를 통해 latex이나 HTML 코드로 리턴해준다. 이를 통해 문서에 붙여넣기를 쉽게할 수 있다. 

공간 데이터 

sp, maptools - shapefile을 비롯한 공간 데이터를 로딩할 수 있는 툴이다.

maps -  맵에 다각형을 쉽게 그려주는 툴이다.

ggmap -  Google map으로 부터 street map을 다운로드 받고, ggplot의 background로 쓸 수 있다.

시계열, 금융 데이터

zoo - 시계열 데이터를 저장하기 위한 가장 유명한 포맷을 다룰 수 있다.

xts - 시계열 데이터를 다루기 위한 툴

quantmod - 금융 데이터를 다운로드하고, 그래프를 그리고, 분석할 수 있는 툴이다.

높은 성능을 내기 위한 R 코드 작성

Rcpp - C++을 call하는 R function을 사용한다. 

data.table - 데이터셋을 빠르게 조작하기 위한 다른 방법을 사용한다. "빅 데이터"에 유용하다.

parallel - 큰 데이터 셋을 다루기 위한 병렬 프로세싱을 사용한다.

웹으로 작업하기

XML - R을 통해 XML 문서를 읽고 만드는 패키지

jsonlite - R을 통해 JSON 데이터를 읽고 만드는 패키지

httr - HTTP Connection을 통한 작업을 위한 라이브러리

R 패키지 만들기

devtools - 코드를 R 패키지로 만들기

testthat - 프로젝트의 유닛 테스트를 위한 쉬운 방법을 제공한다.

roxygen2 - R 패키지의 도큐먼트를 만들기 위한 빠른 방법. roxygen2는 코드의 코멘트를 도큐먼트로 만들고, 패키지의 네임스페이스를 만든다.


반응형
반응형