计分方式
-
组合观点
情 感 分 = 主 体 ∗ ∑ i = 1 n ( 观 点 i ∗ ∏ j = 1 n 程 度 j ∗ ( − 1 ) 否 定 数 ) 情感分 = 主体 * \sum_{i=1}^{n} {(观点_i * \prod_{j=1}^{n}程度_j * (-1)^{否定数})} 情感分=主体∗∑i=1n(观点i∗∏j=1n程度j∗(−1)否定数)
-
直接观点
情 感 分 = 观 点 i ∗ ∏ j = 1 n 程 度 j ∗ ( − 1 ) 否 定 数 情感分 = 观点_i * \prod_{j=1}^{n}程度_j * (-1)^{否定数} 情感分=观点i∗∏j=1n程度j∗(−1)否定数
句子 |
主体 |
观点 |
程度(含否定) |
得分 |
观点类型 |
价格真tm高 |
价格(-1) |
高(1) |
真tm(2) |
− 11 ∗ 2 = − 2 -1 1 * 2 = -2 −11∗2=−2 |
组合观点 |
价格没有不合理 |
价格 |
合理(1) |
没有(-1)不(-1) |
1 ∗ ( − 1 ) 2 = 1 1*(-1)^2=1 1∗(−1)2=1 |
直接观点 |
希望有美颜功能 |
美颜功能 |
希望有(-1) |
|
-1 |
直接观点 |
有美颜功能 |
美颜功能(1) |
有(1) |
|
1 ∗ 1 = 1 1*1=1 1∗1=1 |
组合观点 |
麻雀虽小五脏俱全 |
麻雀(1) |
小(-1)、五脏俱全(1) |
|
1 ∗ − 1 + 1 = 0 1 * -1 + 1=0 1∗−1+1=0 |
混合观点 |
正面观点 |
负面观点 |
声音足够小 |
声音过小 |
声音足够大 |
声音过大 |
材质够软 |
材质不够软 |
材料够硬 |
材质不够硬 |
观点 |
语境 |
好评 |
发动机力气大 |
差评 |
开盖要很大的力气 才行 |
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
train = [
'手机慢', '手机烂', '手机垃圾', '音箱差',
'手机快', '手机好看', '音箱好看', '音箱ok',
]
y = [0, 0, 0, 0, 1, 1, 1, 1]
entities = {'手机', '音箱', '拍照'}
vectorizer = TfidfVectorizer(tokenizer=jieba.cut)
X = vectorizer.fit_transform(train)
clf = MultinomialNB()
clf.fit(X, y)
text = '手机很慢,但拍照好看,无聊时听听FM,音箱ok'
for clause in text.split(','):
for word in jieba.cut(clause):
if word in entities:
vector = vectorizer.transform([clause])
pred = clf.predict(vector)[0]
print(word, pred)
手机 0
拍照 1
音箱 1
合并同flag词
from jieba.posseg import lcut
text = '拳王真的非常非常威猛高大'
ls = lcut(text)
words = [i.word for i in ls]
flags = [i.flag for i in ls]
print(words)
print(flags)
def combine(words, flags):
"""
合并相邻的同flag项
e.g.
[ 非常 非常 美丽 动人 ] → [ 非常非常 美丽动人 ]
"""
length = len(words)
for i in range(length - 1, 0, -1):
if flags[i-1] == flags[i]:
words[i-1] = words[i-1] + words[i]
del words[i]
del flags[i]
return words, flags
words, flags = combine(words, flags)
print(words)
print(flags)
-
print
-
[‘拳王’, ‘真的’, ‘非常’, ‘非常’, ‘威猛’, ‘高大’]
[‘n’, ‘d’, ‘d’, ‘d’, ‘a’, ‘a’]
[‘拳王’, ‘真的非常非常’, ‘威猛高大’]
[‘n’, ‘d’, ‘a’]
否定词模型
texts = [
'价格 高', '价格 不 高', '价格 不是 高', '价格 不是 不 高',
'价格 低', '价格 不 低', '价格 不是 低', '价格 不是 不 低',
'价值 高', '价值 不 高', '价值 不是 高', '价值 不是 不 高',
'价值 低', '价值 不 低', '价值 不是 低', '价值 不是 不 低',
]
y = [
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
]
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
for clf in [MultinomialNB, LogisticRegression, SVC]:
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(texts)
classifier = clf()
classifier.fit(X, y)
print(classifier.score(X, y), clf.__name__)
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Embedding, Dense,\
LSTM, Bidirectional,\
Conv1D, GlobalMaxPool1D
"""数据读取与处理"""
words = {word for text in texts for word in text.split()}
word2id = {w: i for i, w in enumerate(words, 1)}
x = [[word2id[word] for word in text.split()] for text in texts]
"""配置"""
input_dim = len(words) + 1
maxlen = 4
output_dim = 6
x = pad_sequences(x, maxlen)
def modeling(model_name='rnn'):
"""建模"""
model = Sequential()
model.add(Embedding(input_dim, output_dim, input_length=maxlen))
if model_name == 'cnn':
model.add(Conv1D(filters=6, kernel_size=3, padding='same', activation='relu'))
model.add(GlobalMaxPool1D())
else:
model.add(Bidirectional(LSTM(units=8)))
model.add(Dense(units=1, activation='sigmoid'))
model.summary()
"""编译、训练"""
model.compile('adam', 'binary_crossentropy', ['acc'])
model.fit(x, y, batch_size=1, epochs=500, verbose=2, validation_split=.125)
modeling(model_name='cnn')
modeling(model_name='rnn')
word2flag = {
'价格': 'subject', '价值': 'subject',
'高': 'adjective', '低': 'adjective',
'不': 'privative', '不是': 'privative',
}
word2value = {
'价格': -1, '价值': 1,
'高': 1, '低': -1,
'不': -1, '不是': -1,
}
def calculate(words):
dt = {'privative': 1}
flags = [word2flag[word] for word in words]
values = [word2value[word] for word in words]
for i in range(len(words)):
if flags[i] == 'privative':
dt['privative'] *= values[i]
else:
dt[flags[i]] = values[i]
subject = dt.get('subject', 0)
adjective = dt.get('adjective', 0)
privative = dt.get('privative')
return subject * adjective * privative
scores = [calculate(text.split()) for text in texts]
y_pred = [1 if score > 0 else 0 for score in scores]
accuracy = sum([1 if i == j else 0 for i, j in zip(y, y_pred)]) / len(y)
print(accuracy)
否定词
不
不是
不算
不怎么
不曾
不等于
不会
不能
不是
不算
不太
不再
从不
从来不
从没
从未
没
没有
无
并不
并不是
并没有
并未
没法
未
不得不
不是不
并非不
不可不
不是没
不是没有
不会不
别不
不无道理
未尝不可
是否
是不是
附录
en |
cn |
Sentiment Analysis |
情感分析 |
flag |
n.标志、旗帜;v 标记 |
degree word |
程度词 |
sentiment word |
情感词 |
privative |
否定词 |
sentiment |
感情;观点 |
emotion |
情感;情绪 |
separator |
分隔符 |
conjunction |
连接词 |
explicit |
明显的;直率的 |
obscure |
隐晦的;含蓄的 |
parse |
n.语法分析;vt.解析;vi.理解 |
lexical |
词汇的 |
syntax |
语法;句法; |
semantic |
语义(的) |