@@ -53,13 +53,16 @@ class LogisticRegression # rubocop:disable Metrics/ClassLength
5353 # - regularization: L2 regularization strength (default: 0.01)
5454 # - max_iterations: Maximum training iterations (default: 100)
5555 # - tolerance: Convergence threshold (default: 1e-4)
56+ # - min_word_length: Minimum word length filter in tokenization
5657 #
5758 # @rbs (*String | Symbol | Array[String | Symbol], ?learning_rate: Float, ?regularization: Float,
58- # ?max_iterations: Integer, ?tolerance: Float) -> void
59+ # ?max_iterations: Integer, ?tolerance: Float, ?min_word_length: Integer) -> void
60+ # rubocop:disable Metrics/ParameterLists
5961 def initialize ( *categories , learning_rate : DEFAULT_LEARNING_RATE ,
6062 regularization : DEFAULT_REGULARIZATION ,
6163 max_iterations : DEFAULT_MAX_ITERATIONS ,
62- tolerance : DEFAULT_TOLERANCE )
64+ tolerance : DEFAULT_TOLERANCE ,
65+ min_word_length : Classifier . config . min_word_length )
6366 super ( )
6467 categories = categories . flatten
6568 @categories = categories . map { |c | c . to_s . prepare_category_name }
@@ -74,7 +77,9 @@ def initialize(*categories, learning_rate: DEFAULT_LEARNING_RATE,
7477 @fitted = false
7578 @dirty = false
7679 @storage = nil
80+ @min_word_length = min_word_length
7781 end
82+ # rubocop:enable Metrics/ParameterLists
7883
7984 # Trains the classifier with text for a category.
8085 #
@@ -130,7 +135,7 @@ def classify(text)
130135 def probabilities ( text )
131136 raise NotFittedError , 'Model not fitted. Call fit() after training.' unless @fitted
132137
133- features = text . word_hash
138+ features = text . word_hash ( @min_word_length )
134139 synchronize do
135140 softmax ( compute_scores ( features ) )
136141 end
@@ -143,7 +148,7 @@ def probabilities(text)
143148 def classifications ( text )
144149 raise NotFittedError , 'Model not fitted. Call fit() after training.' unless @fitted
145150
146- features = text . word_hash
151+ features = text . word_hash ( @min_word_length )
147152 synchronize do
148153 compute_scores ( features ) . transform_keys ( &:to_s )
149154 end
@@ -239,7 +244,8 @@ def as_json(_options = nil)
239244 regularization : @regularization ,
240245 max_iterations : @max_iterations ,
241246 tolerance : @tolerance ,
242- fitted : @fitted
247+ fitted : @fitted ,
248+ min_word_length : @min_word_length
243249 }
244250 end
245251
@@ -336,7 +342,7 @@ def reload!
336342 def marshal_dump
337343 fit unless @fitted
338344 [ @categories , @weights , @bias , @vocabulary , @learning_rate , @regularization ,
339- @max_iterations , @tolerance , @fitted ]
345+ @max_iterations , @tolerance , @fitted , @min_word_length ]
340346 end
341347
342348 # Custom marshal deserialization to recreate mutex.
@@ -345,7 +351,7 @@ def marshal_dump
345351 def marshal_load ( data )
346352 mu_initialize
347353 @categories , @weights , @bias , @vocabulary , @learning_rate , @regularization ,
348- @max_iterations , @tolerance , @fitted = data
354+ @max_iterations , @tolerance , @fitted , @min_word_length = data
349355 @training_data = [ ]
350356 @dirty = false
351357 @storage = nil
@@ -395,7 +401,7 @@ def train_from_stream(category, io, batch_size: Streaming::DEFAULT_BATCH_SIZE)
395401 reader . each_batch do |batch |
396402 synchronize do
397403 batch . each do |text |
398- features = text . word_hash
404+ features = text . word_hash ( @min_word_length )
399405 features . each_key { |word | @vocabulary [ word ] = true }
400406 @training_data << { category : category , features : features }
401407 end
@@ -444,7 +450,7 @@ def train_batch_for_category(category, documents, batch_size: Streaming::DEFAULT
444450 documents . each_slice ( batch_size ) do |batch |
445451 synchronize do
446452 batch . each do |text |
447- features = text . word_hash
453+ features = text . word_hash ( @min_word_length )
448454 features . each_key { |word | @vocabulary [ word ] = true }
449455 @training_data << { category : category , features : features }
450456 end
@@ -463,7 +469,7 @@ def train_single(category, text)
463469 category = category . to_s . prepare_category_name
464470 raise StandardError , "No such category: #{ category } " unless @categories . include? ( category )
465471
466- features = text . word_hash
472+ features = text . word_hash ( @min_word_length )
467473 synchronize do
468474 features . each_key { |word | @vocabulary [ word ] = true }
469475 @training_data << { category : category , features : features }
@@ -570,6 +576,7 @@ def restore_state(data, categories)
570576 @fitted = data . fetch ( 'fitted' , true )
571577 @dirty = false
572578 @storage = nil
579+ @min_word_length = data [ 'min_word_length' ] || Classifier . config . min_word_length
573580 end
574581
575582 def restore_weights_and_bias ( data )
0 commit comments