Рисование дендрограммы

Интерпретацию кластеров можно облегчить, если изобразить их в виде дендрограммы. Результаты иерархической кластеризации обычно так и представляются, поскольку дендрограмма позволяет уместить большой объем информации в сравнительно малом пространстве. Поскольку дендрограммы – графические изображения и сохраняются в формате JPG, то нам понадобится библиотека Python Imaging Library (PIL), которую можно скачать с сайта http://pythonware.com. Библиотека поставляется в виде инсталлятора для Windows и набора исходных файлов для других платформ. Дополнительная информация о загрузке и установке PIL имеется в приложении A. Библиотека PIL позволяет легко генерировать изображения, состоящие из текста и линий, а для построения дендрограммы больше ничего и не нужно. Добавьте в начало файла clusters.py предложение import:

from PIL import Image,ImageDraw Прежде всего мы воспользуемся функцией, которая возвращает полную высоту кластера. Чтобы определить высоту изображения и понять, где расставлять узлы, необходимо знать высоту каждого кластера. Если кластер представлен листовым узлом (то есть от него не отходят ветви), то его высота равна 1. В противном случае высота кластера равна сумме высот его потомков. Высоту легко вычислить с помощью рекурсивной функции, которую мы добавим в файл clusters.py: def getheight(clust):

#    Это листовый узел? Тогда высота равна 1

if clust.left==None and clust.right==None: return 1

#    Иначе высота равна сумме высот обеих ветвей

return getheight(clust.left)+getheight(clust.right)

Еще нам нужно знать полную ошибку в корневом узле. Поскольку длина линий зависит от величины ошибки в каждом узле, то коэффициент масштабирования будет вычисляться в зависимости от полной ошибки. Ошибка в узле – это просто максимум из значений ошибки обоих его потомков:

def getdepth(clust):

#       Расстояние для листового узла равно 0,0

if clust.left==None and clust.right==None: return 0

#       Расстояние для внутреннего узла равно максимуму из расстояний обеих ветвей

#       плюс его собственное расстояние

return max(getdepth(clust.left),getdepth(clust.right))+clust.distance Функция drawdendrogram создает новое изображение высотой 20 пикселей и фиксированной шириной для каждого кластера. Коэффициент масштабирования определяется путем деления фиксированной ширины на полную глубину. Функция создает объект рисования этого изображения и затем вызывает функцию drawnode для корневого узла, сообщая, что его следует расположить на полпути вниз вдоль левого края изображения.

def drawdendrogram(clust,labels,]peg=’clusters.]pg’):

#       высота и ширина h=getheight(clust)*20 w=1200

depth=getdepth(clust)

#       ширина фиксирована, расстояния масштабируются scaling=float(w-150)/depth

#       создать новое изображение на белом фоне img=Image.new(‘RGB’,(w,h),(255,255,255)) draw=ImageDraw.Draw(img)

draw.line((0,h/2,10,h/2),fill=(255,0,0))

#       нарисовать первый узел drawnode(draw,clust,10,(h/2),scaling,labels) img.save(jpeg,’JPEG’)

Самой важной является функция drawnode, которая принимает кластер и его положение. Она получает высоты дочерних узлов, вычисляет, в каком месте они должны располагаться, и проводит ведущие к ним линии – одну длинную вертикальную и две горизонтальные. Длины горизонтальных линий определяются накопленной в этом кластере ошибкой. Если линия длинная, значит, кластеры, объединением которых был получен данный кластер, были не очень-то похожи. А короткая линия означает, что они были почти идентичны. Добавьте функцию drawnode в файл clusters.py:

def drawnode(draw,clust,x,y,scaling,labels): if clust.id<0: h1=getheight(clust.left)*20 h2=getheight(clust.right)*20

Рис. 3.3. Дендрограмма, иллюстрирующая кластеры блогов

top=y-(h1+h2)/2 bottom=y+(h1+h2)/2

#      Длина линии ll=clust.distance*scaling

#      Вертикальная линия от данного кластера к его потомкам draw.line((x,top+h1/2,x,bottom-h2/2),fill=(255,0,0))

#      Горизонтальная линия к левому потомку draw.line((x,top+h1/2,x+ll,top+h1/2),fill=(255,0,0))

#      Горизонтальная линия к правому потомку draw.line((x,bottom-h2/2,x+ll,bottom-h2/2),fill=(255,0,0))

#      Вызываем функцию для изображения левого и правого потомков drawnode(draw,clust.left,x+ll,top+h1/2,scaling,labels) drawnode(draw,clust.right,x+ll,bottom-h2/2,scaling,labels)

else:

#      Если это листовый узел, рисуем метку draw.text((x+5,y-7),labels[clust.id],(0,0,0))

Чтобы сгенерировать изображение, введите в интерактивном сеансе следующие команды: >> reload(clusters)

>> clusters.drawdendrogram(clust,blognames,jpeg=’blogclust.jpg’) В результате будет создан файл blogclust.jpg, содержащий дендрограм- му, которая должна быть похожа на ту, что изображена на рис. 3.3. Если хотите, можете изменить настройки высоты и ширины, чтобы рисунок было проще напечатать или чтобы он был более разреженным.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100