📄 barrel.c
字号:
/* Managing the connection between document-vectors (wi2dvf's) and cdocs Copyright (C) 1997, 1998, 1999 Andrew McCallum Written by: Andrew Kachites McCallum <mccallum@cs.cmu.edu> This file is part of the Bag-Of-Words Library, `libbow'. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation, version 2. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA */#include <bow/libbow.h>#include <values.h>static int _bow_barrel_version = -1;#define BOW_DEFAULT_BARREL_VERSION 3/* Create a new, empty `bow_barrel', with cdoc's of size ENTRY_SIZE and cdoc free function FREE_FUNC.*/bow_barrel *bow_barrel_new (int word_capacity, int class_capacity, int entry_size, void (*free_func)()){ bow_barrel *ret; ret = bow_malloc (sizeof (bow_barrel)); ret->method = (rainbow_method*) (bow_argp_method ? : bow_method_at_name (bow_default_method_name)); ret->cdocs = bow_array_new (class_capacity, entry_size, free_func); ret->wi2dvf = bow_wi2dvf_new (word_capacity); ret->classnames = NULL; /* return a document barrel by default */ ret->is_vpc = 0; return ret;}static void_bow_barrel_cdoc_free (bow_cdoc *cdoc){ if (cdoc->filename) free ((void*)(cdoc->filename)); if (cdoc->class_probs) free ((void*)(cdoc->class_probs));}/* Add statistics about the document described by CDOC and WV to the BARREL. */intbow_barrel_add_document (bow_barrel *barrel, bow_cdoc *cdoc, bow_wv *wv){ int di; /* Add the CDOC. (This makes a new copy of CDOC in the array.) */ di = bow_array_append (barrel->cdocs, cdoc); /* Add the words in WV. */ bow_wi2dvf_add_di_wv (&(barrel->wi2dvf), di, wv); /* xxx Why is this assert here? */ assert (barrel->classnames == NULL); return di;}/* Add statistics to the barrel BARREL by indexing all the documents found when recursively decending directory DIRNAME. Return the number of additional documents indexed. */intbow_barrel_add_from_text_dir (bow_barrel *barrel, const char *dirname, const char *except_name, const char *classname){ int text_file_count, binary_file_count; int class;#ifdef VPC_ONLY /* Used when we are building a class barrel */ bow_cdoc cdoc; bow_cdoc *cdocp; int word_count = 0; int di; /* Function used to build a multinomial vpc barrel without building a * document barrel */ int class_barrel_index_file (const char *filename, void *context) { FILE *fp; int num_words; /* If the filename matches the exception name, return immediately. */ if (except_name && !strcmp (filename, except_name)) return 0; if (!(fp = fopen (filename, "r"))) { bow_verbosify (bow_progress, "Couldn't open file `%s' for reading.", filename); return 0; } if (bow_fp_is_text (fp)) { /* Add all the words in this document. */ num_words = bow_wi2dvf_add_di_text_fp (&(barrel->wi2dvf), di, fp, filename); word_count += num_words; text_file_count++; } else { bow_verbosify (bow_progress, "\nFile `%s' skipped because not text\n", filename); binary_file_count++; } fclose (fp); bow_verbosify (bow_progress, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" "%6d : %8d", text_file_count, bow_num_words ()); return 1; }#endif int barrel_index_file (const char *filename, void *context) { FILE *fp; bow_cdoc cdoc; bow_cdoc *cdocp; int di; /* a document index */ int num_words; /* If the filename matches the exception name, return immediately. */ if (except_name && !strcmp (filename, except_name)) return 0; if (!(fp = fopen (filename, "r"))) { bow_verbosify (bow_progress, "Couldn't open file `%s' for reading.", filename); return 0; } if (bow_fp_is_text (fp)) { /* The file contains text; snarf the words and put them in the WI2DVF map. */ cdoc.type = bow_doc_train; cdoc.class = class; /* Set to one so bow_infogain_per_wi_new() works correctly by default. */ cdoc.prior = 1.0f; assert (cdoc.class >= 0); cdoc.filename = strdup (filename); assert (cdoc.filename); cdoc.class_probs = NULL; /* Add the CDOC to CDOCS, and determine the "index" of this document. */ di = bow_array_append (barrel->cdocs, &cdoc); /* Add all the words in this document. */ num_words = bow_wi2dvf_add_di_text_fp (&(barrel->wi2dvf), di, fp, filename); /* Fill in the new CDOC's idea of WORD_COUNT */ cdocp = bow_array_entry_at_index (barrel->cdocs, di); cdocp->word_count = num_words; text_file_count++; } else { bow_verbosify (bow_progress, "\nFile `%s' skipped because not text\n", filename); binary_file_count++; } fclose (fp); bow_verbosify (bow_progress, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" "%6d : %8d", text_file_count, bow_num_words ()); return 1; } if (!(barrel->classnames)) barrel->classnames = bow_int4str_new (0); class = bow_str2int (barrel->classnames, classname);#ifdef VPC_ONLY /* If we are building a class barrel, make one cdoc per class */ if (barrel->is_vpc) { cdoc.type = bow_doc_train; cdoc.class = class; cdoc.filename = strdup (classname); cdoc.word_count = 0; /* Number of documents in this class */ cdoc.normalizer = -1.0f; cdoc.prior = 1.0f; /* Need to set this later... */ cdoc.class_probs = NULL; /* Add the CDOC to CDOCS, and determine the "index" of this "document." */ di = bow_array_append (barrel->cdocs, &cdoc); }#endif bow_verbosify (bow_progress, "Gathering stats... files : unique-words :: " " "); text_file_count = binary_file_count = 0;#ifdef VPC_ONLY /* Call our special function for building a class barrel rather than * a document barrel. When finished, set the priors and word counts */ if (barrel->is_vpc) { bow_map_filenames_from_dir (class_barrel_index_file, 0, dirname, ""); cdocp = bow_array_entry_at_index (barrel->cdocs, di); cdocp->prior = (float) text_file_count; cdocp->word_count = word_count; } else #endif bow_map_filenames_from_dir (barrel_index_file, 0, dirname, ""); bow_verbosify (bow_progress, "\n"); if (binary_file_count > text_file_count) bow_verbosify (bow_quiet, "Found mostly binary files, which were ignored.\n"); return text_file_count;}/* Call this on a vector-per-document barrel to set the CDOC->PRIOR's so that the CDOC->PRIOR's for all documents of the same class sum to 1. */voidbow_barrel_set_cdoc_priors_to_class_uniform (bow_barrel *barrel){ int *ci2dc; /* class index 2 document count */ int ci2dc_size = 100; int ci; int di; bow_cdoc *cdoc; int total_model_docs = 0; int num_non_zero_ci2dc_entries = 0; ci2dc = bow_malloc (sizeof (int) * ci2dc_size); for (ci = 0; ci < ci2dc_size; ci++) ci2dc[ci] = 0; for (di = 0; di < barrel->cdocs->length; di++) { cdoc = bow_array_entry_at_index (barrel->cdocs, di); if (cdoc->class >= ci2dc_size) { /* CI2DC must grow to accommodate larger "class index" */ int old_size = ci2dc_size; ci2dc_size *= 2; ci2dc = bow_realloc (ci2dc, sizeof (int) * ci2dc_size); for ( ; old_size < ci2dc_size; old_size++) ci2dc[old_size] = 0; } if (cdoc->type == bow_doc_train) { if (ci2dc[cdoc->class] == 0) num_non_zero_ci2dc_entries++; ci2dc[cdoc->class]++; total_model_docs++; } } for (di = 0; di < barrel->cdocs->length; di++) { cdoc = bow_array_entry_at_index (barrel->cdocs, di); if (cdoc->type == bow_doc_train) { cdoc->prior = (1.0 / (num_non_zero_ci2dc_entries * ci2dc[cdoc->class])); assert (cdoc->prior >= 0); } }#if 0 fprintf (stderr, "Infogain post-prior-setting\n"); bow_infogain_per_wi_print (stderr, barrel, num_non_zero_ci2dc_entries, 5);#endif /* Do some sanity checks. */ { float prior_total = 0; for (di = 0; di < barrel->cdocs->length; di++) { cdoc = bow_array_entry_at_index (barrel->cdocs, di); if (cdoc->type == bow_doc_train) prior_total += cdoc->prior; } assert (prior_total < 1.1 && prior_total > 0.9); } free (ci2dc);}/* Modify the BARREL by removing those entries for words that are not in the int/str mapping MAP. */voidbow_barrel_prune_words_not_in_map (bow_barrel *barrel, bow_int4str *map){ int wi; int max_wi = MIN (barrel->wi2dvf->size, bow_num_words()); assert (max_wi); /* For each word in MAP. */ for (wi = 0; wi < max_wi; wi++) { if (bow_str2int_no_add (map, bow_int2word (wi)) == -1) { /* Word WI is not in MAP. Remove it from the BARREL. */ bow_wi2dvf_hide_wi (barrel->wi2dvf, wi); } }}/* Modify the BARREL by removing those entries for words that are in the int/str mapping MAP. */voidbow_barrel_prune_words_in_map (bow_barrel *barrel, bow_int4str *map){ int i; int wi; /* For each word in MAP. */ for (i = 0; i < map->str_array_length; i++) { if ((wi = bow_word2int_no_add (bow_int2str (map, i))) != -1) { /* Word WI is in MAP. Remove it from the BARREL. */ bow_wi2dvf_hide_wi (barrel->wi2dvf, wi); } }}/* Modify the BARREL by removing those entries for words that are not among the NUM_WORDS_TO_KEEP top words, by information gain. This function is similar to BOW_WORDS_KEEP_TOP_BY_INFOGAIN(), but this one doesn't change the word-int mapping. */voidbow_barrel_keep_top_words_by_infogain (int num_words_to_keep, bow_barrel *barrel, int num_classes){ float *wi2ig; int wi2ig_size; int wi, i; struct wiig_list_entry { float ig; int wi; } *wiig_list; /* For sorting the above entries. */ int compare_wiig_list_entry (const void *e1, const void *e2) { if (((struct wiig_list_entry*)e1)->ig > ((struct wiig_list_entry*)e2)->ig) return -1; else if (((struct wiig_list_entry*)e1)->ig == ((struct wiig_list_entry*)e2)->ig) return 0; else return 1; } if (num_words_to_keep == 0) return; /* Unhide "document vectors" for all WI's */ bow_wi2dvf_unhide_all_wi (barrel->wi2dvf); /* Get the information gain of all the words. */ wi2ig = bow_infogain_per_wi_new (barrel, num_classes, &wi2ig_size); /* Make a list of the info gain numbers paired with their WI's, in prepartion for sorting. */ wiig_list = alloca (sizeof (struct wiig_list_entry) * wi2ig_size); for (wi = 0; wi < wi2ig_size; wi++) { wiig_list[wi].wi = wi; wiig_list[wi].ig = wi2ig[wi]; } /* Sort the list */ qsort (wiig_list, wi2ig_size, sizeof (struct wiig_list_entry), compare_wiig_list_entry); num_words_to_keep = MIN (num_words_to_keep, wi2ig_size);#if 1 bow_verbosify (bow_progress, "Showing here top %d words by information gain; " "%d put in model\n", MIN(5,num_words_to_keep), num_words_to_keep); for (i = 0; i < MIN(5,num_words_to_keep); i++) bow_verbosify (bow_progress, "%20.10f %s\n", wiig_list[i].ig, bow_int2word (wiig_list[i].wi));#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -