FeatureWeights.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /* FeatureWeights.cpp
  2. *
  3. * Copyright (C) 2007-2008 Ola So"der, 2010-2012,2015,2016,2017 Paul Boersma
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. * os 2007/05/29 Initial release
  20. * pb 2010/06/06 removed some array-creations-on-the-stack
  21. * pb 2011/03/08 tried to repair some of the header file chaos (several
  22. * procedures here should be in KNN.c instead) pb 2011/04/12 C++
  23. */
  24. #include "FeatureWeights.h"
  25. #include "KNN.h" // BUG
  26. #include "oo_DESTROY.h"
  27. #include "FeatureWeights_def.h"
  28. #include "oo_COPY.h"
  29. #include "FeatureWeights_def.h"
  30. #include "oo_EQUAL.h"
  31. #include "FeatureWeights_def.h"
  32. #include "oo_CAN_WRITE_AS_ENCODING.h"
  33. #include "FeatureWeights_def.h"
  34. #include "oo_WRITE_TEXT.h"
  35. #include "FeatureWeights_def.h"
  36. #include "oo_WRITE_BINARY.h"
  37. #include "FeatureWeights_def.h"
  38. #include "oo_READ_TEXT.h"
  39. #include "FeatureWeights_def.h"
  40. #include "oo_READ_BINARY.h"
  41. #include "FeatureWeights_def.h"
  42. #include "oo_DESCRIPTION.h"
  43. #include "FeatureWeights_def.h"
  44. void structFeatureWeights ::v_info () {
  45. our structDaata ::v_info ();
  46. MelderInfo_writeLine (
  47. U"Number of weights: ", our fweights->numberOfColumns);
  48. }
  49. Thing_implement (FeatureWeights, Daata, 0);
  50. /////////////////////////////////////////////////////////////////////////////////////////////
  51. // Creation... //
  52. /////////////////////////////////////////////////////////////////////////////////////////////
  53. autoFeatureWeights FeatureWeights_create (
  54. ///////////////////////////////
  55. // Parameters //
  56. ///////////////////////////////
  57. integer nweights // number of weights
  58. )
  59. {
  60. try {
  61. autoFeatureWeights me = Thing_new (FeatureWeights);
  62. my fweights = TableOfReal_create (1, nweights);
  63. for (integer i = 1; i <= nweights; i++) { my fweights->data[1][i] = 1; }
  64. return me;
  65. } catch (MelderError) { Melder_throw (U"FeatureWeights not created."); }
  66. }
  67. /////////////////////////////////////////////////////////////////////////////////////////////
  68. // Compute prior probabilities //
  69. /////////////////////////////////////////////////////////////////////////////////////////////
  70. integer FeatureWeights_computePriors (
  71. ///////////////////////////////
  72. // Parameters //
  73. ///////////////////////////////
  74. Categories c, // source categories
  75. //
  76. integer *indices, // Out: instances indices ..
  77. //
  78. double *priors // Out: .. and their prior probabilities
  79. //
  80. )
  81. {
  82. integer nc = 0;
  83. for (integer y = 1; y <= c->size; y++) {
  84. integer ifriend = -1;
  85. for (integer sc = 0; sc < nc; sc++)
  86. if (FeatureWeights_areFriends (c->at[y], c->at[indices[sc]]))
  87. ifriend = sc;
  88. if (ifriend < 0) {
  89. indices[nc] = y;
  90. priors[nc] = 1;
  91. nc++;
  92. } else {
  93. priors[ifriend]++;
  94. }
  95. }
  96. for (integer q = 0; q < nc; q++) priors[q] /= c->size;
  97. return nc;
  98. }
  99. /////////////////////////////////////////////////////////////////////////////////////////////
  100. // Compute feature weights //
  101. /////////////////////////////////////////////////////////////////////////////////////////////
  102. autoFeatureWeights FeatureWeights_compute // Obsolete
  103. (
  104. ///////////////////////////////
  105. // Parameters //
  106. ///////////////////////////////
  107. PatternList pp, // Source pattern
  108. //
  109. Categories c, // Source categories
  110. //
  111. integer k // k(!)
  112. )
  113. {
  114. return FeatureWeights_computeRELIEF (pp, c, k);
  115. }
  116. /////////////////////////////////////////////////////////////////////////////////////////////
  117. // Compute feature weights (wrapper), evaluate using folding //
  118. /////////////////////////////////////////////////////////////////////////////////////////////
  119. autoFeatureWeights FeatureWeights_computeWrapperInt (
  120. ///////////////////////////////
  121. // Parameters //
  122. ///////////////////////////////
  123. KNN me, // Classifier
  124. //
  125. integer k, // k(!)
  126. //
  127. int d, // distance weighting
  128. //
  129. integer nseeds, // the number of seeds
  130. //
  131. double alfa, // shrinkage factor
  132. //
  133. double stop, // stop at
  134. //
  135. int mode, // mode (co/serial)
  136. //
  137. int emode // evaluation mode (10-fold/L1O)
  138. //
  139. )
  140. {
  141. if (!me) return autoFeatureWeights ();
  142. try {
  143. double pivot = 0.5;
  144. double range = 0.5;
  145. autoNUMvector<double> results ((integer)0, nseeds);
  146. autoThingVector<structFeatureWeights> cs ((integer)0, nseeds);
  147. for (integer y = 0; y <= nseeds; y++) {
  148. cs[y] = FeatureWeights_create (my input->nx);
  149. }
  150. for (integer x = 1; x <= my input->nx; x++)
  151. cs[nseeds]->fweights->data[1][x] = pivot;
  152. results[nseeds] = KNN_evaluate (me, cs[nseeds].get (), k, d, emode);
  153. while (range > 0 && results[nseeds] < stop) {
  154. integer best = nseeds;
  155. if (mode == 2) {
  156. for (integer x = 1; x <= (my input)->nx; x++) {
  157. for (integer y = 0; y < nseeds; y++) {
  158. cs[y]->fweights->data[1][x] = NUMrandomUniform (
  159. OlaMAX (0, cs[nseeds]->fweights->data[1][x] - range),
  160. OlaMIN (1, cs[nseeds]->fweights->data[1][x] + range));
  161. results[y] =
  162. KNN_evaluate (me, cs[y].get (), k, d, emode);
  163. }
  164. for (integer q = 0; q < nseeds; q++)
  165. if (results[q] > results[best]) best = q;
  166. if (results[best] > results[nseeds]) {
  167. for (integer x = 1; x <= (my input)->nx;
  168. x++) // HELP FIXME the same index for an inner
  169. // and an outer loop!!!
  170. cs[nseeds]->fweights->data[1][x] =
  171. cs[best]->fweights->data[1][x];
  172. results[nseeds] = results[best];
  173. }
  174. }
  175. } else {
  176. for (integer y = 0; y < nseeds; y++) {
  177. for (integer x = 1; x <= (my input)->nx; x++) {
  178. cs[y]->fweights->data[1][x] = NUMrandomUniform (
  179. OlaMAX (0, cs[nseeds]->fweights->data[1][x] - range),
  180. OlaMIN (1, cs[nseeds]->fweights->data[1][x] + range));
  181. }
  182. results[y] = KNN_evaluate (me, cs[y].get (), k, d, emode);
  183. }
  184. for (integer q = 0; q < nseeds; q++)
  185. if (results[q] > results[best]) best = q;
  186. if (results[best] > results[nseeds]) {
  187. for (integer x = 1; x <= (my input)->nx; x++)
  188. cs[nseeds]->fweights->data[1][x] =
  189. cs[best]->fweights->data[1][x];
  190. results[nseeds] = results[best];
  191. }
  192. }
  193. range -= alfa;
  194. }
  195. autoFeatureWeights result = cs[nseeds].move ();
  196. return result;
  197. } catch (MelderError) {
  198. Melder_throw (U"FeatureWeights: wrapper not computed.");
  199. }
  200. }
  201. /////////////////////////////////////////////////////////////////////////////////////////////
  202. // Compute feature weights (wrapper), evaluate using separate test set //
  203. /////////////////////////////////////////////////////////////////////////////////////////////
  204. autoFeatureWeights FeatureWeights_computeWrapperExt (
  205. ///////////////////////////////
  206. // Parameters //
  207. ///////////////////////////////
  208. KNN nn, // Classifier
  209. //
  210. PatternList pp, // test pattern
  211. //
  212. Categories c, // test categories
  213. //
  214. integer k, // k(!)
  215. //
  216. int d, // distance weighting
  217. //
  218. integer nseeds, // the number of seeds
  219. //
  220. double alfa, // shrinkage factor
  221. //
  222. double stop, // stop at
  223. //
  224. int mode // mode (co/serial)
  225. //
  226. )
  227. {
  228. if (!nn) return autoFeatureWeights ();
  229. try {
  230. double pivot = 0.5;
  231. double range = 0.5;
  232. autoNUMvector<double> results ((integer)0, nseeds);
  233. autoThingVector<structFeatureWeights> cs ((integer)0, nseeds);
  234. for (integer y = 0; y <= nseeds; y++) {
  235. cs[y] = FeatureWeights_create (pp->nx);
  236. }
  237. for (integer x = 1; x <= pp->nx; x++)
  238. cs[nseeds]->fweights->data[1][x] = pivot;
  239. results[nseeds] =
  240. FeatureWeights_evaluate (cs[nseeds].get (), nn, pp, c, k, d);
  241. while (range > 0 && results[nseeds] < stop) {
  242. integer best = nseeds;
  243. if (mode == 2) {
  244. for (integer x = 1; x <= pp->nx; x++) {
  245. for (integer y = 0; y < nseeds; y++) {
  246. cs[y]->fweights->data[1][x] = NUMrandomUniform (
  247. OlaMAX (0, cs[nseeds]->fweights->data[1][x] - range),
  248. OlaMIN (1, cs[nseeds]->fweights->data[1][x] + range));
  249. results[y] = FeatureWeights_evaluate (
  250. cs[y].get (), nn, pp, c, k, d);
  251. }
  252. for (integer q = 0; q < nseeds; q++) {
  253. if (results[q] > results[best]) best = q;
  254. }
  255. if (results[best] > results[nseeds]) {
  256. for (integer x = 1; x <= pp->nx;
  257. x++) // BUG: a loop over x inside a loop over
  258. // x; just hope mode is never 2
  259. {
  260. cs[nseeds]->fweights->data[1][x] =
  261. cs[best]->fweights->data[1][x];
  262. }
  263. results[nseeds] = results[best];
  264. }
  265. }
  266. } else {
  267. for (integer y = 0; y < nseeds; y++) {
  268. for (integer x = 1; x <= pp->nx; x++) {
  269. cs[y]->fweights->data[1][x] = NUMrandomUniform (
  270. OlaMAX (0, cs[nseeds]->fweights->data[1][x] - range),
  271. OlaMIN (1, cs[nseeds]->fweights->data[1][x] + range));
  272. }
  273. results[y] =
  274. FeatureWeights_evaluate (cs[y].get (), nn, pp, c, k, d);
  275. }
  276. for (integer q = 0; q < nseeds; q++) {
  277. if (results[q] > results[best]) best = q;
  278. }
  279. if (results[best] > results[nseeds]) {
  280. for (integer x = 1; x <= pp->nx; x++)
  281. cs[nseeds]->fweights->data[1][x] =
  282. cs[best]->fweights->data[1][x];
  283. results[nseeds] = results[best];
  284. }
  285. }
  286. range -= alfa;
  287. }
  288. autoFeatureWeights result = cs[nseeds].move ();
  289. return result;
  290. } catch (MelderError) {
  291. Melder_throw (U"FeatureWeights: wrapper not computed.");
  292. }
  293. }
  294. /////////////////////////////////////////////////////////////////////////////////////////////
  295. // Evaluate feature weights, wrapper aux. //
  296. /////////////////////////////////////////////////////////////////////////////////////////////
  297. double FeatureWeights_evaluate // Obsolete - use *_EvaluateWithTestSet
  298. // instead
  299. (
  300. ///////////////////////////////
  301. // Parameters //
  302. ///////////////////////////////
  303. FeatureWeights fws, // Weights to evaluate
  304. //
  305. KNN nn, // Classifier
  306. //
  307. PatternList pp, // test pattern
  308. //
  309. Categories c, // test categories
  310. //
  311. integer k, // k(!)
  312. //
  313. int d // distance weighting
  314. //
  315. )
  316. {
  317. try {
  318. autoCategories o = KNN_classifyToCategories (nn, pp, fws, k, d);
  319. double hits = 0.0;
  320. for (integer y = 1; y <= o->size; y++)
  321. if (FeatureWeights_areFriends (o->at[y], c->at[y])) hits++;
  322. hits /= o->size;
  323. return hits;
  324. } catch (MelderError) { throw; }
  325. }
  326. /////////////////////////////////////////////////////////////////////////////////////////////
  327. // Compute feature weights according to the RELIEF-F algorithm //
  328. /////////////////////////////////////////////////////////////////////////////////////////////
  329. autoFeatureWeights FeatureWeights_computeRELIEF (
  330. ///////////////////////////////
  331. // Parameters //
  332. ///////////////////////////////
  333. PatternList pp, // source pattern
  334. //
  335. Categories c, // source categories
  336. //
  337. integer k // k(!)
  338. //
  339. )
  340. {
  341. autoPatternList p = Data_copy (pp);
  342. autoFeatureWeights me = FeatureWeights_create (p->nx);
  343. /////////////////////////////////
  344. // Initial weights <- 0 //
  345. /////////////////////////////////
  346. for (integer i = 1; i <= p->nx; i++) { my fweights->data[1][i] = 0.0; }
  347. /////////////////////////////////
  348. // Normalization //
  349. /////////////////////////////////
  350. autoNUMvector<double> min ((integer)0, p->nx - 1);
  351. autoNUMvector<double> max ((integer)0, p->nx - 1);
  352. for (integer x = 1; x <= p->nx; x++) {
  353. max[x] = p->z[1][x]; // BUG: this will just crash because of
  354. // array index out of bounds
  355. min[x] = max[x];
  356. }
  357. for (integer y = 1; y <= p->ny; y++) {
  358. for (integer x = 1; x <= p->nx; x++) {
  359. if (p->z[y][x] > max[x]) max[x] = p->z[y][x];
  360. if (p->z[y][x] < min[x]) min[x] = p->z[y][x];
  361. }
  362. }
  363. autoNUMvector<double> alfa ((integer)0, p->nx - 1);
  364. for (integer x = 1; x <= p->nx; x++) {
  365. alfa[x] = max[x] - min[x]; // BUG: this will just crash because of
  366. // array index out of bounds
  367. }
  368. for (integer y = 1; y <= p->ny; y++) {
  369. for (integer x = 1; x <= p->nx; x++) {
  370. if (alfa[x] != 0.0) {
  371. p->z[y][x] = (p->z[y][x] - min[x]) / alfa[x];
  372. } else {
  373. p->z[y][x] = 0.0;
  374. }
  375. }
  376. }
  377. /////////////////////////////////
  378. // Computing prior class probs //
  379. /////////////////////////////////
  380. autoNUMvector<double> priors (
  381. (integer) 0, c->size - 1); // worst-case allocations
  382. autoNUMvector<integer> classes ((integer) 0, c->size - 1); //
  383. autoNUMvector<integer> enemies ((integer) 0, c->size - 1); //
  384. autoNUMvector<integer> friends ((integer) 0, c->size - 1); //
  385. integer nclasses =
  386. FeatureWeights_computePriors (c, classes.peek (), priors.peek ());
  387. Melder_assert (nclasses >= 2);
  388. /////////////////////////////////
  389. // Updating the w.vector //
  390. /////////////////////////////////
  391. for (integer y = 1; y <= p->ny; y++) {
  392. integer nfriends =
  393. KNN_kFriends (p.get (), p.get (), c, y, k, friends.peek ());
  394. integer nenemies = KNN_kUniqueEnemies (
  395. p.get (), p.get (), c, y, nclasses - 1, enemies.peek ());
  396. if (nfriends && nenemies) {
  397. autoNUMvector<double> classps ((integer)0, nenemies - 1);
  398. for (integer eq = 0; eq < nenemies; eq++) {
  399. for (integer iq = 0; iq < nclasses; iq++) {
  400. if (FeatureWeights_areFriends (
  401. c->at[enemies[eq]], c->at[classes[iq]])) {
  402. classps[eq] = priors[iq];
  403. break;
  404. }
  405. }
  406. }
  407. for (integer x = 1; x <= p->nx; x++) {
  408. double p1 = 0.0;
  409. double p2 = 0.0;
  410. for (integer ec = 0; ec < nfriends; ec++) {
  411. p1 += fabs (p->z[y][x] - p->z[friends[ec]][x]) /
  412. (p->ny * nfriends);
  413. }
  414. for (integer ec = 0; ec < nenemies; ec++) {
  415. p2 += (fabs (p->z[y][x] - p->z[enemies[ec]][x]) *
  416. classps[ec]) /
  417. p->ny;
  418. }
  419. my fweights->data[1][x] = my fweights->data[1][x] - p1 + p2;
  420. }
  421. }
  422. }
  423. return me;
  424. }
  425. /* End of file FeatureWeights.cpp */