이번 포스팅에서는 PostgreSQL, Greenplum DB에서 Window 함수를 사용해서 그룹별로 요약 통계량을 구하고, 이 통계량을 이용해서 새로운 변수를 만드는 방법을 소개하겠습니다. 

 

(1) 전체 평균: MAX(value) OVER(PARTITION BY NULL) 을 계산해서 새로운 변수 만들기

(2) 그룹별 평균: MAX(value) OVER(PARTITION BY group_col) 을 계산해서 새로운 변수 만들기

 

 

먼저, 예제로 사용할 테이블을 만들어보겠습니다. 

 

-------------------------------------------------------------------
-- Aggregation by groupby using Window Function
-------------------------------------------------------------------

-- creating a sample table
DROP TABLE IF EXISTS tbl;
CREATE TABLE tbl (
	grp TEXT 
	, id INT
	, val INT
);

INSERT INTO tbl VALUES 
  ('a', 1, 4)
, ('a', 2, 1)
, ('a', 3, 3)
, ('a', 4, 5)
, ('a', 5, 2)
, ('b', 6, 7)
, ('b', 7, 5)
, ('b', 8, 8)
, ('b', 9, 10)
, ('b', 10, 9)
;

SELECT * FROM tbl ORDER BY 1, 2;
--grp|id|val|
-----+--+---+
--a  | 1|  4|
--a  | 2|  1|
--a  | 3|  3|
--a  | 4|  5|
--a  | 5|  2|
--b  | 6|  7|
--b  | 7|  5|
--b  | 8|  8|
--b  | 9| 10|
--b  |10|  9|

 

 

 

(1) 전체 평균: MAX(value) OVER (PARTITION BY NULL) 을 계산해서 새로운 변수 만들기

 

아래 예에서는 그룹별 구분없이 전체 최대값을 계산해서 MAX(val) OVER(PARTITION BY NULL) 해서 원래 값을 나누어주어서 새로운 변수 val_max_ration 를 만들어주었습니다. 

 

-- MAX value for all values using Window Function OVER(PARTITION BY NULL)
SELECT 
	a.*
	, val::NUMERIC / MAX(val) OVER(PARTITION BY NULL) 
		AS val_max_ratio 
FROM tbl AS a
ORDER BY 1, 2
;

--grp|id|val|val_max_ratio         |
-----+--+---+----------------------+
--a  | 1|  4|0.40000000000000000000|
--a  | 2|  1|0.10000000000000000000|
--a  | 3|  3|0.30000000000000000000|
--a  | 4|  5|0.50000000000000000000|
--a  | 5|  2|0.20000000000000000000|
--b  | 6|  7|0.70000000000000000000|
--b  | 7|  5|0.50000000000000000000|
--b  | 8|  8|0.80000000000000000000|
--b  | 9| 10|1.00000000000000000000|
--b  |10|  9|0.90000000000000000000|

 

 

 

(2) 그룹별 평균: MAX(value) OVER(PARTITION BY group_col) 을 계산해서 새로운 변수 만들기

 

아래의 예에서는 MAX(val) OVER(PARTITION BY grp)그룹별 최대값을 구해서 원래 값을 나누어줌으로써 그룹별 최대값 대비 값의 비율(val_grp_max_ration) 이라는 새로운 변수를 만들었습니다. 

 

-- MAX value by Group using Window Function OVER(PARTITION BY grp)
SELECT 
	a.*
	, val::NUMERIC / MAX(val) OVER(PARTITION BY grp) 
		AS val_grp_max_ratio 
FROM tbl AS a
ORDER BY 1, 2
;

--grp|id|val|val_grp_max_ratio         |
-----+--+---+----------------------+
--a  | 1|  4|0.80000000000000000000|
--a  | 2|  1|0.20000000000000000000|
--a  | 3|  3|0.60000000000000000000|
--a  | 4|  5|1.00000000000000000000|
--a  | 5|  2|0.40000000000000000000|
--b  | 6|  7|0.70000000000000000000|
--b  | 7|  5|0.50000000000000000000|
--b  | 8|  8|0.80000000000000000000|
--b  | 9| 10|1.00000000000000000000|
--b  |10|  9|0.90000000000000000000|

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python의 Plotly 모듈을 이용해서 클리브랜드 점 그래프 (Cleveland Dot Plot in Python using Plotly) 그리는 방법을 소개하겠습니다. 

 

Cleveland and McGill (1984) 이  “Graphical Methods for Data Presentation: Full Scale Breaks, Dot Charts, and Multibased Logging.” 이라는 논문에서 막대 그래프 대비 점 그래프가 데이터 해석, 가독성에서 가지는 우수성을 소개하면서 Cleveland Dot Plot 이라고도 많이 불리는 그래프입니다.

 

예제로 사용할 데이터로, "학교(schools)" 범주형 변수의 졸업생 별 남성(men)과 여성(women)의 수입(earning) 데이터로 pandas DataFrame을 만들어보겠습니다. 

 

## making a sample pandas DataFrame
import pandas as pd

df = pd.DataFrame({
    'schools': [
        "Brown", "NYU", "Notre Dame", "Cornell", "Tufts", "Yale",
        "Dartmouth", "Chicago", "Columbia", "Duke", "Georgetown",
        "Princeton", "U.Penn", "Stanford", "MIT", "Harvard"],
    'earnings_men': [
        92, 94, 100, 107, 112, 114, 114, 118, 119, 124, 131, 137, 141, 151, 152, 165], 
    'earnings_women': [
        72, 67, 73, 80, 76, 79, 84, 78, 86, 93, 94, 90, 92, 96, 94, 112]
})



print(df)
#        schools  earnings_men  earnings_women
# 0        Brown            92              72
# 1          NYU            94              67
# 2   Notre Dame           100              73
# 3      Cornell           107              80
# 4        Tufts           112              76
# 5         Yale           114              79
# 6    Dartmouth           114              84
# 7      Chicago           118              78
# 8     Columbia           119              86
# 9         Duke           124              93
# 10  Georgetown           131              94
# 11   Princeton           137              90
# 12      U.Penn           141              92
# 13    Stanford           151              96
# 14         MIT           152              94

# 15     Harvard           165             112

 

 

Plotly 의 graph_objects 메소드를 사용해서 졸업한 학교(schools) 별 남성의 수입(earnings_men)과 여성의 수입(earnings_women) 에 대해서 점으로 마킹을 하고 수입을 텍스트로 표기 (mode="markers + text") 하여 클리브랜드 점 그래프 (Cleveland Dot Plot)을 그려보겠습니다. 

 

import plotly.graph_objects as go

fig = go.Figure()

## Dot Plot for Men
fig.add_trace(go.Scatter(
    x=df['earnings_men'],
    y=df['schools'],
    marker=dict(color="red", size=10),
    mode="markers + text",
    name="Men",
    text=df['earnings_men'],
    textposition="middle right"
))

## Dot Plot for Women
fig.add_trace(go.Scatter(
    x=df['earnings_women'],
    y=df['schools'],
    marker=dict(color="blue", size=10),
    mode="markers + text",
    name="Women",
    text=df['earnings_women'],
    textposition="middle left"
))

## title and axis title
fig.update_layout(
    title="Earnings by School and Gender",
    xaxis_title="Annual Salary (in thousands)",
    yaxis_title="School")


fig.show()

Cleveland Dot Plot in Python using Plotly

 

Plotly 그래프는 interactive mode 로서 마우스 커서를 그래프에 가져다대면 해당 점의 정보가 팝업으로 나타나서 편리하게 볼 수 있습니다. 

 

R의 ggplot2 패키지를 이용한 클리브랜드 점 그래프 (Cleveland Dot Plot in R using ggplot2) 그리는 방법은 https://rfriend.tistory.com/75 를 참고하세요. 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python 의 Plotly 모듈을 사용해서 

 

(1) 3차원 산점도 그리기 (3D Scatter Plot using Plotly)

(2) 3차원 표면도 그리기 (3D Surface Plot using Plotly) 

 

하는 방법을 소개하겠습니다 

 

 

 

(1) 3차원 산점도 그리기 (3D Scatter Plot using Plotly)

 

3차원 산점도는 x, y, z 의 3개 축을 기준으로 3차원의 공간에 산점도를 그려서 3개 변수들 간의 관계를 분석하기 위해서 사용합니다. 마커의 크기와 색깔을 달리해서 4번째 변수의 특성을 3차원 산점도에 추가해서 그릴 수도 있습니다. 

 

Scatter3D trace 는 go.Scatter3D() 함수에 의해 반환되는 그래프 객체입니다. 3차원 산점도이기 때문에 x, y, z 의 좌표값을 반드시 넣어줘야 하며, 이들 값은 리스트(List) 또는 Array 객체를 사용합니다. 

 

아래는 싸인과 코싸인 값을 이용해서 3차원 산점도를 그려본 예입니다. 

 

import plotly.graph_objs as go
import numpy as np

z = np.linspace(0, 10, 50)
x = np.cos(z)
y = np.sin(z)

trace = go.Scatter3d(
   x = x, 
   y = y, 
   z = z,
   mode = 'markers', 
   marker = dict(
      size = 12,
      color = z, 
      colorscale = 'Bluered_r'
      )
   )

layout = go.Layout(title = '3차원 산점도 (3D Scatter plot)')

fig = go.Figure(data = [trace], layout = layout)

fig.show()

3D Scatter Plot in Python using Plotly

 

 

 

(2) 3차원 표면도 그리기 (3D Surface Plot using Plotly) 

 

3차원 표면도는 위도(x, latitude), 경도(y, longitude), 고도(z, altitude) 의 3차원 데이터를 그래프로 표현한 것입니다. 이때 3차원 데이터 값을 개별 점(indivisual points)으로 표현한 대신에 표면(surface)으로 표현하여서 3차원 데이터 간의 관계를 분석할 때 사용합니다.

 

이때 위도(x, latitude), 경도(y, longitude)는 독립변수(indepedent variable)이 되고, 고도(z, altitude)는 종속변수(dependent variable) 가 됩니다. 

 

아래 예는 Plotly의 graph_objs 메소드 중에서 go.Surface() 메소드를 사용해서 3차원 표면도를 그려면 것입니다. 

 

import numpy as np
import plotly.graph_objs as go

x = np.outer(np.linspace(-2, 2, 30), np.ones(30))
y = x.copy().T # transpose
z = np.cos(x ** 2 + y ** 2)

trace = go.Surface(x = x, y = y, z =z )
data = [trace]

layout = go.Layout(title = '3차원 표면도 (3D Surface Plot)')

fig = go.Figure(data = data, layout=layout)

fig.show()

 

 

Plotly 그래프는 interactive mode 를 지원하기 때문에 마우스 커서를 그래프 위에 가져가면 해당 좌표의 정보가 팝업으로 나타납니다. 그리고 커서를 클릭해서 위-아래-좌-우 방향으로 이동하면 3차원 표면도가 방향이 돌아가기 때문에 입체적으로 3차원 표면을 관찰할 수 있는 장점이 있습니다. 

 

 

[Reference]

* Plotly - 3D Scatter and Surface Plot
 : https://www.tutorialspoint.com/plotly/plotly_3d_scatter_and_surface_plot.htm

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다 .

행복한 데이터 과학자 되세요!  :-)

 

 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python 의 Pandas 에서 함수를 적용할 때 사용하는 map(), applymap(), apply() 메소드에 대해서 알아보겠습니다. 

 

(1) map(): Series 에 대해 element-wise 로 함수 적용

(2) applymap(): DataFrame에 대해 element-wise 로 함수 적용

(3) apply(): DataFrame에 대해 행/열 (row/column) 로 함수 적용

 

 

Pandas 함수 적용하기: map, applymap, apply

 

 

(1) map(): Series 에 대해 element-wise 로 함수 적용

 

예제로 사용할 DataFrame을 만들어보겠습니다. 

 

import numpy as np
import pandas as pd

## making a sample pandas DataFrame
np.random.seed(1004)

df = pd.DataFrame(
    np.random.randn(4, 3), 
    columns=['x1', 'x2', 'x3'], 
    index=['A', 'B', 'C', 'D'])

print(df)
#          x1        x2        x3
# A  0.594403  0.402609 -0.805162
# B  0.115126 -0.753065 -0.784118
# C  1.461576  1.576076 -0.171318
# D -0.914482  0.860139  0.358802

 

 

 

map() 메소드는 pandas Series 에 대해 함수를 적용할 때 사용합니다. 아래 예제는 익명 함수 lambda 로 정의한 s_formater 함수를 map() 메소드로 Series에 적용해 본 것입니다. 

 

## pandas Series
df['x1']
# A    0.594403
# B    0.115126
# C    1.461576
# D   -0.914482
# Name: x1, dtype: float64


## map: applying an element-wise function for Series
s_formater = lambda x: '%.2f'% x

df['x1'].map(s_formater)
# A     0.59
# B     0.12
# C     1.46
# D    -0.91
# Name: x1, dtype: object

 

 

 

아래 예제에서는 Series의 인덱스를 키로 해서 매핑(mapping by index)하여 Series의 값을 변환한 것입니다. 

-------------------------------------------------------

s_1 인덱스 --> s_1 값 = s_2 인덱스  -->  s_2 값

-------------------------------------------------------

'a'             -->             0                    -->     'A'

'b'             -->             1                     -->     'B'

'c'             -->             2                     -->     'C'

-------------------------------------------------------

 

 

## 예제 pandas Series 만들기
s_1 = pd.Series({'a': 0, 'b': 1, 'c': 2})
s_2 = pd.Series({0: 'A', 1: 'B', 2: 'C'})

print(s_1)
# a    0
# b    1
# c    2
# dtype: int64

print(s_2)
# 0    A
# 1    B
# 2    C
# dtype: object


##-- 인덱스 키를 기준으로 매핑하기 (mapping by index on Series)
print(s_1.map(s_2))
# a    A
# b    B
# c    C
# dtype: object

 

 

 

(2) applymap(): DataFrame에 대해 element-wise 로 함수 적용

 

다음 예제는 applymap() 메소드를 사용해서 익명함수 lambda 로 정의한 s_formater 함수를 DataFrame 의 각 원소에 대해 적용한 것입니다. (map() 은 Series 대상 vs. applymap()은 DataFrame 대상 element-wise 함수 적용)

 

## applymap: applying an element-wise for DataFrame
s_formater = lambda x: '%.2f'% x

df_2 = df.applymap(s_formater)

print(df_2)
#       x1     x2     x3
# A   0.59   0.40  -0.81
# B   0.12  -0.75  -0.78
# C   1.46   1.58  -0.17
# D  -0.91   0.86   0.36

 

 

 

(3) apply(): DataFrame에 대해 행/열 (row/column) 로 함수 적용

 

아래 예제는 column 기준 (axis=0),  row 기준 (axis=1) 으로 익명함수 lambda로 정의한 (열 또는 행 기준, 최대값 - 최소값) 을 계산하는 함수를 apply() 메소드로 DataFrame에 대해 적용해본 것입니다. 

 

## apply: applying a function on row/column basis of a DataFrame
f = lambda x: x.max() - x.min()

## on column basis
df.apply(f, axis=0)

# x1    2.376058
# x2    2.329141
# x3    1.163964
# dtype: float64



## on row basis
df.apply(f, axis=1)

# A    1.399565
# B    0.899243
# C    1.747393
# D    1.774621
# dtype: float64

 

 

 

아래 예는 apply() 메소드를 써서 DataFrame에 행(row) 기준으로 최대값을 계산하는 익명함수 lambda로 정의한 함수를 적용해서 'x_max'라는 새로운 칼럼을 추가한 것입니다. 

 

## 새로운 칼럼 추가하기
df['x_max'] = df.apply(lambda x: x.max(), axis=1)

print(df)
#          x1        x2        x3     x_max
# A  0.594403  0.402609 -0.805162  0.594403
# B  0.115126 -0.753065 -0.784118  0.115126
# C  1.461576  1.576076 -0.171318  1.576076
# D -0.914482  0.860139  0.358802  0.860139


## equivalent
df['x_max'] = df.max(axis=1)

 

 

* Pandas DataFrame에서 여러개의 칼럼에 대해 그룹을 집계를 할 때 다른 집계 함수를 적용하는 방법은 https://rfriend.tistory.com/393 를 참고하세요. 

 

* Python의 익명 함수 lambda 에 대해서는 https://rfriend.tistory.com/366 를 참고하세요. 

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python의 List Comprehension 에 대해서 알아보겠습니다.

(번역하기가 애매해서 영어 원문 그대로 사용하겠습니다)

 

1. List Comprehension 이란? 

 

Python의 List Comprehension 은 기존에 존재하는 List 에서 새로운 List 를 간결하게 생성하는 방법입니다.

 

List Comprehension Syntax 는 아래와 같습니다. 

new_list = [expression for item in iterable if condition == True]

 

 

 

간단한 예를 들어서 설명해보겠습니다.  아래에 6개의 도시를 원소로 가지는 List 가 있습니다. 첫글자가 "S"로 시작하는 도시명을 원소로 가지는 새로운 List를 만든다고 했을 때, for loop 순환문과 if 조건절을 사용하는 방법이 있습니다. 

 

city_list = ["Seoul", "New York", "London", "Shanghai", "Paris", "Tokyo"]

print(city_list)
# ['Seoul', 'New York', 'London', 'Shanghai', 'Paris', 'Tokyo']


## way 1: for loop and if conditional statement
city_s_1 = []

for city in city_list:
    if "S" in city:
        city_s_1.append(city)
        
        
print(city_s_1)
# ['Seoul', 'Shanghai']

 

 

첫글자가 "S"로 시작하는 도시명을 원소로 가지는 새로운 List를 만든다고 했을 때, List Comprehension 을 이용하면 아래와 같이 아주 간결하게 코드를 짤 수 있습니다. 

 

## way 2: List Comprehension
## [expression for item in iterable if condition == True]
city_s_2 = [city for city in city_list if "S" in city]

print(city_s_2)
# ['Seoul', 'Shanghai']

 

 

 

2. 내장 range() 함수와 조건절을 사용한 List Comprehension

 

Python의 iterable 자료형으로 str, list, tuple, dictionary, set, range 등이 있는데요, 아래 예에서는 그중에서 내장 range() 함수로 0~9까지의 정수를 반복적으로 생성해서, if 조건절을 사용해 짝수로 구성된 새로운 List 를 만들어보겠습니다. 

 

## range() 함수와 List Comprehension 으로 짝수 리스트 만들기
even_list = [i for i in range(10) if i%2 == 0]

print(even_list)
# [0, 2, 4, 6, 8]

 

 

 

3. if else 조건절을 사용해서 List Comprehension 만들기

 

if else 조건절을 List Comprehension 에서 사용할 때는 if else 조건절을 앞에 써주고, for loop 순환문을 뒤에 사용해줍니다. (* 위의 2번과 순서가 뒤바뀜에 주의)

 

## 짝수는 그대로, 홀수이면 99로 치환한 리스트
## if else 조건절이 앞에 있고, for 순환문이 뒤에 있음
if_else_list = [i if i%2 == 0 else 99 for i in range(10)]

print(if_else_list)
# [0, 99, 2, 99, 4, 99, 6, 99, 8, 99]

 

 

만약 for loop 순환문을 앞에 써주고 if else 조건절을 뒤에 써서 List Comprehension 을 시도하면 SyntaxError 가 납니다. 

 

## SyntaxError: invalid syntax
[i for i in range(10) if i%2 == 0 else 99] #SyntaxError

 

 

 

4. 2D List 에 대해 중첩된 순환문(Nested for loops)을 사용해서 List Comprehension 

 

4-1.  2D List 를 1D List 로 차원 줄이기 (flattening)

 

list_2d = [[11, 12], 
           [21, 22], 
           [31, 32], 
           [41, 42]
          ]
          
print(list_2d)
# [[11, 12], [21, 22], [31, 32], [41, 42]]


## flattening
## flattening
list_1d = [i for row in list_2d for i in row]

print(list_1d)
# [11, 12, 21, 22, 31, 32, 41, 42]

 

 

4-2. 2D List 를 전치(Transpose) 하기 

 

## Transpose
list_transpose = [[row[i] for row in list_2d] for i in range(2)]

print(list_transpose)
# [[11, 21, 31, 41], [12, 22, 32, 42]]

 

 

 

5. eval() 함수에 List Comprehension 실행하기

 

Python의 eval() 함수는 동적으로 문자열 표현식을 평가하여 실행합니다. (참고: https://rfriend.tistory.com/798 )

eval() 함수에 List Comprehension 을 문자열 표현식으로 넣어서 실행할 수 있습니다. 

 

## eval() 에 list comprehension 표현식(expression)사용 가능
str_list_comprehension = "[i for i in range(10) if i%2 == 0]"

eval(str_list_comprehension)
# [0, 2, 4, 6, 8]

 

 

하지만, 바로 위의 짝수 리스트를 만드는 List Comprehension 과 동일한 과업을 for loop 순환문과 if 조건절 statement 를 문자열로 만들어서 eval() 함수에 넣어 실행하려고 하면 SyntaxError 가 발생합니다. (eval() 함수는 expression 만 평가하여 실행가능하고, statement 는 평가 불가능함)

 

## eval()에 for loop 순환문과 if 조건절 statement 사용 불가
## SyntaxError: invalid syntax
str_for_if = """
new_list = []

for i in range(10):
    if i%2 == 0:
        new_list.append(i)
"""

eval(str_for_if) # SyntaxError: invalid syntax

 

 

 

6. List Comprehension 으로 새로운 Dict 만들기

 

str 자료형은 iterable 타입으로서, 아래처럼 List Comprehension 으로 각 단위문자 별로 쪼개서 새로운 List 로 만들 수 있습니다.  

 

text = "abcde"

print([s for s in text])
# ['a', 'b', 'c', 'd', 'e']

 

 

아래의 예는 range() 함수와 text 를 iterable 하면서 zip() 으로 정수와 각 단위문자를 짝을 이루어서 for loop 순환문으로 발생시키고, 이를  {Key: Value} 로 해서 새로운 Dict 자료형을 만든 것입니다.  

 

## list comprehension을 이용해서 dictionary 만들기
text = "abcde"

{k: v for k, v in zip(range(len(text)), text)}
# {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스티에서는 Python의 내장 함수인 eval() 함수에 대해서 소개하겠습니다. 

 

(1) Python의 eval() 함수 구문 이해 및 문자열 표현식 인풋을 eval() 함수에 사용하기

(2) eval() 함수의 잘못된 사용 예시 (SyntaxError) 

(3) compiled-code-based 인풋을 eval() 함수에 사용하기

 

 

python eval() function

 

(1) Python의 eval() 함수 구문 이해 및 문자열 표현식 인풋을 eval() 함수에 사용하기

 

Python 의 내장함수(built-in function)인 eval() 함수는 임의의 문자열 기반(string-based) 또는 컴파일된 코드 기반 (compiled-code-based) 인풋의 표현식(expressions)을 평가(evaluate)해서 실행해줍니다. 

 

문자열 기반의 표현식을 eval() 함수가 처리하는 순서는 아래와 같습니다. 

 

  (1-a) 문자열 기반 표현식을 파싱한다. (Parse a string-based expression)

  (1-b) 문자열을 파싱한 결과를 바이트코드로 컴파일한다. (Compile it to bytecode)

  (1-c) 파이썬 표현식으로 평가한다. (Evaluate it as a Python expression) 

  (1-d) 평가한 결과를 하나의 값으로 반환한다. (Return the result of the evaluation)

 

 

아래 예시는 문자열 기반 표현식 (string-based expressions) 으로 수학 계산식(math expressions)을 인풋으로 해서 eval() 메소드를 사용해 동적으로 평가하여 실행한 것입니다. 

 

## You can use the built-in Python eval() 
## to dynamically evaluate expressions 
## from a string-based or compiled-code-based input.

##-- eval() for a string-based input
##-- Math expressions
eval("2 + 6")
# 8

eval("10**2")
# 100

eval("sum([1, 2, 3, 4, 5])")
# 15


import math
eval("math.pi * pow(5, 2)")
# 78.53981633974483

 

 

 

eval() 함수는 문자열 표현식에서 아래 예의 x 와 같은 글로벌 변수에 접근해서 표현식을 평가하고 실행할 수 있습니다.  

 

## eval() has access to global names like x
x = 10
eval("x * 5")
# 50

 

 

 

eval() 함수는 문자열의 블리언 표현식 (Boolean expressions)에 대해서도 평가하여 실행할 수 있습니다.

 

아래의 예에서는 순서대로 블리언 표현식 (Boolean expressions)의 

  (a) 비교 연산자 (value comparison operstors: <, >, <=, >=, ==, !=)),

  (b) 논리 연산자 (logical operators: and, or, not),

  (c) 소속 여부 확인 연산자 (membership test operators: in, not in),

  (d) 동일 여부 확인 연산자 (identity operators: is, is not)

을 사용한 문자열 기반 인풋을 eval() 메소드를 통해 평가하고 실행해 보았습니다. 

 

## -- eval() for Boolean expressions
x = 10

## (a) value comparison operators: <, >, <=, >=, ==, !=
eval("x > 5")
# True


## (b) logical operstors: and, or, not
eval("x > 5 and x < 9")
# False


## (c) membership test operators: in, not in
eval("x in {1, 5, 10}")
# True


## (d) identity operators: is, is not
eval("x is 10")
# True

 

 

 

그러면, 그냥 Python 표현식을 쓰면 되지, 왜 굳이 문자열 기반의 표현식을 eval() 함수에 인풋으로 넣어서 쓸까 궁금할 것입니다. 아래의 조건 표현식을 가지는 사용자 정의 함수를 예로 들자면, 사용자 정의함수 myfunc() 를 사용할 때처럼 동적으로 문자열 기반의 조건절 표현식을 바꾸어가면서 쓸 수 있어서 강력하고 편리합니다. 

 

## suppose you need to implement a conditional statement, 
## but you want to change the condition on the fly, dynamically. 
def myfunc(a, b, condition):
    if eval(condition):
        return a + b
    return a - b
    
    
myfunc(5, 10, "a > b")
# -5


myfunc(5, 10, "a <= b")
# 15


myfunc(5, 10, "a is b")
# -5

 

 

 

(2) eval() 함수의 잘못된 사용 예시 (SyntaxError) 

 

(2-1) 만약 eval() 함수의 인풋으로 표현식(expressions) 이 아니라, if, while 또는 for 와 같은 키워드를 사용해서 만든 코드 블락으로 이루어진 명령문(statement)을 사용한다면 "SyntaxError: invalid syntax" 에러가 발생합니다. 

 

## if you pass a compound statement to eval(), 
## then you'll get a SyntaxError. 
x = 10
eval("if x>5: print(x)")
# File "<string>", line 1
#     if x>5: print(x)
#     ^
# SyntaxError: invalid syntax

 

 

 

(2-2) eval() 함수에 할당 연산(assignment operations: =) 을 사용하면 "SyntaxError: invalid syntax" 에러가 발생합니다. 

 

## Assignment operations aren't allowed with eval(). 
eval("x = 10")
# File "<string>", line 1
#     x = 10
#       ^
# SyntaxError: invalid syntax

 

 

 

(2-3) Python 구문의 규칙을 위배하면 "SyntaxError: unexpedted EOF while parsing" 에러가 발생합니다. 

(아래 예에서는 "1 + 2 -" 에서 문자열 마지막에 - 부호가 잘못 들어갔음) 

 

## If an expression violates Python syntax, then SyntaxError
eval("1 + 2 -")
# File "<string>", line 1
#     1 + 2 -
#           ^
# SyntaxError: unexpected EOF while parsing

 

 

 

(3) compiled-code-based 인풋을 eval() 함수에 사용하기

 

eval() 함수의 인풋으로 위의 문자열 기반 객체 대신 compiled-code-based 객체를 사용할 수도 있습니다. compiled-code-based 객체를 eval() 함수의 인풋으로 사용하면 아래의 두 단계를 거칩니다. 

 

  (3-a) 컴파일된 코드를 평가한다. (Evaluate the compiled code)

  (3-b) 평가 결과를 반환한다. (Return the result of the evaluation)

 

위의 (1)번에서 문자열 기반의 표현식을 eval() 함수의 인풋으로 사용했을 때 대비 compiled-code 객체를 eval() 함수의 인풋으로 사용할 경우 파싱하고 컴파일 하는 단계가 없고, 바로 컴파일된 코드를 평가하고 반환하는 단계로 넘어가므로 똑같은 표현식을 여러번 평가해야 하는 경우에 속도 향상을 기대할 수 있습니다. 

 

 

Python의 eval() 함수에 compiled code 객체를 인풋으로 사용하려면, 

compiled_code_object = compile(source, filename, mode) 의 구문을 사용해서 컴파일 해주면 됩니다. 

 - source 에는 문자열 표현식(string-based expression)을 넣어줍니다. 

 - filename 에는 문자열 기반 표현식을 사용할 경우 "<string>" 을 써줍니다. 

 - mode 에는 컴파일된 코드를 eval() 함수로 처리하길 원할 경우 "eval" 을 써줍니다. 

 

##-- eval() for compiled-code-based input
compiled_code = compile("(2 + 3) * 10", "<string>", "eval")
eval(compiled_code)
# 50

 

 

 

 

[ Reference ]

* Real Python site: "Python eval(): Evaluate Expressions Dynamically
: https://realpython.com/python-eval-function/

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다 .

행복한 데이터 과학자 되세요! :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 PostgreSQL, Greenplum database에서 Array의 특정 위치의 값을 가져오는 방법, 특히 PL/Python 사용자 정의 함수를 이용해서 Array의 여러개 위치에서 값을 가져오는 방법을 소개하겠습니다. 

 

PostgreSQL, Greenplum database 에서 

(1) Array 에서 특정 위치의 하나의 원소 값 가져오기

(2) Array 에서 시작~끝 위치의 원소 값을 Slicing 해서 가져오기

(3) Array 에서 여러개 위치의 원소 값을 PL/Python 사용자 정의함수를 사용해서 가져오기

 

 

How to get multiple elements in an Array using PL/Python on PostgreSQL, Greenplum database

 

 

 

먼저 Array를 포함하는 예제로 사용할 간단할 테이블을 만들어보겠습니다. 

 

-- creating a sample table with array column
DROP TABLE IF EXISTS arr_sample_tbl;
CREATE TABLE arr_sample_tbl (
	grp TEXT
	, x_arr iNTEGER[]
);

INSERT INTO arr_sample_tbl VALUES 
('a',  ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
, ('b', ARRAY[11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
, ('c', ARRAY[21, 22, 23, 24, 25, 26, 27, 28, 29, 30])
, ('d', ARRAY[31, 32, 33, 34, 35, 36, 37, 38, 39, 40])
;

SELECT * FROM arr_sample_tbl ORDER BY grp;
--grp|x_arr                          |
-----+-------------------------------+
--a  |{1,2,3,4,5,6,7,8,9,10}         |
--b  |{11,12,13,14,15,16,17,18,19,20}|
--c  |{21,22,23,24,25,26,27,28,29,30}|
--d  |{31,32,33,34,35,36,37,38,39,40}|

 

 

 

(1) Array 에서 특정 위치의 하나의 원소 값 가져오기

 

PostgreSQL/ Greenplum Array 칼럼에 array_column[position::int] 처럼 [ ] 안에 위치 값을 하나의 정수로 넣어주면 됩니다. 아래 예에서는 x_arr Array 칼럼의 3번째 위치한 값을 가져와 봤습니다. 

 

-- getting a value in an array using postion
SELECT 
	grp
	, x_arr[3] -- POSITION INDEX ok
FROM arr_sample_tbl 
ORDER BY grp
;
--grp|x_arr|
-----+-----+
--a  |    3|
--b  |   13|
--c  |   23|
--d  |   33|

 

 

 

(2) Array 에서 시작~끝 위치의 원소 값을 Slicing 해서 가져오기

 

PostgreSQL/ Greenplum Array 칼럼에서 array_column[start_position:end_position] 구문으로 "시작 위치 ~ 끝 위치" 까지의 연속된 원소 값들을 Slicing 해올 수 있습니다. 아래 예제에서는 x_arr 의 Array 칼럼에서 1번째부터 3번째 위치까지의 연속된 원소값들을 Slicing 해왔습니다. 

 

-- slicing from start position to end position
SELECT 
	grp
	, x_arr[1:3] -- SLICING ok
FROM arr_sample_tbl 
ORDER BY grp
;
--grp|x_arr     |
-----+----------+
--a  |{1,2,3}   |
--b  |{11,12,13}|
--c  |{21,22,23}|
--d  |{31,32,33}|

 

 

 

(3) Array 에서 여러개 위치의 원소 값을 PL/Python 사용자 정의함수를 사용해서 가져오기

 

위의 (2)번에서는 Array에서 연속된 (시작 위치 ~ 끝 위치) 까지의 값을 Slicing 해왔는데요, 만약 연속된 위치의 여러개 값이 아니라 Array 안에 띄엄띄엄 있는 여러개의 원소 값들을 위치로 가져오고 싶을 때는 SQL syntax error 가 발생합니다. 

 

-- SQL Error [42601]: ERROR: syntax error at or near ","
SELECT 
	grp
	, x_arr[1, 4, 6, 9]  -- SQL Error -_-;;;
FROM arr_sample_tbl 
ORDER BY grp
;
--SQL Error [42601]: ERROR: syntax error at or near ","
--  Position: 24
--
--Error position: line: 528 pos: 23

 

 

PostgreSQL, Greenplum DB에서 Array 내에 띄엄띄엄 있는 여러개 위치의 원소값을 가져오고 싶을 때 아래의 PL/Python 사용자 정의함수를 사용해보세요. 참고로, Input으로 집어넣는 DB col_position 위치 값은 1부터 시작하는 반면, PL/Python의 내부 코드블록에서는 Python array의 위치 index가 0 부터 시작하기 때문에 np.array(col_postion) - 1 처럼 1을 빼줬습니다. 

아래 예제에서는 x_arr 칼럼의 1, 4, 6, 9 번째 위치에 있는 Array 복수개 원소들을 복수의 위치값을 사용해서 가져왔습니다. Greenplum 을 사용하면 분산병렬처리가 되기 때문에 PL/Python 사용자 정의함수의 처리 속도도 무척 빠르답니다! 

 

-- UDF: selecting multiple elements using PL/Python in PostgreSQL, Greenplum
DROP FUNCTION IF EXISTS plpy_arr_multi_idx_select(int[], int[]);
CREATE OR REPLACE FUNCTION plpy_arr_multi_idx_select(
          x_arr int[], col_position int[]
          ) 
RETURNS int[]
AS $$
    import numpy as np
    
    # INPUT ARRAY
    arr = np.array(x_arr)
    
    # COLUMN POSITION 
    # Python starts from 0 index. (vs. SQL starts from 1)
    # , so -1 from col_position
    col_position_arr = np.array(col_position) - 1
    
    # getting data by positional indexing
    arr_selected = arr[col_position_arr]
    
    return arr_selected

$$ LANGUAGE 'plpythonu';


-- executing the PL/Python UDF above
-- getting multiple values in an array 
-- using PL/Python UDF in PostgreSQL, Greenplum DB
SELECT 
	grp
	, plpy_arr_multi_idx_select( -- PL/Python USER DEFINED Funtion
		x_arr                -- INPUT ARRAY
		, ARRAY[1, 4, 6, 9]  -- COLUMN POSITION
	) AS selected_values
FROM arr_sample_tbl 
ORDER BY grp
;

--grp|selected_values|
-----+---------------+
--a  |{1,4,6,9}      |
--b  |{11,14,16,19}  |
--c  |{21,24,26,29}  |
--d  |{31,34,36,39}  |

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 PostgreSQL, Greenplum Database에서 문자열에 대한 함수 3가지를 소개하겠습니다. 

 

(1) STRING_AGG() : 개별 문자열을 그룹별로 하나의 문자열로 합치기

     (concatenate individual strings into a string by group) 

(2) STRING_TO_ARRAY() : 문자열을 구분자를 기준으로 나누어서 여러개의 원소를 가진 Array 로 만들기

      (splits a string into array elements using supplied delimiter)

(3) UNNEST(STRING_TO_ARRAY()) : 문자열 원소를 가진 ARRAY를 나누어서 개별 문자열 행으로 풀기

       (the opposite of STRING_AGG(), splits array elements and unnest it into multiple rows)

 

 

concatenating strings into a string, unnest string array into multiple rows in PostgreSQL, Greenplum

 

 

예제로 사용할 country 테이블을 만들어보겠습니다. 

 

---------------------------------------------------------------------------------------------
-- String functions and operators in PostgreSQL, Greenplum Database
-- string_agg(), string_to_array(), unnest(string_to_array())
----------------------------------------------------------------------------------------------

DROP TABLE IF EXISTS country;
CREATE TABLE country (
	continent  TEXT
	, country TEXT 
);
INSERT INTO country VALUES 
('Asia', 'Korea')
, ('Asia', 'China')
, ('Asia', 'Japan')
, ('Ameria', 'USA')
, ('Ameria', 'Canada')
, ('Ameria', 'Mexico')
, ('Europe', 'UK')
, ('Europe', 'Fance')
, ('Europe', 'Germany');


SELECT * FROM country ORDER BY 1, 2;
--continent|country|
-----------+-------+
--Ameria   |Canada |
--Ameria   |Mexico |
--Ameria   |USA    |
--Asia     |China  |
--Asia     |Japan  |
--Asia     |Korea  |
--Europe   |Fance  |
--Europe   |Germany|
--Europe   |UK     |

 

 

 

(1) STRING_AGG() : 개별 문자열을 그룹별로 하나의 문자열로 합치기

     (concatenate individual strings into a string by group) 

 

-- (1) string_agg()
-- : non-null input values concatenated into a string, separated by delimiter
-- syntax: string_agg(expression, delimiter [order by])
DROP TABLE IF EXISTS country_agg_tbl;
CREATE TABLE country_agg_tbl AS (
	SELECT 
		continent
		, STRING_AGG(country, ',') AS country_agg
	FROM country 
	GROUP BY continent
); 

SELECT * FROM country_agg_tbl ORDER BY 1, 2;
--continent|country_agg      |
-----------+-----------------+
--Ameria   |USA,Canada,Mexico|
--Asia     |Korea,China,Japan|
--Europe   |UK,Fance,Germany |

 

 

 

(2) STRING_TO_ARRAY() : 문자열을 구분자를 기준으로 나누어서 여러개의 원소를 가진 Array 로 만들기

      (splits a string into array elements using supplied delimiter)

 

-- (2) string_to_array()
-- : splits string into array elements using supplied delimiter and optional null string
-- syntax: string_to_array(text, text [, text])


SELECT 
	continent
	, STRING_TO_ARRAY(country_agg, ',') AS country_array
FROM country_agg_tbl
ORDER BY 1;

--continent|country_array      |
-----------+-------------------+
--Ameria   |{USA,Canada,Mexico}|
--Asia     |{Korea,China,Japan}|
--Europe   |{UK,Fance,Germany} |

 

 

옵션으로 세번째 매개변수 위치에 "NULL 처리할 문자열"을 지정할 수 있습니다. 아래 예에서는 'USA' 문자열에 대해서 NULL 처리하였습니다. 

 

-- NULL string optional
SELECT 
	continent
	, STRING_TO_ARRAY(
		country_agg -- string
		, ','       -- delimiter
		, 'USA' -- NULL string
		) AS country_array
FROM country_agg_tbl
ORDER BY 1;

--continent|country_array       |
-----------+--------------------+
--Ameria   |{NULL,Canada,Mexico}|   -- 'USA' --> NULL
--Asia     |{Korea,China,Japan} |
--Europe   |{UK,Fance,Germany}  |

 

 

 

(3) UNNEST(STRING_TO_ARRAY()) : 문자열 원소를 가진 ARRAY를 나누어서 개별 문자열 행으로 풀기

       (the opposite of STRING_AGG(), splits array elements and unnest it into multiple rows)

 

-- (3) unnest(string_to_array())
-- splits array elements and unnest it into multiple rows
-- the opposite of string_agg()

SELECT 
	continent
	, UNNEST(STRING_TO_ARRAY(country_agg, ',')) AS country
FROM country_agg_tbl
ORDER BY 1, 2;

--continent|country|
-----------+-------+
--Ameria   |Canada |
--Ameria   |Mexico |
--Ameria   |USA    |
--Asia     |China  |
--Asia     |Japan  |
--Asia     |Korea  |
--Europe   |Fance  |
--Europe   |Germany|
--Europe   |UK     |

 

[Reference]

* PostgreSQL's STRING_AGG() function
   : https://www.postgresql.org/docs/9.4/functions-aggregate.html 

* PostgreSQL's STRING_TO_ARRAY() function
   : https://www.postgresql.org/docs/9.1/functions-array.html

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python의 popen() 메소드PL/Python 사용자 정의 함수를 사용하여 

 

(1) Python 의 popen() 메소드 소개

(2) Greenplum DB에 설치된 Package 이름 리스트 확인

(3) Greenplum DB에 설치된 Docker Container Image 리스트 확인

(4) Greenplum DB에 등록된 PL/Container Runtime ID 확인

 

하는 방법을 소개하겠습니다. 

 

 

(1) Python 의 popen() 메소드 소개

 

Python 메서드 popen() 은 시스템 명령어(command) 실행 결과를 가져올 때 사용합니다. popen() 메소드의 반환 값은 파이프에 연결된 열린 파일 객체이며, 모드가 'r'(기본값) 이면 읽기모드이고, 'w' 이면 쓰기모드입니다. Buffering 크기도 정수로 설정할 수 있습니다. 

 

python os.popen() method

 

 

아래 예시는 Python의 os.popen() 메소드를 사용해 'ifconfig' command 를 실행하여 IP 주소를 확인해본 것입니다. 

 

import os

ifconfig = os.popen('ifconfig')
ifconfig_info = ifconfig.read()
ifconfig.close()

print(ifconfig_info)

# lo0: flags=xxxx<UP,LOOPBACK,...
# 	options=xxxx<RXCSUM,TXCSUM,...
# 	inet xxxxxxx netmask 0xff000000 
# 	inet6 ::xx prefixlen xxx 
# 	inet6 fe80::xxxx prefixlen xx scopeid xx 
# 	nd6 options=xxx<PERFORMNUD,DAD>
# gif0: flags=xxx<POINTOPOINT,MULTICAST> mtu 1280
# stf0: flags=0<> mtu xxxx
# en5: flags=xxx<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
# 	ether ac:de:48:00:11:22 
# 	inet6 fe80::aede:48ff:fe00:1122%en5 prefixlen xx scopeid 0x4 
# 	nd6 options=xxx<PERFORMNUD,DAD>
# 	media: autoselect (100baseTX <full-duplex>)
# 	status: active
# ap1: flags=xxxx<BROADCAST,SIMPLEX,MULTICAST> mtu xxxx
# 	options=xxx<CHANNEL_IO>
# 	ether aa:66:5a:20:77:d2 
# 	media: autoselect
# ...

 

 

 

(2) Greenplum DB에 설치된 Package 이름 리스트 확인

 

아래 코드는 os.popen() 메소드로 'gppkg -q --all' 시스템 명령어(command)를 실행해서 Greenplum DB 에 설치된 Package 이름 리스트를 확인하는 PL/Python 사용자 정의 함수입니다.  split() 후에 7번째 위치 이후의 값만 가져오면 됩니다. 

 

--- UDF for getting all package's list on Greenplum DB
DROP FUNCTION IF EXISTS plpy_gppkg_info_func();
CREATE OR REPLACE FUNCTION plpy_gppkg_info_func() 
RETURNS TABLE (LIST text) 
AS $$

	import os
	
	process = os.popen('gppkg -q --all')
	processed = process.read()
	process.close()
	
	# get only packages names 
	result = processed.split()[7:]
	
	return result

$$ LANGUAGE 'plpythonu';


-- Run the UDF above
SELECT plpy_gppkg_info_func() AS gppkg_info;
--gppkg_info                               |
------------------------------------------+
--DataSciencePython-2.0.5                 |
--DataScienceR-2.0.2                      |
--plr-3.0.4                               |
--plcontainer-2.1.5                       |
--pivotal_greenplum_backup_restore-1.25.0 |
--madlib-1.20.0_1                         |

 

 

 

 

(3) Greenplum DB에 설치된 Docker Container Image 리스트 확인

 

아래 코드는 os.popen() 메소드로 'plcontainer image-list' 시스템 명령어(command)를 실행해서 Greenplum DB 에 설치된 Docker Container Image 이름 리스트를 확인하는 PL/Python 사용자 정의 함수입니다.  줄바꿈 '\n' 구분자로 split() 하여서 결과값을 반환받았습니다. 

 

---- UDF for  displaying the installed Docker images on the local host use
DROP FUNCTION IF EXISTS plpy_container_imagelist_func();
CREATE OR REPLACE FUNCTION plpy_container_imagelist_func() 
RETURNS TABLE (LIST text) 
AS $$

	import os
	
	processed = os.popen('plcontainer image-list').read().split('\n')
	
	return processed

$$ LANGUAGE 'plpythonu';


-- Run the UDF above
SELECT plpy_container_imagelist_func() AS container_image_info;
--container_image_info                                                                    |
------------------------------------------------------------------------------------------+
--REPOSITORY                               TAG       IMAGE ID       CREATED         SIZE  |
--pivotaldata/plcontainer_python3_shared   devel     e4cda7f63158   20 months ago   6.71GB|
--pivotaldata/plcontainer_r_shared         devel     3a2472dec133   3 years ago     1.19GB|
--pivotaldata/plcontainer_python_shared    devel     c94546182146   3 years ago     2.34GB|
--                                                                                        |

 

 

(4) Greenplum DB에 등록된 PL/Container Runtime ID 확인

 

아래 코드는 os.popen() 메소드로 'plcontainer runtime-show' 시스템 명령어(command)를 실행해서 Greenplum DB 에 등록된 PL/Container Runtime ID 리스트를 확인하는 PL/Python 사용자 정의 함수입니다.  

'plcontainer runtime-add -r plc_python3_shared -i' 이런식으로 Docker Container Image 정보를 PL/Container configuration file 에 추가 등록해준 정보를 'plcontainer runtime-show' 로 확인할 수 있습니다. 

 

----- UDF for listing the names of the runtimes you created and added to the PL/Container XML file.
DROP FUNCTION IF EXISTS plpy_container_runtimeshow_func();
CREATE OR REPLACE FUNCTION plpy_container_runtimeshow_func() 
RETURNS TABLE (LIST text) 
AS $$

	import os
	
	processed = os.popen('plcontainer runtime-show').read().split('\n')
	
	return processed

$$ LANGUAGE 'plpythonu';


-- Run the UDF above
SELECT plpy_container_runtimeshow_func() AS container_runtimeshow_info;

--PL/Container Runtime Configuration: 
-----------------------------------------------------------
--  Runtime ID: plc_python3_shared
--  Linked Docker Image: pivotaldata/plcontainer_python3_shared:devel
--  Runtime Setting(s): 
--  Shared Directory: 
--  ---- Shared Directory From HOST '/usr/local/greenplum-db-6.22.1/bin/plcontainer_clients' to Container '/clientdir', access mode is 'ro'
-----------------------------------------------------------
--
-----------------------------------------------------------
--  Runtime ID: plc_r_shared
--  Linked Docker Image: pivotaldata/plcontainer_r_shared:devel
--  Runtime Setting(s): 
--  Shared Directory: 
--  ---- Shared Directory From HOST '/usr/local/greenplum-db-6.22.1/bin/plcontainer_clients' to Container '/clientdir', access mode is 'ro'
-----------------------------------------------------------
--
-----------------------------------------------------------
--  Runtime ID: plc_python_shared
--  Linked Docker Image: pivotaldata/plcontainer_python_shared:devel
--  Runtime Setting(s): 
--  Shared Directory: 
--  ---- Shared Directory From HOST '/usr/local/greenplum-db-6.22.1/bin/plcontainer_clients' to Container '/clientdir', access mode is 'ro'
-----------------------------------------------------------

 

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 OpenAI 의 ChatGPT 의 Rest API 를 사용하기 위한 준비 과정으로서 API Key를 생성하는 방법을 소개하겠습니다. 별로 어렵지 않으므로 아래의 내용을 참고해서 순차적으로 따라해 보시기 바랍니다. 

 

 

1. OpenAI 회원가입

 

https://platform.openai.com/overview 에 접속하면 아래와 같이 OpenAI platform 에서 제공하는 애플리케이션 개발 관련 API, Plugin 서비스를 한눈에 살펴볼 수 있습니다. 

 

아직 OpenAI 회원가입을 하지 않았다면, 아래 사이트의 우측 상단에 있는 'Sign up' 메뉴를 선택해서 회원가입을 먼저 하면 됩니다. 

 

OpenAI Platform Overview

 

 

계정을 생성하는 회원 가입 페이지는 아래와 같습니다. Email 주소를 입력하거나, 아니면 Google, Microsoft, Apple 계정을 연동해서 쉽고 빠르게 회원가입을 진행할 수도 있습니다. 

OpenAI Create your account

 

 

 

2. 로그인 후 'View API Keys' 메뉴로 가기

 

우측 상단의 Personal > View API keys 클릭 후 > 본문의 + Create enw secret key 메뉴 클릭

(만약 기존에 발급받았던 API keys 가 존재할 경우 API keys 페이지에 API Keys 리스트만 나오며, API Key 자체를 다 보여주지는 않습니다.). 

 

OpenAI View API keys

 

 

 

3. '+ Create new secret key' 메뉴 선택해서 API key 생성

 

API keys 페이지의 본문 중간에 있는 '+ Create new secret key' 메뉴를 클릭하면 아래에 보이는 바와 같이 'Create new secret key' 팝업 창이 뜹니다. 팝업 창의 가운데 빈칸에 key의 이름을 입력해주고 우측 하단에 'Create secret key' 단추를 클릭하면 API key 가 생성됩니다. 

 

OpenAI API key creation

 

 

 

4. 새로 생성된 OpenAI API Key 복사 후 별도 저장

 

새로 생성된 API key 는 보안 상의 이유로 해서 최초로 생성되는 시점에 딱 한번만 볼 수 있으며, 이후에는 다시 볼 수 없습니다. 따라서 아래 복사를 해서 안전한 곳에 보관을 해서 사용해야 합니다. 만약 API key 를 잃어버렸다면 새로 발급받는 방법밖에 없으므로 보관에 유의하시기 바랍니다. 

 

OpenAI API key copy

 

 

 

5. 생성된 OpenAI API keys 목록 조회

 

위에서 생성한 API key 에 대해서 아래의 화면처럼 "이름(name)-키(key)-생성일(created)-최종사용일(last used)" 의 내용으로 확인할 수 있습니다.   (이때 API key는 보안 이유로 볼 수 없습니다.) 

 

API key 는 다른 사람과 공유할 수 없으며, 브라우저나 클라이언트 쪽의 코드에 노출하면 안됩니다. 각 사용자의 보안을 보호하기 위해서 OpenAI 회사가 공개적으로 노출된 사용자의 API Key를 찾는다면 자동으로 API key를 변경할 수 있다고 하네요. 보안뿐만 아니라 비용 과금과도 관련되었으므로 API key는 노출되지 않게 잘 관리해야 겠지요. 

 

이제 API key 생성이 끝났으므로, 애플리케이션 개발에 API key를 사용하면 됩니다. 

 

OpenAI API keys: generated lists

 

 

 

6. OpenAI API 사용량 확인 

 

좌측의 'Usage' 메뉴를 선택하면 개인이나 조직의 일별 API 사용량 (Daily usage) 을 확인할 수 있습니다. 

계정별로 $18 의 무료 시범 사용 (Free trial usage) 이 가능합니다. 공부하는 개인이라면 $18 로 API 테스트를 해보기에 부족함이 없을 것 같아요. 

 

OpenAI API usage

 

 

 

7. Rate limits 

 

API 를 사용함에 있어 requests-per-minute, tokens-per-minute, images-per-minite 별 제한이 있으므로 애플리케이션 개발에 참고하시기 바랍니다. (좌측의 'Rate limits' 메뉴에서 조회) 

 

 

 

다음번 포스팅에서는 API key를 사용해서 Python으로 ChatGPT 를 실제로 사용해보는 예제를 소개하겠습니다. 

 

* 참고: OpenAI의 API와 Greenplum, PostgreSQL의 pgvector 를 연동해서 Semantic search, Question & Answering 에 활용하는 방법은 https://rfriend.tistory.com/804 를 참고하세요. 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,