HierarchicalCluster.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /**
  2. * @file HierarchicalCluster.cpp
  3. * @brief Hierarchical Clustering wrapper
  4. * @author Michael Koch
  5. * @date 10/25/2010
  6. */
  7. #ifdef NOVISUAL
  8. #include <vislearning/nice_nonvis.h>
  9. #else
  10. #include <vislearning/nice.h>
  11. #endif
  12. #include <iostream>
  13. #include <core/vector/Distance.h>
  14. #include "vislearning/math/cluster/HierarchicalCluster.h"
  15. #include "vislearning/math/cluster/cluster.h"
  16. #include <set>
  17. #undef max
  18. #undef min
  19. #include <limits>
  20. using namespace OBJREC;
  21. using namespace std;
  22. using namespace NICE;
  23. #undef DEBUG_HierarchicalCluster
  24. HierarchicalCluster::HierarchicalCluster(int _noClasses, char _method,
  25. int _distanceType) :
  26. noClasses(_noClasses), method(_method), distanceType(_distanceType)
  27. {
  28. srand(time(NULL));
  29. }
  30. HierarchicalCluster::~HierarchicalCluster()
  31. {
  32. }
  33. void HierarchicalCluster::cluster(const VVector & features,
  34. VVector & prototypes, std::vector<double> & weights,
  35. std::vector<int> & assignment)
  36. {
  37. double double_max = std::numeric_limits<double>::max();
  38. if (features.size() <= 1)
  39. {
  40. prototypes=features;
  41. }
  42. else
  43. {
  44. int featureamount = features.size();
  45. int dimension = features[0].size();
  46. double **data;
  47. int **mask;
  48. VVectorToDoubleArray(features, data, mask);
  49. double * weightpointer = new double[dimension];
  50. for (uint i = 0; i < dimension; i++)
  51. {
  52. if (i < weights.size())
  53. {
  54. weightpointer[i] = weights[i];
  55. }
  56. else
  57. {
  58. weightpointer[i] = 1.0;
  59. }
  60. }
  61. int transpose = 0;
  62. double ** distmatrix = NULL;
  63. Node * nodes = treecluster(featureamount, dimension, data, mask,
  64. weightpointer, transpose, distanceFunction(distanceType),
  65. method, distmatrix);
  66. std::vector<double> distances;
  67. for (int i = 0; i < featureamount; i++)
  68. {
  69. Node currentnode = nodes[i];
  70. if (currentnode.distance < double_max)
  71. {
  72. distances.push_back(currentnode.distance);
  73. }
  74. }
  75. //TODO cluster estimation refactor without cluster.h in HierarchicalCluster.h
  76. if (noClasses <= 0)
  77. {
  78. std::sort(distances.begin(), distances.end());
  79. std::vector<double> gradient;
  80. std::vector<int> cuts;
  81. size_t count = 0;
  82. double last_element;
  83. for (size_t i = 0; i < distances.size(); i++)
  84. {
  85. if (count > 0)
  86. {
  87. gradient.push_back(distances[i] - last_element);
  88. }
  89. last_element = distances[i];
  90. count++;
  91. }
  92. size_t pos_max = 0;
  93. double max;
  94. if (gradient.size() > 0)
  95. {
  96. max = gradient[0];
  97. for (size_t i = 1; i < gradient.size(); i++)
  98. {
  99. if (gradient[i] > max)
  100. {
  101. max = gradient[i];
  102. pos_max = i;
  103. }
  104. }
  105. }
  106. size_t pos_reject = pos_max + 1;
  107. double distance_reject = distances[pos_reject];
  108. for (size_t i = 0; i < featureamount; i++)
  109. {
  110. if (nodes[i].distance < double_max && nodes[i].distance
  111. >= distance_reject)
  112. {
  113. cuts.push_back(2);
  114. }
  115. else
  116. {
  117. cuts.push_back(0);
  118. }
  119. }
  120. bool change = true;
  121. while (change)
  122. {
  123. change = false;
  124. for (size_t i = 0; i < featureamount; i++)
  125. {
  126. if (cuts[i] > 0 && nodes[i].distance < double_max
  127. && nodes[i].distance >= distance_reject)
  128. {
  129. if (nodes[i].left < 0)
  130. {
  131. int pos_left = -nodes[i].left - 1;
  132. if (cuts[pos_left] > 0)
  133. {
  134. if (cuts[i] > 0)
  135. {
  136. cuts[i]--;
  137. change = true;
  138. }
  139. }
  140. }
  141. if (nodes[i].right < 0)
  142. {
  143. int pos_right = -nodes[i].right - 1;
  144. if (cuts[pos_right] > 0)
  145. {
  146. if (cuts[i] > 0)
  147. {
  148. cuts[i]--;
  149. change = true;
  150. }
  151. }
  152. }
  153. }
  154. }
  155. }
  156. noClasses = 0;
  157. for (int i = 0; i < featureamount; i++)
  158. {
  159. noClasses += cuts[i];
  160. }
  161. }
  162. int clusterassignment[featureamount];
  163. cuttree(featureamount, nodes, noClasses, clusterassignment);
  164. // assignment.clear();
  165. for (int i = 0; i < featureamount; i++)
  166. {
  167. if (clusterassignment[i] >= 0)
  168. {
  169. assignment.push_back(clusterassignment[i]);
  170. }
  171. }
  172. prototypes.clear();
  173. for (int k = 0; k < noClasses; k++)
  174. {
  175. prototypes.push_back(Vector(dimension));
  176. prototypes[k].set(0);
  177. weights.push_back(0);
  178. }
  179. compute_prototypes(features, prototypes, weights, assignment);
  180. }
  181. }
  182. void HierarchicalCluster::VVectorToDoubleArray(const VVector &data,
  183. double ** &doublearray, int ** &mask)
  184. {
  185. if (data.size() > 0)
  186. {
  187. int featureamount = data.size();
  188. int dimension = data[0].size();
  189. doublearray = new double*[featureamount];
  190. mask = new int*[featureamount];
  191. for (int i = 0; i < featureamount; ++i)
  192. {
  193. doublearray[i] = new double[dimension];
  194. mask[i] = new int[dimension];
  195. }
  196. for (int row = 0; row < featureamount; row++)
  197. {
  198. for (int col = 0; col < dimension; col++)
  199. {
  200. doublearray[row][col] = data[row][col];
  201. if (isNaN(data[row][col]))
  202. {
  203. mask[row][col] = 0;
  204. }
  205. else
  206. {
  207. mask[row][col] = 1;
  208. }
  209. }
  210. }
  211. }
  212. }
  213. //TODO find better space for that one and refactor with enum
  214. char HierarchicalCluster::distanceFunction(int distancetype)
  215. {
  216. // dist (input) char
  217. // Defines which distance measure is used, as given by the table:
  218. // dist=='e': Euclidean distance
  219. // dist=='b': City-block distance
  220. // dist=='c': correlation
  221. // dist=='a': absolute value of the correlation
  222. // dist=='u': uncentered correlation
  223. // dist=='x': absolute uncentered correlation
  224. // dist=='s': Spearman's rank correlation
  225. // dist=='k': Kendall's tau
  226. // For other values of dist, the default (Euclidean distance) is used.
  227. char type = 'e';
  228. switch (distancetype)
  229. {
  230. case 0:
  231. {
  232. type = 'e';
  233. }
  234. break;
  235. case 1:
  236. {
  237. type = 'b';
  238. }
  239. break;
  240. case 2:
  241. {
  242. type = 'c';
  243. }
  244. break;
  245. case 3:
  246. {
  247. type = 'a';
  248. }
  249. break;
  250. case 4:
  251. {
  252. type = 'u';
  253. }
  254. break;
  255. case 5:
  256. {
  257. type = 'x';
  258. }
  259. break;
  260. case 6:
  261. {
  262. type = 's';
  263. }
  264. break;
  265. case 7:
  266. {
  267. type = 'k';
  268. }
  269. break;
  270. default:
  271. type = 'e';
  272. break;
  273. }
  274. return type;
  275. }
  276. int HierarchicalCluster::compute_prototypes(const VVector & features,
  277. VVector & prototypes, std::vector<double> & weights, const std::vector<
  278. int> & assignment)
  279. {
  280. int j = 0;
  281. for (int k = 0; k < noClasses; k++)
  282. {
  283. prototypes[k].set(0);
  284. weights[k] = 0;
  285. }
  286. for (VVector::const_iterator i = features.begin(); i != features.end(); i++, j++)
  287. {
  288. int k = assignment[j];
  289. NICE::Vector & p = prototypes[k];
  290. const NICE::Vector & x = *i;
  291. p += x;
  292. weights[k]++;
  293. }
  294. for (int k = 0; k < noClasses; k++)
  295. {
  296. NICE::Vector & p = prototypes[k];
  297. if (weights[k] <= 0)
  298. {
  299. return -1;
  300. }
  301. p *= (1.0 / weights[k]);
  302. weights[k] = weights[k] / features.size();
  303. }
  304. return 0;
  305. }