From 8deba3cb36f32b4890d79db637eefff5d42df364 Mon Sep 17 00:00:00 2001 From: dinopuguh Date: Mon, 12 Oct 2020 08:01:34 +0700 Subject: [PATCH 1/5] Implement unit test --- .gitignore | 2 ++ go.mod | 5 +++++ go.sum | 10 ++++++++++ gosentiwordnet.go | 17 ++++++++++------- gosentiwordnet_test.go | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 .gitignore create mode 100644 go.mod create mode 100644 go.sum create mode 100644 gosentiwordnet_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce4af3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +coverage.out +coverage.html \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4c36029 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/dinopuguh/gosentiwordnet + +go 1.14 + +require github.com/stretchr/testify v1.6.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..56d62e7 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gosentiwordnet.go b/gosentiwordnet.go index bbe062a..8d691cd 100644 --- a/gosentiwordnet.go +++ b/gosentiwordnet.go @@ -13,10 +13,13 @@ import ( const sentiWordnetAssetName = "rawdata/SentiWordNet_3.0.0.txt" +// SentimentAnalyzer represent the sentiment analyzer with sentiwordnet lexicon type SentimentAnalyzer struct { Lexicon map[string]Sentiment } +// Sentiment reprensent sentiment score for each word +// containing positive, negative and objective type Sentiment struct { Positive float64 Negative float64 @@ -56,13 +59,12 @@ func (sa *SentimentAnalyzer) generateLexicon() { line++ } - - if err := scanner.Err(); err != nil { - log.Fatal(err.Error()) - } } -func (sa *SentimentAnalyzer) GetSentimentScore(word string, posTag string, usage string) (bool, Sentiment) { +// GetSentimentScore count the sentiment score of word based on POS tag and the word usage. +// POS tag: part-of-speech tag of word +// Word usage: 1 for most common usage and a higher number would indicate lesser common usages +func (sa *SentimentAnalyzer) GetSentimentScore(word string, posTag string, usage string) (Sentiment, bool) { var result Sentiment posTag = "(" + posTag + ")" @@ -78,10 +80,11 @@ func (sa *SentimentAnalyzer) GetSentimentScore(word string, posTag string, usage } } - return match, result + return result, match } -func NewGoSentiwordnet() *SentimentAnalyzer { +// New generate the sentiment analyzer with sentiwordnet lexicon +func New() *SentimentAnalyzer { var sa SentimentAnalyzer sa.generateLexicon() diff --git a/gosentiwordnet_test.go b/gosentiwordnet_test.go new file mode 100644 index 0000000..a6a7288 --- /dev/null +++ b/gosentiwordnet_test.go @@ -0,0 +1,34 @@ +package gosentiwordnet_test + +import ( + "testing" + + "github.com/dinopuguh/gosentiwordnet" + "github.com/stretchr/testify/assert" +) + +type SentimentTestCase struct { + Word string + PosTag string + Usage string + Scores gosentiwordnet.Sentiment +} + +func generateTestCases() []SentimentTestCase { + return []SentimentTestCase{ + {Word: "love", PosTag: "v", Usage: "2", Scores: gosentiwordnet.Sentiment{Positive: 1, Negative: 0, Objective: 0}}, + {Word: "neat", PosTag: "a", Usage: "4", Scores: gosentiwordnet.Sentiment{Positive: 0.625, Negative: 0, Objective: 0.375}}, + {Word: "overacting", PosTag: "n", Usage: "1", Scores: gosentiwordnet.Sentiment{Positive: 0, Negative: 0.875, Objective: 0.125}}, + {Word: "finely", PosTag: "r", Usage: "2", Scores: gosentiwordnet.Sentiment{Positive: 0.625, Negative: 0, Objective: 0.375}}, + } +} + +func TestSentimentAnalysis(t *testing.T) { + sa := gosentiwordnet.New() + for _, testCase := range generateTestCases() { + scores, match := sa.GetSentimentScore(testCase.Word, testCase.PosTag, testCase.Usage) + if match { + assert.Equalf(t, testCase.Scores, scores, testCase.Word) + } + } +} From bfaa18104e1158245e6f7cd2075a00cc302e6477 Mon Sep 17 00:00:00 2001 From: dinopuguh Date: Mon, 12 Oct 2020 09:16:23 +0700 Subject: [PATCH 2/5] Add travis CI build --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..07098fe --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: go +go: + - 1.14.x + +script: + - go test -v -coverprofile=coverage.txt -covermode=count + +after_success: + - bash <(curl -s https://codecov.io/bash) + - rm -rf coverage.txt From 591f2486d70f814b681d32ca403e2043a17321fe Mon Sep 17 00:00:00 2001 From: dinopuguh Date: Mon, 12 Oct 2020 09:16:57 +0700 Subject: [PATCH 3/5] Update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ce4af3f..632f4d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +coverage.txt coverage.out coverage.html \ No newline at end of file From eb545ac1315d5b73158395bc268f6fee7f16dcbd Mon Sep 17 00:00:00 2001 From: dinopuguh Date: Mon, 12 Oct 2020 09:17:08 +0700 Subject: [PATCH 4/5] Update unit testing --- example/main.go | 32 ++++++++++++++++++++++++++++++++ gosentiwordnet_test.go | 8 ++++---- 2 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 example/main.go diff --git a/example/main.go b/example/main.go new file mode 100644 index 0000000..794f9cf --- /dev/null +++ b/example/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + + goswn "github.com/dinopuguh/gosentiwordnet" +) + +// Token represent the required parameter for using gosentiwordnet +type Token struct { + Word string // the word want to process + PosTag string // part-of-speech tag of word + Usage string // word usage (1 for most common usage and a higher number would indicate lesser common usages) +} + +func main() { + sa := goswn.New() + + tokens := []Token{ + Token{Word: "love", PosTag: "v", Usage: "2"}, + Token{Word: "neat", PosTag: "a", Usage: "4"}, + Token{Word: "overacting", PosTag: "n", Usage: "1"}, + } + + for _, token := range tokens { + scores, exist := sa.GetSentimentScore(token.Word, token.PosTag, token.Usage) + if exist { + fmt.Printf("💬 Sentiment score of %s: %v\n", token.Word, scores) + // 💬 Sentiment score: {positive_score negative_score objective_score} + } + } +} diff --git a/gosentiwordnet_test.go b/gosentiwordnet_test.go index a6a7288..c179144 100644 --- a/gosentiwordnet_test.go +++ b/gosentiwordnet_test.go @@ -16,10 +16,10 @@ type SentimentTestCase struct { func generateTestCases() []SentimentTestCase { return []SentimentTestCase{ - {Word: "love", PosTag: "v", Usage: "2", Scores: gosentiwordnet.Sentiment{Positive: 1, Negative: 0, Objective: 0}}, - {Word: "neat", PosTag: "a", Usage: "4", Scores: gosentiwordnet.Sentiment{Positive: 0.625, Negative: 0, Objective: 0.375}}, - {Word: "overacting", PosTag: "n", Usage: "1", Scores: gosentiwordnet.Sentiment{Positive: 0, Negative: 0.875, Objective: 0.125}}, - {Word: "finely", PosTag: "r", Usage: "2", Scores: gosentiwordnet.Sentiment{Positive: 0.625, Negative: 0, Objective: 0.375}}, + SentimentTestCase{Word: "love", PosTag: "v", Usage: "2", Scores: gosentiwordnet.Sentiment{Positive: 1, Negative: 0, Objective: 0}}, + SentimentTestCase{Word: "neat", PosTag: "a", Usage: "4", Scores: gosentiwordnet.Sentiment{Positive: 0.625, Negative: 0, Objective: 0.375}}, + SentimentTestCase{Word: "overacting", PosTag: "n", Usage: "1", Scores: gosentiwordnet.Sentiment{Positive: 0, Negative: 0.875, Objective: 0.125}}, + SentimentTestCase{Word: "finely", PosTag: "r", Usage: "2", Scores: gosentiwordnet.Sentiment{Positive: 0.625, Negative: 0, Objective: 0.375}}, } } From a7154f95e0490b7f264057fd0fb80e92c65e4733 Mon Sep 17 00:00:00 2001 From: dinopuguh Date: Mon, 12 Oct 2020 09:17:18 +0700 Subject: [PATCH 5/5] Create readme file and funding --- FUNDING.yml | 7 ++++++ README.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 FUNDING.yml diff --git a/FUNDING.yml b/FUNDING.yml new file mode 100644 index 0000000..52e0a34 --- /dev/null +++ b/FUNDING.yml @@ -0,0 +1,7 @@ +# These are supported funding model platforms + +github: [dinopuguh] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel diff --git a/README.md b/README.md index dcd325d..6544a04 100644 --- a/README.md +++ b/README.md @@ -1 +1,60 @@ -go-sentiwordnet +# 💬 GoSentiwordnet + +Sentiment analyzer using [sentiwordnet](https://github.com/aesuli/SentiWordNet) lexicon in Go. This library produce sentiment score for each word, including positive, negative, and objective score. + +## ⚙ Installation + +First of all, [download](https://golang.org/dl/) and install Go `1.14` or higher is required. + +Install this library using the [`go get`](https://golang.org/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them) command: + +```bash +$ go get github.com/dinopuguh/gosentiwordnet +``` + + + +## ⚡ Quickstart + +```go +package main + +import ( + "fmt" + + goswn "github.com/dinopuguh/gosentiwordnet" +) + +func main() { + sa := goswn.New() + + scores, exist := sa.GetSentimentScore("love", "v", "2") + if exist { + fmt.Println("💬 Sentiment score:", scores) // => 💬 Sentiment score: {1 0 0} + } +} +``` + +The `GetSentimentScore` required 3 parameters(word, pos-tag, and word usage): + +1. **Word**: the word want to process +2. **POS tag**: part-of-speech tag of the word +3. **Word usage**: 1 for most common usage and a higher number would indicate lesser common usages + + + +## 👍 Contributing + +If you want to say **thank you** and/or support the active development of `Gosentiwordnet`: + +1. Add a [GitHub Star](https://github.com/dinopuguh/gosentiwordnet/stargazers) to the project. +2. Write a review or tutorial on [Medium](https://medium.com/), [Dev.to](https://dev.to/) or personal blog. +3. Be a part of our [sponsors](https://github.com/sponsors/dinopuguh) to support this project. + + + +## 💻 Contributors + +- Dino Puguh (initial works) + +Open for any pull requests to develop this project. \ No newline at end of file