tsentiment 2.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/composite_pattern.rb +35 -0
- data/lib/findSentiment.rb +110 -0
- data/lib/median.rb +19 -0
- data/lib/negated.rb +137 -0
- data/lib/negativity.rb +59 -0
- data/lib/positivity.rb +58 -0
- data/lib/task.rb +11 -0
- data/lib/total_sentiment.rb +24 -0
- data/source/adjectives.json +36 -0
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 166e9071ff25501edcd39c37c497a9c57c3de187c7f6db99f2365214793c0a90
|
4
|
+
data.tar.gz: 6c73f3d2508da10f31ef64401a126c9582536114cf90c8c92abca53111733dd1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e71042c1e22d9fcc53b0890cd0f70b91c71f3fd285747b8dc494cddfd8c3a3a167e1d8561fe8212e1d3cac8ebbccdf67b1cabc0f87cb6f3fe21d64768ecc23cb
|
7
|
+
data.tar.gz: dd8d13dcd701ca9b5e353389ebad541eb4acb154b08239bed6d253ea4bc7dfaf3ab378d94df6f01f38a39f1a6747e00605ba2641de9460f7a16fc12a77a53fa1
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'task'
|
2
|
+
|
3
|
+
class CompositeTask < Task
|
4
|
+
|
5
|
+
def initialize(name)
|
6
|
+
super(name)
|
7
|
+
@sub_tasks = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def <<(task)
|
11
|
+
@sub_tasks << task
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](index)
|
15
|
+
@sub_tasks[index]
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(index, new_value)
|
19
|
+
@sub_tasks[index] = new_value
|
20
|
+
end
|
21
|
+
|
22
|
+
def size
|
23
|
+
@sub_tasks.size
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove_sub_task(task)
|
27
|
+
@sub_tasks.delete(task)
|
28
|
+
end
|
29
|
+
|
30
|
+
def sentiment_value
|
31
|
+
time=0.0
|
32
|
+
@sub_tasks.each { |task| time += task.sentiment_value}
|
33
|
+
time
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
#Version with median library, negated sentiment calculation and overall sentiment calculation with composite
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require_relative 'median'
|
6
|
+
require_relative 'negativity'
|
7
|
+
require_relative 'positivity'
|
8
|
+
require_relative 'negated'
|
9
|
+
require_relative 'composite_pattern'
|
10
|
+
require_relative 'total_sentiment'
|
11
|
+
|
12
|
+
|
13
|
+
class FindSentiment
|
14
|
+
|
15
|
+
def self.value(reviews, rating)
|
16
|
+
|
17
|
+
sentiment = Array.new
|
18
|
+
lexicon_sentiment = Array.new
|
19
|
+
review_sentiment = Array.new
|
20
|
+
overall_sentiment = Array.new
|
21
|
+
composite = CompositeTask.new('Sentiment')
|
22
|
+
negated = FindNegation.instance
|
23
|
+
|
24
|
+
i = 0
|
25
|
+
|
26
|
+
reviews.each do
|
27
|
+
string = reviews[i]
|
28
|
+
|
29
|
+
phrase_sentiment = Array.new
|
30
|
+
|
31
|
+
j = 0
|
32
|
+
|
33
|
+
sentence = string.split(".")
|
34
|
+
|
35
|
+
sentence.each do
|
36
|
+
|
37
|
+
phrase = sentence[j]
|
38
|
+
|
39
|
+
length = phrase.gsub(/\s+/, "").size
|
40
|
+
|
41
|
+
# Do not analyse the sentence if it's just an empty or just has one character
|
42
|
+
|
43
|
+
if length <= 1
|
44
|
+
j+=1
|
45
|
+
else
|
46
|
+
|
47
|
+
#Split the phrase into lexicons based on no. of negators and see if there are any
|
48
|
+
|
49
|
+
lexicon = phrase.split(/not|no|never/)
|
50
|
+
k = 0
|
51
|
+
|
52
|
+
if lexicon.count > 1 # If block handles the sentiment calculation of a phrase if the it has any negator
|
53
|
+
lexicon.each do
|
54
|
+
#lexicon_value = FindNegation.value(lexicon[k])
|
55
|
+
negated.sentiment(lexicon[k])
|
56
|
+
lexicon_value = negated.sentiment_value
|
57
|
+
lexicon_sentiment.push(lexicon_value)
|
58
|
+
k+=1
|
59
|
+
end
|
60
|
+
|
61
|
+
#sentiment value of each phrase separated by a full stop with negated sentiment calculation
|
62
|
+
sentiment_value = lexicon_sentiment.sum
|
63
|
+
|
64
|
+
else
|
65
|
+
|
66
|
+
# This block handles the sentiment calculation of a single phrase if it has no negator at all
|
67
|
+
|
68
|
+
#Finding total sentiment using composite design pattern
|
69
|
+
|
70
|
+
composite << TotalSentiment.new(phrase)
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
#sentiment value of each phrase separated by a full stop without negative words
|
75
|
+
sentiment_value = composite.sentiment_value
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
#stores sentiment value of each phrase of a review into the array phrase_sentiment
|
80
|
+
phrase_sentiment.push(sentiment_value)
|
81
|
+
|
82
|
+
j += 1
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
#Store sentiment of a single review - median of all phrases in a review
|
88
|
+
|
89
|
+
review_sentiment.push(FindMedian.value(phrase_sentiment))
|
90
|
+
|
91
|
+
i += 1
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
#Overall sentiment of all reviews - median of sentiment of all reviews
|
96
|
+
|
97
|
+
overall_sentiment = FindMedian.value(review_sentiment)
|
98
|
+
|
99
|
+
#Total sentiment of average of overall sentiment value of all user reviews + overall user rating
|
100
|
+
|
101
|
+
total_sentiment = (rating.to_f + overall_sentiment.to_f) / 2
|
102
|
+
|
103
|
+
return total_sentiment.to_f.round(2)
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
string = Array.new
|
110
|
+
|
data/lib/median.rb
ADDED
data/lib/negated.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
require_relative 'task'
|
2
|
+
require_relative 'median'
|
3
|
+
require 'singleton'
|
4
|
+
require 'json'
|
5
|
+
require 'net/http'
|
6
|
+
require_relative 'negativity'
|
7
|
+
require_relative 'positivity'
|
8
|
+
|
9
|
+
class FindNegation < Task
|
10
|
+
|
11
|
+
include Singleton
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
end
|
15
|
+
|
16
|
+
def sentiment(comment)
|
17
|
+
|
18
|
+
@phrase = comment
|
19
|
+
@sentiment
|
20
|
+
|
21
|
+
positive = FindPositivity.instance
|
22
|
+
negative = FindNegativity.instance
|
23
|
+
|
24
|
+
uri = URI('http://18.221.169.60/results')
|
25
|
+
params = { :limit => 10, :page => 3 }
|
26
|
+
uri.query = URI.encode_www_form(params)
|
27
|
+
res = Net::HTTP.get_response(uri)
|
28
|
+
adjectives = JSON.parse(res.body)
|
29
|
+
|
30
|
+
positives = adjectives[0]['positives']
|
31
|
+
negatives = adjectives[0]['negatives']
|
32
|
+
|
33
|
+
words = @phrase.split(/\W+/)
|
34
|
+
|
35
|
+
array1 = Array.new
|
36
|
+
output1 = Hash.new
|
37
|
+
array2 = Array.new
|
38
|
+
output2 = Hash.new
|
39
|
+
|
40
|
+
words.each do
|
41
|
+
|ws| ws.scan(/[\w']+/) do
|
42
|
+
|w| if positives.key?(w)
|
43
|
+
output1[ws] = positives[w]
|
44
|
+
array1.push(output1)
|
45
|
+
end
|
46
|
+
|
47
|
+
if negatives.key?(w)
|
48
|
+
output2[ws] = negatives[w]
|
49
|
+
array2.push(output2)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if array1.count == 0 && array2.count == 0
|
55
|
+
#puts "In case 0"
|
56
|
+
@sentiment = 0
|
57
|
+
end
|
58
|
+
|
59
|
+
if array1.count == 0 && array2.count != 0
|
60
|
+
#puts "In case 1"
|
61
|
+
positivity_sentiment = 0
|
62
|
+
negative.sentiment(@phrase)
|
63
|
+
negativity_sentiment = negative.sentiment_value
|
64
|
+
@sentiment = positivity_sentiment - negativity_sentiment
|
65
|
+
end
|
66
|
+
|
67
|
+
if array1.count != 0 && array2.count == 0
|
68
|
+
#puts "In case 2"
|
69
|
+
negativity_sentiment = 0
|
70
|
+
positive.sentiment(@phrase)
|
71
|
+
positivity_sentiment = positive.sentiment_value
|
72
|
+
@sentiment = negativity_sentiment - positivity_sentiment
|
73
|
+
end
|
74
|
+
|
75
|
+
if array1.count != 0 && array2.count != 0
|
76
|
+
|
77
|
+
#puts "In case 3"
|
78
|
+
|
79
|
+
first_positive = output1
|
80
|
+
first_negative = output2
|
81
|
+
|
82
|
+
index1 = @phrase.index("#{first_positive.keys[0]}")
|
83
|
+
index2 = @phrase.index("#{first_negative.keys[0]}")
|
84
|
+
|
85
|
+
if index1 < index2
|
86
|
+
#puts "The word #{first_positive.keys[0]} appears first"
|
87
|
+
negated_adj = first_positive
|
88
|
+
negated_sentiment = (negated_adj.values[0] * -1) # Negation only changes positive sentiment to negative
|
89
|
+
else
|
90
|
+
# puts "The word #{first_negative.keys[0]} appears first"
|
91
|
+
negated_adj = first_negative
|
92
|
+
#puts negated_adj
|
93
|
+
negated_sentiment = (negated_adj.values[0]) # Double negativity already
|
94
|
+
end
|
95
|
+
|
96
|
+
#Fetch the words after the first adjective and store it in remainder[1]
|
97
|
+
|
98
|
+
remainder = @phrase.split(/#{negated_adj.keys[0]}/)
|
99
|
+
|
100
|
+
# Find the sentiment of remainder[1]
|
101
|
+
|
102
|
+
positive.sentiment(remainder[1])
|
103
|
+
positivity_sentiment = positive.sentiment_value
|
104
|
+
|
105
|
+
negative.sentiment(remainder[1])
|
106
|
+
negativity_sentiment = negative.sentiment_value
|
107
|
+
|
108
|
+
#Now total sentiment = negated sentiment of first adjective + sentiment of the remainder[1]
|
109
|
+
|
110
|
+
if index1 < index2
|
111
|
+
#puts "I am in first positive"
|
112
|
+
fraction = Array[negated_sentiment, negativity_sentiment]
|
113
|
+
values = FindMedian.value(fraction)
|
114
|
+
@sentiment = positivity_sentiment + values
|
115
|
+
else
|
116
|
+
#puts "I am in first negative"
|
117
|
+
fraction = Array[negated_sentiment, positivity_sentiment]
|
118
|
+
values = FindMedian.value(fraction)
|
119
|
+
@sentiment = values + negativity_sentiment
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
def sentiment_value
|
127
|
+
@sentiment
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
#string = "This product is bad"
|
133
|
+
|
134
|
+
#weight = FindNegation.instance
|
135
|
+
#weight.sentiment(string)
|
136
|
+
#puts weight.sentiment_value
|
137
|
+
|
data/lib/negativity.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative 'task'
|
2
|
+
require_relative 'median'
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require 'singleton'
|
6
|
+
|
7
|
+
class FindNegativity < Task
|
8
|
+
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
end
|
13
|
+
|
14
|
+
def sentiment(comment)
|
15
|
+
|
16
|
+
@phrase = comment
|
17
|
+
@sentiment
|
18
|
+
uri = URI('http://18.221.169.60/results')
|
19
|
+
params = { :limit => 10, :page => 3 }
|
20
|
+
uri.query = URI.encode_www_form(params)
|
21
|
+
res = Net::HTTP.get_response(uri)
|
22
|
+
adjectives = JSON.parse(res.body)
|
23
|
+
|
24
|
+
negatives = adjectives[0]['negatives']
|
25
|
+
|
26
|
+
words = @phrase.split(/\W+/)
|
27
|
+
|
28
|
+
array = Array.new
|
29
|
+
output = Hash.new
|
30
|
+
|
31
|
+
words.each do
|
32
|
+
|ws| ws.scan(/[\w']+/) do
|
33
|
+
|w| if negatives.key?(w)
|
34
|
+
output[ws] = negatives[w]
|
35
|
+
array.push(output)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
@sentiment = FindMedian.value(output.values)
|
41
|
+
#puts negativity_sentiment
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def sentiment_value
|
46
|
+
(@sentiment * -1)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
#string = "This product is bad"
|
55
|
+
|
56
|
+
#weight = FindNegativity.instance
|
57
|
+
#weight.sentiment(string)
|
58
|
+
#puts weight.sentiment_value
|
59
|
+
|
data/lib/positivity.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative 'task'
|
2
|
+
require_relative 'median'
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require 'singleton'
|
6
|
+
|
7
|
+
class FindPositivity < Task
|
8
|
+
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
end
|
13
|
+
|
14
|
+
def sentiment(comment)
|
15
|
+
|
16
|
+
@phrase = comment
|
17
|
+
@sentiment
|
18
|
+
uri = URI('http://18.221.169.60/results')
|
19
|
+
params = { :limit => 10, :page => 3 }
|
20
|
+
uri.query = URI.encode_www_form(params)
|
21
|
+
res = Net::HTTP.get_response(uri)
|
22
|
+
adjectives = JSON.parse(res.body)
|
23
|
+
|
24
|
+
positives = adjectives[0]['positives']
|
25
|
+
|
26
|
+
words = @phrase.split(/\W+/)
|
27
|
+
|
28
|
+
array = Array.new
|
29
|
+
output = Hash.new
|
30
|
+
|
31
|
+
words.each do
|
32
|
+
|ws| ws.scan(/[\w']+/) do
|
33
|
+
|w| if positives.key?(w)
|
34
|
+
output[ws] = positives[w]
|
35
|
+
array.push(output)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
@sentiment = FindMedian.value(output.values)
|
41
|
+
#puts positivity_sentiment
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def sentiment_value
|
46
|
+
@sentiment
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
#string = "This product is good"
|
54
|
+
|
55
|
+
#weight = FindPositivity.instance
|
56
|
+
#weight.sentiment(string)
|
57
|
+
#puts weight.sentiment_value
|
58
|
+
|
data/lib/task.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'composite_pattern'
|
2
|
+
require_relative 'positivity'
|
3
|
+
require_relative 'negativity'
|
4
|
+
require_relative 'negated'
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
class TotalSentiment < CompositeTask
|
9
|
+
|
10
|
+
def initialize(phrase)
|
11
|
+
super ('Find total sentiment')
|
12
|
+
|
13
|
+
positive = FindPositivity.instance
|
14
|
+
negative = FindNegativity.instance
|
15
|
+
negated = FindNegation.instance
|
16
|
+
positive.sentiment(phrase)
|
17
|
+
negative.sentiment(phrase)
|
18
|
+
#negated.sentiment(phrase)
|
19
|
+
|
20
|
+
self << positive
|
21
|
+
self << negative
|
22
|
+
#self << negated
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
{
|
2
|
+
"results": [{
|
3
|
+
"positives": {
|
4
|
+
"good": 3,
|
5
|
+
"terrific": 4,
|
6
|
+
"brilliant": 4,
|
7
|
+
"awesome": 4,
|
8
|
+
"perfect": 4,
|
9
|
+
"amazing": 4,
|
10
|
+
"tasty": 3,
|
11
|
+
"yummy": 3,
|
12
|
+
"great": 4,
|
13
|
+
"best": 5,
|
14
|
+
"marvellous": 5,
|
15
|
+
"crazy": 5,
|
16
|
+
"wonderful": 4,
|
17
|
+
"commendable": 5
|
18
|
+
},
|
19
|
+
"negatives": {
|
20
|
+
"bad": 3,
|
21
|
+
"worst": 4,
|
22
|
+
"ridiculous": 4,
|
23
|
+
"pathetic": 5,
|
24
|
+
"poor": 4,
|
25
|
+
"hopeless": 4,
|
26
|
+
"useless": 4,
|
27
|
+
"late": 4,
|
28
|
+
"rotten": 5,
|
29
|
+
"spoilt": 5,
|
30
|
+
"tasteless": 4,
|
31
|
+
"flavorless": 4
|
32
|
+
|
33
|
+
}
|
34
|
+
}]
|
35
|
+
|
36
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tsentiment
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Surya Kumar Govindan
|
@@ -16,7 +16,16 @@ email: suryajapan@gmail.com
|
|
16
16
|
executables: []
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
|
-
files:
|
19
|
+
files:
|
20
|
+
- lib/composite_pattern.rb
|
21
|
+
- lib/findSentiment.rb
|
22
|
+
- lib/median.rb
|
23
|
+
- lib/negated.rb
|
24
|
+
- lib/negativity.rb
|
25
|
+
- lib/positivity.rb
|
26
|
+
- lib/task.rb
|
27
|
+
- lib/total_sentiment.rb
|
28
|
+
- source/adjectives.json
|
20
29
|
homepage: http://rubygems.org/gems/tsentiment
|
21
30
|
licenses: []
|
22
31
|
metadata: {}
|