복붙노트

[PYTHON] 파이썬에서 다음 코드 예제와 같은 방사형 클러스터를 만들려면 어떻게해야합니까?

PYTHON

파이썬에서 다음 코드 예제와 같은 방사형 클러스터를 만들려면 어떻게해야합니까?

나는이 정확한 계층을 만드는 방법에 대한 몇 가지 예제를 발견했다. (적어도 나는 그들이 그렇다고 생각한다.) 다음과 같은 stackoverflow.com/questions/2982929/ 위대한 일을하고 거의 내가 원하는 것을 수행한다.

[편집] Paul의 코드가 단순화 된 버전입니다. 이제 누군가가이 현재 클러스터 모양 대신 방사형 클러스터로 들어가는 것을 더 쉽게 할 수 있어야합니다.

import scipy
import pylab
import scipy.cluster.hierarchy as sch

def fix_verts(ax, orient=1):
    for coll in ax.collections:
        for pth in coll.get_paths():
            vert = pth.vertices
            vert[1:3,orient] = scipy.average(vert[1:3,orient]) 

# Generate random features and distance matrix.
x = scipy.rand(40)
D = scipy.zeros([40,40])
for i in range(40):
    for j in range(40):
        D[i,j] = abs(x[i] - x[j])

fig = pylab.figure(figsize=(8,8))

# Compute and plot the dendrogram.
ax2 = fig.add_axes([0.3,0.71,0.6,0.2])
Y = sch.linkage(D, method='single')
Z2 = sch.dendrogram(Y)
ax2.set_xticks([])
ax2.set_yticks([])

fix_verts(ax2,0)
fig.savefig('test.png')

그러나 나무와 같은 구조 대신 다음 다이어그램과 같은 방사형 클러스터가 필요합니다.

해결법

  1. ==============================

    1.나는이 문제를 좀 더 연구했으며 이제는 링키지 출력을 (플롯 된 해킹을 해킹하기보다는) 직접 방사형 클러스터를 플로팅하기위한 새로운 함수를 만드는 것이 가장 좋은 것으로 보인다. 나는 결국 뭔가를 요리 할 수 ​​있지만, 곧 아무것도 만들지는 못합니다.

    나는이 문제를 좀 더 연구했으며 이제는 링키지 출력을 (플롯 된 해킹을 해킹하기보다는) 직접 방사형 클러스터를 플로팅하기위한 새로운 함수를 만드는 것이 가장 좋은 것으로 보인다. 나는 결국 뭔가를 요리 할 수 ​​있지만, 곧 아무것도 만들지는 못합니다.

    나는 당신의 데이터가 이런 종류의 방사형 삽입을 자연스럽게 인정한다고 가정하고 있습니다. 그걸 확인 했니? 귀하의 목적에 맞는 적절한 방법이 연계되어 있습니까?

    어떤 방법 으로든 연결은 이진 트리 구조를 반환합니다. 당신의 예에서는보다 일반적인 나무가 있습니다. 트리 노드를 통합하는 방법에 대한 추가 지식이 필요합니다. 이 모든 준비가 원래 dendrogram 해킹의 아이디어를 무효화합니다.

    최신 정보: 이 순진한 예제 플롯이 당신의 목적을 위해 충분히 유사할까요? 그렇다면, 나는 그것을 달성하기위한 몇 가지 간단한 코드를 게시 할 수있을 것이다.

    업데이트 2 :

    다음은 코드입니다.

    radial_demo.py:

    from numpy import r_, ones, pi, sort
    from numpy.random import rand
    from radial_grouper import tree, pre_order, post_order
    from radial_visualizer import simple_link
    from pylab import axis, figure, plot, subplot
    
    # ToDo: create proper documentation
    def _s(sp, t, o):
        subplot(sp)
        t.traverse(simple_link, order= o)
        axis('equal')
    
    def demo1(n):
        p= r_[2* pi* rand(1, n)- pi, ones((1, n))]
        t= tree(p)
        f= figure()
        _s(221, t, pre_order)
        _s(222, t, post_order)
        t= tree(p, tols= sort(2e0* rand(9)))
        _s(223, t, pre_order)
        _s(224, t, post_order)
        f.show()
        # f.savefig('test.png')
    
    # ToDO: implement more demos
    
    if __name__ == '__main__':
        demo1(123)
    

    radial_grouper.py:

    """All grouping functionality is collected here."""
    from collections import namedtuple
    from numpy import r_, arange, argsort, array, ones, pi, where
    from numpy import logical_and as land
    from radial_support import from_polar
    
    __all__= ['tree', 'pre_order', 'post_order']
    
    Node= namedtuple('Node', 'ndx lnk')
    
    # ToDo: enhance documentation
    def _groub_by(p, tol, r):
        g, gm, gp= [], [], p- p[0]
        while True:
            if gp[-1]< 0: break
            ndx= where(land(0.<= gp, gp< tol))[0]
            if 0< len(ndx):
                g.append(ndx)
                gm.append(p[ndx].mean())
            gp-= tol
        return g, array([gm, [r]* len(gm)])
    
    def _leafs(p):
        return argsort(p[0])
    
    def _create_leaf_nodes(ndx):
        nodes= []
        for k in xrange(len(ndx)):
            nodes.append(Node(ndx[k], []))
        return nodes
    
    def _link_and_create_nodes(_n, n_, cn, groups):
        nodes, n0= [], 0
        for k in xrange(len(groups)):
            nodes.append(Node(n_+ n0, [cn[m] for m in groups[k]]))
            n0+= 1
        return n_, n_+ n0, nodes
    
    def _process_level(nodes, polar, p, tol, scale, _n, n_):
        groups, p= _groub_by(p, tol, scale* polar[1, _n])
        _n, n_, nodes= _link_and_create_nodes(_n, n_, nodes, groups)
        polar[:, _n: n_]= p
        return nodes, polar, _n, n_
    
    def _create_tree(p, r0, scale, tols):
        if None is tols:
            tols= .3* pi/ 2** arange(5)[::-1]
        _n, n_= 0, p.shape[1]
        polar= ones((2, (len(tols)+ 2)* n_))
        polar[0, :n_], polar[1, :n_]= p[0], r0
        # leafs
        nodes= _create_leaf_nodes(_leafs(p))
        nodes, polar, _n, n_= _process_level(
        nodes, polar, polar[0, _leafs(p)], tols[0], scale, _n, n_)
        # links
        for tol in tols[1:]:
            nodes, polar, _n, n_= _process_level(
            nodes, polar, polar[0, _n: n_], tol, scale, _n, n_)
        # root
        polar[:, n_]= [0., 0.]
        return Node(n_, nodes), polar[:, :n_+ 1]
    
    def _simplify(self):
        # ToDo: combine single linkages
        return self._root
    
    def _call(self, node0, node1, f, level):
        f(self, [node0.ndx, node1.ndx], level)
    
    def pre_order(self, node0, f, level= 0):
        for node1 in node0.lnk:
            _call(self, node0, node1, f, level)
            pre_order(self, node1, f, level+ 1)
    
    def post_order(self, node0, f, level= 0):
        for node1 in node0.lnk:
            post_order(self, node1, f, level+ 1)
            _call(self, node0, node1, f, level)
    
    class tree(object):
        def __init__(self, p, r0= pi, scale= .9, tols= None):
            self._n= p.shape[1]
            self._root, self._p= _create_tree(p, r0, scale, tols)
    
        def traverse(self, f, order= pre_order, cs= 'Cartesian'):
            self.points= self._p
            if cs is 'Cartesian':
                self.points= from_polar(self._p)
            order(self, self._root, f, 0)
            return self
    
        def simplify(self):
            self._root= _simplify(self)
            return self
    
        def is_root(self, ndx):
            return ndx== self._p.shape[1]- 1
    
        def is_leaf(self, ndx):
            return ndx< self._n
    
    if __name__ == '__main__':
        # ToDO: add tests
        from numpy import r_, round
        from numpy.random import rand
        from pylab import plot, show
    
        def _l(t, n, l):
            # print round(a, 3), n, l, t.is_root(n[0]), t.is_leaf(n[1])
            plot(t.points[0, n], t.points[1, n])
            if 0== l:
                plot(t.points[0, n[0]], t.points[1, n[0]], 's')
            if t.is_leaf(n[1]):
                plot(t.points[0, n[1]], t.points[1, n[1]], 'o')
    
        n= 123
        p= r_[2* pi* rand(1, n)- pi, ones((1, n))]
        t= tree(p).simplify().traverse(_l)
        # t= tree(p).traverse(_l, cs= 'Polar')
        show()
        # print
        # t.traverse(_l, post_order, cs= 'Polar')
    

    radial_support.py:

    """All supporting functionality is collected here."""
    from numpy import r_, arctan2, cos, sin
    from numpy import atleast_2d as a2d
    
    # ToDo: create proper documentation strings
    def _a(a0, a1):
        return r_[a2d(a0), a2d(a1)]
    
    def from_polar(p):
        """(theta, radius) to (x, y)."""
        return _a(cos(p[0])* p[1], sin(p[0])* p[1])
    
    def to_polar(c):
        """(x, y) to (theta, radius)."""
        return _a(arctan2(c[1], c[0]), (c** 2).sum(0)** .5)
    
    def d_to_polar(D):
        """Distance matrix to (theta, radius)."""
        # this functionality is to adopt for more general situations
        # intended functionality:
        # - embedd distance matrix to 2D
        # - return that embedding in polar coordinates
        pass
    
    if __name__ == '__main__':
        from numpy import allclose
        from numpy.random import randn
        c= randn(2, 5)
        assert(allclose(c, from_polar(to_polar(c))))
    
        # ToDO: implement more tests
    

    radial_visualizer.py:

    """All visualization functionality is collected here."""
    from pylab import plot
    
    # ToDo: create proper documentation
    def simple_link(t, ndx, level):
        """Simple_link is just a minimal example to demonstrate what can be
        achieved when it's called from _grouper.tree.traverse for each link.
        - t, tree instance
        - ndx, a pair of (from, to) indicies
        - level, of from, i.e. root is in level 0
        """
        plot(t.points[0, ndx], t.points[1, ndx])
        if 0== level:
            plot(t.points[0, ndx[0]], t.points[1, ndx[0]], 's')
        if t.is_leaf(ndx[1]):
            plot(t.points[0, ndx[1]], t.points[1, ndx[1]], 'o')
    
    # ToDO: implement more suitable link visualizers
    # No doubt, this will the part to burn most of the dev. resources
    
    if __name__ == '__main__':
        # ToDO: implement tests
        pass
    

    여기서 소스 코드를 찾을 수 있습니다. 어쨌든 마음에 들지 않게 고쳐 주시고 추후 수정 사항을 요지와 동기화하십시오.

  2. ==============================

    2.matplotlib와 함께 networkx 패키지를 사용하여이 작업을 수행 할 수 있다고 생각합니다. networkx 갤러리에서 다음 예제를 확인하십시오.

    matplotlib와 함께 networkx 패키지를 사용하여이 작업을 수행 할 수 있다고 생각합니다. networkx 갤러리에서 다음 예제를 확인하십시오.

    http://networkx.lanl.gov/examples/drawing/circular_tree.html

    일반적으로 networkx에는 많은 훌륭한 그래프 분석 및 플로팅 방법이 있습니다.

  3. ==============================

    3.나는 dendrogram에서 각 "U"의 밑에 정점들을 합쳐주는 fix_verts 함수를 추가했다.

    나는 dendrogram에서 각 "U"의 밑에 정점들을 합쳐주는 fix_verts 함수를 추가했다.

    이 시도:

    import scipy
    import pylab
    import scipy.cluster.hierarchy as sch
    
    def fix_verts(ax, orient=1):
        for coll in ax.collections:
            for pth in coll.get_paths():
                vert = pth.vertices
                vert[1:3,orient] = scipy.average(vert[1:3,orient]) 
    
    # Generate random features and distance matrix.
    x = scipy.rand(40)
    D = scipy.zeros([40,40])
    for i in range(40):
        for j in range(40):
            D[i,j] = abs(x[i] - x[j])
    
    
    fig = pylab.figure(figsize=(8,8))
    
    # Compute and plot first dendrogram.
    ax1 = fig.add_axes([0.09,0.1,0.2,0.6])
    Y = sch.linkage(D, method='centroid')
    Z1 = sch.dendrogram(Y, orientation='right')
    ax1.set_xticks([])
    ax1.set_yticks([])
    
    # Compute and plot second dendrogram.
    ax2 = fig.add_axes([0.3,0.71,0.6,0.2])
    Y = sch.linkage(D, method='single')
    Z2 = sch.dendrogram(Y)
    ax2.set_xticks([])
    ax2.set_yticks([])
    
    # Plot distance matrix.
    axmatrix = fig.add_axes([0.3,0.1,0.6,0.6])
    idx1 = Z1['leaves']
    idx2 = Z2['leaves']
    D = D[idx1,:]
    D = D[:,idx2]
    im = axmatrix.matshow(D, aspect='auto', origin='lower', cmap=pylab.cm.YlGnBu)
    axmatrix.set_xticks([])
    fix_verts(ax1,1)
    fix_verts(ax2,0)
    fig.savefig('test.png')
    

    결과는 다음과 같습니다.

    그게 네가 한 일이되기를 바란다.

  4. from https://stackoverflow.com/questions/5089030/how-do-i-create-a-radial-cluster-like-the-following-code-example-in-python by cc-by-sa and MIT license