tsentiment 2.0.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: {}
|