728x90

flask-admin을 사용할때, 특정 그룹의 사용자 ( admin? ) 가 아니면 admin 페이지에 접근 못하게 막고 싶을 수 있다.

(아니 대부분의 경우 막아야 한다!)

그럴때 사용하면 된다.

class MyAdminIndexView(AdminIndexView):
    def is_accessible(self):
      #블라블라 허용된 그룹의 사용자인지 판별 
      # session['id'] 가져와서 판별 등등.
      return False

admin = Admin(app, name='flask', template_mode='bootstrap3', index_view = MyAdminIndexView())

바로 is_accessible() 메소드를 오버라이드 하여 막으면 된다.

admin 페이지 접근이 막힌 모습

 

근데 이 코드는 문제가 있다. 딱 index 페이지만 막힌 모습이다. model 별 url을 입력하면 통과해서 확인 가능하다.

testtable 페이지가 바로 확인 가능한 모습

이럴때는 ModelView를 추가할때, 동일하게 is_accessible() 메소드를 오버라이드 해주면 처리할 수 있다.

class MyModelView(ModelView):
  def is_accessible(self):
      #블라블라 허용된 그룹의 사용자인지 판별 
      # session['id'] 가져와서 판별 등등.
      return False

  column_display_pk = True

  def __init__(self, cls, session, **kwargs):
    super(MyModelView, self).__init__(cls, session, **kwargs)

admin = Admin(app, name='flask', template_mode='bootstrap3', index_view = MyAdminIndexView())
admin.add_view(MyModelView(TestTable, db.session))

 

이는 is_accessible() 메소드가 다음과 같은 class diagram에서 최상위 클래스인 'BaseView'에 있기 때문이다.

flask-admin의 view 클래스 구조

그래서 Index용과 그 외 ModelView용 페이지 인가 제어 ( 이 부분도 일반화되어 교체 가능하게 해도 되고 )

ModelView 클래스를 만들고, 모든 model view 만들때 상속시켜주면 이제 진짜 인가된 사용자 그룹만

허용 시킬 수 있게 된다. 

728x90

'프로그래밍 > Python' 카테고리의 다른 글

flask-admin 에서 pk, fk 등이 보이지 않고, 수정, 추가 안될때 해결 방법  (0) 2023.05.01
lof  (0) 2019.08.26
ball tree  (0) 2019.08.01
kd tree  (1) 2019.07.04
keras를 활용한 다중선형회귀분석  (2) 2019.05.30
728x90

1. column_list,  form_columns 를 수정하는 방법

 

String타입의 pk를 가지는 TestTable 이라는 테이블을 만들었다고 치자.

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy(app)

class TestTable(db.Model):
    __tablename__ = 'test'

    id = db.Column(db.String, primary_key=True)
    test_string = db.Column(db.String)

admin = Admin(app, name='flask', template_mode='bootstrap3')
admin.add_view(ModelView(TestTable, db.session))


@app.route('/', methods=['GET', 'POST'])
def index():
  return 'hi'

위 코드를 실행하여, flask-admin 페이지로 들어가면 다음과 같다. (임의로 row 하나 넣어둠)

flask-admin 페이지 모습

근데 보면 pk인 id가 보이지 않는다. Create 탭을 들어가도, 막상 데이터를 추가하고자 하면,

추가에 실패한다.

이럴때는 CustomModelView를 만들어서 column_list, form_columns 필드를 수정해주면 해결된다.

class MyModelView(ModelView):
  column_list = ()
  form_columns = ()

  def __init__(self, cls, session, **kwargs):
    MyModelView.column_list = [ c_attr.key for c_attr in db.inspect(cls).mapper.column_attrs ]
    MyModelView.form_columns = [ c_attr.key for c_attr in db.inspect(cls).mapper.column_attrs ]
    super(MyModelView, self).__init__(cls, session, **kwargs)

admin = Admin(app, name='flask', template_mode='bootstrap3')
admin.add_view(MyModelView(TestTable, db.session))

위 코드에서는 model class의 column 을 다 돌면서 추가해주었다. 이렇게 하여 실행하면 잘 나오는 것을 확인할 수 있다.

pk가 잘 나오는 모습
Create에도 이제 id가 잘 노출 된다


2. column_display_pk 를 수정하는 방법

 

이 방법은 create는 안되지만, ( 뭐, form_columns만 따로 채워주면 되긴 한다 ) 볼 수는 있는 방법이다.

class MyModelView(ModelView):
  column_display_pk = True

  def __init__(self, cls, session, **kwargs):
    super(MyModelView, self).__init__(cls, session, **kwargs)

역시 잘 나온다.

이 방법은 Id 부분에도 클릭하여 ordering이 가능하다.

728x90

'프로그래밍 > Python' 카테고리의 다른 글

flask-admin에서 ModelView 페이지 접근 막는 법  (0) 2023.05.01
lof  (0) 2019.08.26
ball tree  (0) 2019.08.01
kd tree  (1) 2019.07.04
keras를 활용한 다중선형회귀분석  (2) 2019.05.30
728x90

local outlier fator(이하 lof)는 각 점들의 밀도와 이웃점들의 밀도를 고려하여 해당 점의 스코어를 계산합니다.

 

lof를 구하기 앞서 먼저 reachability-distance를 구해야 한다.

 

reachability-distance(A,B)는  두 점 사이의 거리와 B에서 k번째 근접이웃까지의 거리중

 

큰 값이 reachability-distance의 값이 된다. 예를 들어,

 

reachability-distance

위 그림에서 빨간선으로 이어진 점들을 B라고 볼때,

 

A까지의 거리가 각 점들에서 k-distance보다 크므로 빨간선이 reachability-distance값이 된다.

 

그 다음으로 lrd(local reachability density)를 구해야 한다.

 

여기서 Nk는 k-distance내 점들의 집합이다.

 

A가 밀도가 높지 않은 지역에 위치할 경우 A로부터 집합내의 점 B까지 거리가 길어지므로,

 

A의 lrd값은 작아진다.

 

최종적으로 lof는 주변 이웃 점들의 평균 lrd값을 구하고,

 

A의 lrd값을 나누어줌으로써 구해진다.

 

위에서 언급했듯,

 

A가 밀도가 높지 않은 지역에 위치할 경우 lrd값은 작아지므로 반대로 lof값은 커진다. (분모이므로)

 

import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import LocalOutlierFactor

print(__doc__)

np.random.seed(42)

# Generate train data
X_inliers = 0.3 * np.random.randn(100, 2)
X_inliers = np.r_[X_inliers + 2, X_inliers - 2]

# Generate some outliers
X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2))
X = np.r_[X_inliers, X_outliers]

n_outliers = len(X_outliers)
ground_truth = np.ones(len(X), dtype=int)
ground_truth[-n_outliers:] = -1

# fit the model for outlier detection (default)
clf = LocalOutlierFactor(n_neighbors=20, contamination=0.1)
# use fit_predict to compute the predicted labels of the training samples
# (when LOF is used for outlier detection, the estimator has no predict,
# decision_function and score_samples methods).
y_pred = clf.fit_predict(X)
X_scores = clf.negative_outlier_factor_

plt.title("Local Outlier Factor (LOF)")
plt.scatter(X[:, 0], X[:, 1], color='k', s=3., label='Data points')
# plot circles with radius proportional to the outlier scores
radius = (X_scores.max() - X_scores) / (X_scores.max() - X_scores.min())
plt.scatter(X[:, 0], X[:, 1], s=1000 * radius, edgecolors='r',
            facecolors='none', label='Outlier scores')
plt.axis('tight')
plt.xlim((-5, 5))
plt.ylim((-5, 5))
n=np.copy(X_scores*-1) # 스코어값이 음수로 나오므로
n[n<2]=np.nan          # 스코어값이 2보다 작으면 표시 안함
n=np.round(n,2)
for i, txt in enumerate(n):
    if np.isnan(txt):continue
    plt.annotate(txt, (X[i,0], X[i,1]))
legend = plt.legend(loc='upper left')  # 범례 위치
plt.show()

결과

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

참고

https://scikit-learn.org/stable/auto_examples/neighbors/plot_lof_outlier_detection.html

 

Outlier detection with Local Outlier Factor (LOF) — scikit-learn 0.21.3 documentation

Note Click here to download the full example code Outlier detection with Local Outlier Factor (LOF) The Local Outlier Factor (LOF) algorithm is an unsupervised anomaly detection method which computes the local density deviation of a given data point with r

scikit-learn.org

https://jayhey.github.io/novelty%20detection/2017/11/10/Novelty_detection_LOF/

 

로컬 아웃라이어 팩터(Local Outlier Factors)

오브젝트 근처에 있는 데이터들의 밀도까지 고려하는 로컬 아웃라이어 팩터(Local outlier factor)입니다. 근처 데이터의 밀도까지 고려하는 모델로서 다른 방법론들이 해당 데이터만 고려한다면 이 방법은 근처 데이터까지의 거리와 밀도까지 상대적으로 고려해줍니다.

jayhey.github.io

https://godongyoung.github.io/머신러닝/2019/03/11/Local-Outlier-Factor(LOF).html

728x90
728x90

ball tree도 kd tree와 마찬가지로 knn(k-nearest neighbor) search에 많이 쓰이는 트리이다.

 

kd tree보다는 초기 트리 구성에 비용이 크지만, kd tree의 경우 차수가 아주 크면

 

query했을때 검색이 매우 느려지는데, ball tree는 kd tree보다 훨씬 빠르게 결과를 도출한다.

 

 

a(1,1550), b(900,440), c(2500,330), d(4000,2), e(5000,1)

 

위와 같은 데이터가 주어졌을때의 트리의 구성은 그림과 같다.

생성된 트리

먼저 가장 범위가 큰 차수로 정렬을 시키고 (위 데이터에서는 1번째 차원의 범위가 1~5000이므로 가장 크다)

 

중간값을 취하고 왼쪽, 오른쪽으로 나눈 뒤 다시 재귀적으로 트리를 구성하도록 한다.

 

검색에 활용하도록 반지름 값도 구하는데 자식 노드중 가장 멀리 떨어진 노드와의 거리가 반지름이 된다.

 

이때, leaf size가 1보다 큰 경우 중간값을 size만큼의 개수를 취한다.

(leaf size는 검색 결과에 영향은 없지만 검색 속도에 영향이 있을 수 있다.)

 

예시 데이터를 기반으로 'ball'을 그려보면 다음과 같을 것이다.

hyperspheres (balls)

 

알고리즘 설명및 코드의 한글 자료는 거의 전무하여 (내 검색 능력이 모자른 것일 수도)

 

위키백과와 사이트의 내용을 참고하였다.

import numpy as np

class Node:
    def __init__(self, data, radius, depth, left_child=None, right_child=None):
        self.left_child = left_child
        self.right_child = right_child
        self.data = data
        self.radius = radius
        self.depth = depth

    def printALL(self):
        print(self.radius, self.data, self.depth)
        if self.left_child != None:
            self.left_child.printALL()
        if self.right_child != None:
            self.right_child.printALL()

def balltree(ndata, depth):
    if ndata.shape[0] < 1:
        return None

    # element가 한 개일 경우
    if ndata.shape[0] == 1:
        return Node(
            data=np.max(ndata, 0).tolist(),
            radius=0,
            depth=depth,
            left_child=None,
            right_child=None
        )
    else:
        # 범위가 가장 큰 dimension에 따라 정렬
        largest_dim = np.argmax(ndata.max(0) - ndata.min(0))
        i_sort = np.argsort(ndata[:, largest_dim])
        ndata[:] = ndata[i_sort, :]

        nHalf = int(ndata.shape[0] / 2)
        loc = ndata[nHalf, :]
        data = loc.tolist()

        # 중간 값(data)에서 가장 멀리 떨어진 값 까지의 거리
        radius = np.sqrt(np.max(np.sum((ndata - loc) ** 2, 1)))

        return Node(
            data=data,
            radius=radius,
            depth=depth,
            left_child=balltree(ndata[:nHalf], depth+1),
            right_child=balltree(ndata[nHalf+1:], depth+1)
        )

if __name__ == '__main__':
    X = [[1,1550], [900,440], [2500,330], [4000,2], [5000,1]]
    X = np.asarray(X)

    tree = balltree(X, 0)
    tree.printALL()

역시 파이썬 패키지중 sklearn에서 balltree의 생성 및 검색을 간편하게 할 수 있다.

 

결과로 가장 유사한 데이터의 인덱스 번호와 거리를 반환한다.

import numpy as np
from sklearn.neighbors import BallTree

X = [[1,1550], [900,440], [2500,330], [4000,2], [5000,1]]
X = np.asarray(X)

# 트리 생성
tree = BallTree(X)

# 테스트 데이터 쿼리
dist, ind = tree.query([[1, 1551]], 1)

print(dist, ind)

실행 결과

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

참고

https://en.wikipedia.org/wiki/Ball_tree

 

Ball tree - Wikipedia

This article is about the binary tree variant. For a metric-tree involving multi-way splits, see M-tree. In computer science, a ball tree, balltree[1] or metric tree, is a space partitioning data structure for organizing points in a multi-dimensional space

en.wikipedia.org

https://www.astroml.org/book_figures/chapter2/fig_balltree_example.html

 

Ball Tree Example — astroML 0.4 documentation

Ball Tree Example Figure 2.5. This example creates a simple Ball tree partition of a two-dimensional parameter space, and plots a visualization of the result. # Author: Jake VanderPlas # License: BSD # The figure produced by this code is published in the t

www.astroml.org

728x90
728x90

kd 트리는 이진 트리로, 모든 트리의 노드가 k차원으로 이루어져 있다.

 

최근 30차원의 데이터를 다루며 검색 및 존재 하지 않을 경우 유사도(유클리디안 거리)를 구하기 위해

 

보게 되었는데, 아쉽게도 트리를 구성하는 데이터가 10만개가 넘다보니 오래 걸렸다. (내 컴퓨터가 구린 것일 수도...)

 

어쨌든 간단하게 살펴보면,

 

a(7,2), b(5,4), c(9,6), d(4,7), e(8,1) 이 순으로 데이터가 트리가 삽입된다 하자

 

먼저 k=2가 된다.

 

트리의 구성

a는 트리가 비어 있으므로 루트노드가 된다.

 

a의 x좌표를 비교하여 작은 애들은 왼쪽으로 큰 애들은 오른쪽으로 분류한다.

 

따라서 b는 a의 왼쪽 노드, c는 오른쪽 노드가 된다.

 

d의 x좌표는 a의 x좌표보다 작으므로 왼쪽으로 가지만 이미 b가 있으므로 이번에는 y좌표를 비교한다.

 

b의 y좌표보다 d의 y좌표가 크므로 오른쪽에 위치한다. 동일하게 e도 배치하면 위 그림과 같이 트리가 구성된다.

 

 

데이터 순서에 따라 트리의 구성이 달라지고 그에 따라 검색 속도도 천차만별로 바뀌게 된다.

 

이것을 막고자 트리 구성시 정렬 후 중간값을 취하도록 하는 방법도 있다.

from operator import itemgetter

class Node:
    def __init__(self, data, depth, left_child=None, right_child=None):
        self.left_child = left_child
        self.right_child = right_child
        self.data = data
        self.depth = depth
    def printALL(self):
        print(self.depth, self.data)
        if self.left_child != None:
            self.left_child.printALL()
        if self.right_child != None:
            self.right_child.printALL()


def kdtree(point_list, depth=0):
    if not point_list:
        return None

    k = len(point_list[0])
    axis = depth % k

    point_list.sort(key=itemgetter(axis))
    median = len(point_list) // 2

    return Node(
        data=point_list[median],
        depth=depth,
        left_child=kdtree(point_list[:median], depth + 1),
        right_child=kdtree(point_list[median + 1:], depth + 1)
    )

if __name__ == '__main__':
    point_list = [(7, 2), (5, 4), (9, 6), (4, 7), (8, 1), (2, 3)]
    tree = kdtree(point_list)
    tree.printALL()

위 코드는 위키백과의 것을 알기 쉽게 수정한 것이다.

 

트리 구성시 정렬하여 중간값을 취하고 재귀적으로 왼쪽과 오른쪽을 구하고 있다.

 

또한 python의 scipy라이브러리내 kdtree의 생성과 검색을 제공하고 있다.

from scipy import spatial

if __name__ == '__main__':
    point_list = [(7, 2), (5, 4), (9, 6), (4, 7), (8, 1), (2, 3)]
    tree = spatial.KDTree(point_list)

    print(tree.query((2, 3)))
    print(tree.query((2, 3.5)))

트리의 인자값으로 넣을 컨테이너로써 튜플이나 리스트외에도

 

DataFrame과 ndarray도 넣을 수 있다. query메소드로 검색하면 결과로

 

유클리디안 거리와 가장 유사한 노드의 인덱스 번호를 반환한다.

 

실행 결과

728x90
728x90
"""
 keras를 이용한 x1*100 + x2*200 + 150 학습 모델
"""
from tensorflow import keras

import numpy as np
from random import randint
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# 학습데이터 생성
x = [ randint(0, 100) for i in range(100000) ]
y = [ x[i*2]*100 + x[i*2+1]*200 + 150 for i in range(50000) ]
x = np.asarray(x).astype(np.float32)
x = x.reshape((50000, 2))
y = np.asarray(y).astype(np.float32)
y = y.reshape((50000, 1))

"""
# 학습 데이터 그래프 그리기
xs = x[:,0]
ys = x[:,1]
zs = y

fig = plt.figure(figsize=(12,12))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(xs, ys, zs)
ax.view_init(15, 15)
plt.show()
"""

# 검증 데이터 생성
test_x = [ randint(0, 100) for i in range(100) ]
test_y = [ test_x[i*2]*100 + test_x[i*2+1]*200 + 150 for i in range(50) ]
test_x = np.asarray(test_x).astype(np.float32)
test_x = test_x.reshape((50, 2))
test_y = np.asarray(test_y).astype(np.float32)
test_y = test_y.reshape((50, 1))

# 모델 생성
model = keras.Sequential()
model.add(keras.layers.Dense(1, input_shape=(2,)))
rmsprop = keras.optimizers.RMSprop(lr=0.02)
model.compile(loss='mean_squared_error', optimizer=rmsprop, metrics=[keras.metrics.mse])
model.summary()

# 학습
model.fit(x, y, epochs=10)

# 검증 데이터로 모델 평가 (verbose = 1 출력 모드)
model.evaluate(test_x, test_y, verbose=1)

ret = model.predict(test_x[:3])
print("예측 데이터 : ", ret)
print("실제 데이터 : ", test_y[:3])

tensorflow에 keras가 들어오면서 훨씬 더 간단하게 모델을 만들고 돌려볼 수 있게 되었다.


학습 데이터 그래프

 

728x90

'프로그래밍 > Python' 카테고리의 다른 글

flask-admin 에서 pk, fk 등이 보이지 않고, 수정, 추가 안될때 해결 방법  (0) 2023.05.01
lof  (0) 2019.08.26
ball tree  (0) 2019.08.01
kd tree  (1) 2019.07.04
[python] 디렉토리내 파일 이름 변경  (1) 2015.09.07
728x90

import re

import os


for root, dirs, files in os.walk('C:test\testFolder'):

    for fname in files:

        print(fname)

        match = re.findall("^[0-9]+ ",fname)

        fname_new = re.sub("^[0-9]+ ",match[0][:-1]+".",fname)

        os.rename(fname,fname_new)

        print(fname_new)



728x90

'프로그래밍 > Python' 카테고리의 다른 글

flask-admin 에서 pk, fk 등이 보이지 않고, 수정, 추가 안될때 해결 방법  (0) 2023.05.01
lof  (0) 2019.08.26
ball tree  (0) 2019.08.01
kd tree  (1) 2019.07.04
keras를 활용한 다중선형회귀분석  (2) 2019.05.30

+ Recent posts