module Opener class OpinionDetectorBasic class Opinion attr_reader :term attr_accessor :left_candidates, :right_candidates, :target_ids, :holders def initialize(term) @term = term @left_candidates = [] @right_candidates = [] @holders = [] @target_ids = [] end ## # Returns the term ids of the opinion expression. # # @return [Array] # def ids @ids ||= term.list_ids.sort end ## # Returns the sentence id of the opinion. # # @return [String] # def sentence @sentence ||= term.sentence end ## # Returns the strength of the opinion. # # @return [Integer] # def strength @strength ||= term.accumulated_strength end ## # Returns the polarity of the opinion. # # @return [String] # def polarity @polarity ||= if strength > 0 "positive" elsif strength < 0 "negative" else "neutral" end end ## # Obtain the opinion holders from the terms that belong to the same # sentence. # def obtain_holders(sentences, language) sentence_terms = sentences[sentence] sentence_terms.each do |term| if opinion_holders[language].include?(term.lemma) @holders << term.id break end end end ## # Get the potential right and left candidates of the sentence and # decide which ones are the actual targets of the opinion # def obtain_targets(sentences) sentence_terms = sentences[sentence] max_distance = 3 terms_count = sentence_terms.count index = -1 sentence_terms.each_with_index do |term, i| if ids.include?(term.id) index = i end end unless index+1 >= terms_count min = index+1 max = [index+1+max_distance,terms_count].min @right_candidates = filter_candidates(sentence_terms[min..max]) end index = 0 sentence_terms.each_with_index do |term, i| if ids.include?(term.id) index = i break # needed for left_candidates end end unless index == 0 min = [0, index-1-max_distance].max max = index @left_candidates = filter_candidates(sentence_terms[min..max]) end unless right_candidates.empty? candidate = right_candidates.first @target_ids << candidate.id end if target_ids.empty? list = mix_lists(right_candidates, left_candidates) list.each do |l| @target_ids << l.id break end end end protected ## # If there are no opinion targets, right and left candidates # are mixed into one list and the first one is picked as the target. # # @return [Array] # def mix_lists(lista, listb) list = [] min = [lista.count, listb.count].min (0..min).each do |i| list << lista[i] list << listb[i] if lista.count > listb.count list << lista[min] elsif listb.count > lista.count list << listb[min] end end return list.compact end ## # Filters candidate terms depending on their part of speech and if # they are already part of the expression. # # @return [Hash] # def filter_candidates(sentence_terms) sentence_terms.select{|t| (t.pos == "N" || t.pos == "R") && !ids.include?(t.id)} end ## # Opinion holders for each language code. # # @return [Hash] # def opinion_holders { 'nl' => ['ik','we','wij','ze','zij','jullie','u','hij','het','jij','je','mij','me','hem','haar','ons','hen','hun'], 'en' => ['i','we','he','she','they','it','you'], 'es' => ['yo','tu','nosotros','vosotros','ellos','ellas','nosotras','vosotras'], 'it' => ['io','tu','noi','voi','loro','lei','lui'], 'de' => ['ich','du','wir','ihr','sie','er'], 'fr' => ['je','tu','lui','elle','nous','vous','ils','elles'] } end end # Opinion end # OpinionDetectorBasic end # Opener