ナード戦隊データマン

機械学習と自然言語処理についてのブログ

移動平均を使って感情を気分へ変換する

感情や気分の心理学的な定義は、感情を使ったアプリの開発に役立てられると考えています。ここでは、感情の構成要素と、それを気分へ変換する方法を論文1をもとに書きます。

概要

emotion_and_mood.GIF

感情は、ArousalとValenceという構成要素から成ります。Arousalは感情の覚醒度合いで、高ければ覚醒、低ければ鎮静を表します。感情クラスとArousal,Valenceの対応2を示した図は以下です。

Table 2

Emotion ratings for arousal, valence, CF-self, CF-other, and CF-overall in alphabetical order.

EmotionArousalValenceCF-selfCF-otherCF-overall
Affectionate2.92.576.415.86.105
Aggressive8.127.674.265.95.08
Aggrieved5.915.654.855.054.95
Aghast7.26.473.714.434.07
Agonized6.997.522.423.212.815
Amused3.452.476.46.096.245
Angry8.067.54.585.384.98
Anxious7.046.594.075.24.635
Apologetic4.734.844.434.334.38
Ashamed5.886.013.563.83.68
Bored4.045.833.745.354.545
Carefree3.42.346.626.346.48
Caring3.653.066.535.486.005
Compassionate4.955.474.564.344.45
Concerned6.275.65.585.515.545
Confident2.72.616.555.526.035
Confused6.296.143.554.43.975
Contemptuous6.467.532.633.623.125
Content2.052.286.355.565.955
Cross6.976.685.226.115.665
Curious5.013.346.956.036.49
Desperate7.487.533.544.163.85
Disappointed5.956.734.725.264.99
Disgusted6.877.423.343.893.615
Doubtful6.056.254.855.455.15
Embarrassed4.965.044.194.734.46
Enthusiastic5.732.665.24.764.98
Envious7.546.753.895.094.49
Expectant5.373.575.495.885.685
Frantic8.417.413.273.53.385
Frustrated6.97.464.215.44.805
Grateful32.526.465.295.875
Grievous6.266.823.984.64.29
Guilty6.597.033.43.493.445
Hateful8.168.272.423.452.935
Humble4.965.93.483.253.365
Hurt6.266.643.884.764.32
In love6.271.725.485.525.5
Interested3.962.547.366.196.775
Jaunty5.983.984.354.94.625
Jealous6.146.923.265.24.23
Joyful4.5526.586.26.39
Jubilant5.081.775.174.624.895
Jumpy7.226.373.544.413.975
Lonely5.787.173.855.144.495
Lyrical5.083.185.035.25.115
Melancholic4.425.764.164.234.195
Offended6.046.493.925.274.595
Panic8.267.782.83.363.08
Pardoning3.563.365.174.134.65
Passionate5.692.216.114.785.445
Proud4.122.85.385.445.41
Relaxed1.722.376.075.085.575
Relieved2.682.455.385.025.2
Remorseful5.295.533.333.353.34
Sad5.916.64.515.484.995
Shocked7.566.863.263.893.575
Sick6.717.63.654.233.94
Surprised5.744.094.735.144.935
Triumphant5.53.483.774.093.93
Troubled6.435.774.895.395.14
Wistful5.476.033.523.743.63

The German translations were used in the actual questionnaire.

提案手法では、この感情を気分へ変換するために、フレームを用いています。気分は、ある期間(フレーム)内の感情の系列から、何らかの写像Fを対応させることで数値的に変換し、この数値を量子化することで気分を分類します。

frame_emotions.GIF

写像関数Fは以下のようなものが考えられます:

  • 平均
  • 最大値
  • 最も継続した値
  • 最初に経験した値
  • 最後に経験した値

eval.GIF

この中で最も精度の高いのは、移動平均のようです。

jupyterで実行

感情の乱数を生成します。

from random import random
size = 100
rate = 0.3
es_tmp = [(2*(random()-0.5), 2*(random()-0.5)) for _ in range(size)]
es = []
for e in es_tmp:
    if random() < rate:
        es.append(e)
    else:
        es.append((0,0))

移動平均関数を作成します。

import numpy as np
def mean(es, n=10):
    out1 = []
    out2 = []
    out3 = []
    for i,_ in enumerate(es):
        s = i-n
        if s < 0:
            s = 0
        target = es[s:i+1]
        tmp_v = [x[0] for x in target]
        tmp_a = [x[1] for x in target]
        x = sum(tmp_v)/n
        y = sum(tmp_a)/n
        out1.append(x)
        out2.append(y)
        z = np.dot(x,y)
        if z > 0:
            out3.append(2-np.sign(x))
        elif z < 0:
            out3.append(3+np.sign(x))
        else:
            out3.append(0)
    return out1, out2, out3

V, A, Q = mean(es, 10)

気分の減衰をシミュレートします。

os = [[],[],[],[]]
r = 0.9
for i, (x,y,c) in enumerate(zip(V,A,Q)):
    try:
        for j in range(len(os)):
            os[j].append(os[j][i-1]*r)
    except:
        for j in range(len(os)):
            os[j].append(0)
    os[int(c-1)][i] = abs(x*y)

プロットします。

%matplotlib inline
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
plt.figure(num=None, figsize=(9, 9), dpi=80, facecolor='w', edgecolor='k')
plt.subplot(411)
plt.scatter(x=V, y=A, c=Q)
plt.subplot(412)
for o in os:
    plt.plot(o)
plt.legend(["amusement","anxiety","distress","calmness"], loc=1)
plt.subplot(413)
plt.plot([x[0] for x in es])
plt.legend(["valence"], loc=1)
plt.subplot(414)
plt.plot([x[1] for x in es], "y")
plt.legend(["arousal"], loc=1)

出力

plot_mood.png