中文情感分析【实体级】

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Yellow_python/article/details/101079649

计分方式

  • 组合观点
    = i = 1 n ( i j = 1 n j ( 1 ) ) 情感分 = 主体 * \sum_{i=1}^{n} {(观点_i * \prod_{j=1}^{n}程度_j * (-1)^{否定数})}

  • 直接观点
    = i j = 1 n j ( 1 ) 情感分 = 观点_i * \prod_{j=1}^{n}程度_j * (-1)^{否定数}

句子 主体 观点 程度(含否定) 得分 观点类型
价格真tm高 价格(-1) 高(1) 真tm(2) 11 2 = 2 -1 1 * 2 = -2 组合观点
价格没有不合理 价格 合理(1) 没有(-1)不(-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 = 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 = {'手机', '音箱', '拍照'}

# TF-IDF向量训练
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 语义(的)

猜你喜欢

转载自blog.csdn.net/Yellow_python/article/details/101079649