祭囃

祭囃

人群中观点传播的简易模型

27
2021-07-23

问题提出

当谈论某一具体问题时,人群中的不同个人往往持有不同观点。通过沟通、交流、对话、辩论,个人得以将自己的观点在人群中传播开来,并影响其他人。研究人群中的观点传播规律,一方面是社会学、传播学等领域饶有兴趣的学术课题,另一方面也是指导舆情管理、调度社会运行等现实活动的客观需求。为解决这一问题,人们提出过很多有效的模型,如基于传染病模型、基于机器学习和深度学习方法等。本文从人群中的个人特征、人际关系和观点传播的抽象入手,建立了一个简易模型,对人群中的观点传播能够进行一定程度的仿真与模拟。

问题建模

群体中的个人特征

u_1,u_2,\dots,u_n为某个群体中的个人,每个人对某一问题有不同的观点,并且对于是否向他人表达自己的态度有不同倾向。记p_i\in[0,1] 代表u_i对于该问题的观点,其数值解释为u_i的积极-消极评价程度。记o_i\in[0,1]代表u_i倾向于表达自己观点的程度:o_i越大,u_i就越可能向他人表达观点,即越渴望(就该问题)与他人进行交流;o_i越小,u_i就越可能不向他人表达观点,即越倾向于(就该问题)避免与他人进行交流。

在本文中,具体的个人u_i将被抽象为\{i;p_i;o_i\}的三元组。这一抽象过程极大简化了后续模拟的复杂程度。

群体中的人际关系

u_iu_j在人群中有一定的人际关系。u_iu_j的关系越熟稔及友善,当一方向另一方分享观点时,另一方就越容易接受他的观点;反之,二人的关系越陌生或敌对,当一方向另一方分享观点时另一方就越不容易接受。这一过程中,“人际关系”被转化为“对对方观点的信任程度”。记 u_iu_j的信任程度为值r_{i,j}。需要指出的是,r_{i,j}不一定等于r_{j,i},因为一段人际关系中双方对于对方的评价往往是不尽相同的。

对于所有可能的人际关系,可以将r_{i,j}整理成一矩阵R,称R为该人群的信任矩阵

群体中的观点传播

假设传播过程是离散的,即观点按轮次传播。 u_i在新一轮中的观点将继承自己在上一轮中的观点,并在一定程度上受到其他人的观点影响。定义集合U^{(t)}为第t轮中将会影响的态度的所有人,该集合的生成方法为:(1) u_i一定在集合中;(2)对于每个u_j,j\neq i,均以概率o_i被选入集合中。据此可以得到u_i在第 t轮的观点

p_i^{(t)}=\sum_{u_j\in U^{(t)}}{\frac{r_{(i,j)}}{\sum_{u_k\in U^{(t)}}r_{i,k}}p_j^{(t-1)}}

实验设置及结果

针对上述介绍的模型,赋予数值并进行实验。在本文介绍的实验中,设置人群规模 n=10,观点传播的轮次 t=10。依据不同的现实情景模式,设计了三类不同的实验数值:一般人-一般人模式异议者-倾听者模式教育者-学习者模式

一般人-一般人模式

一般人-一般人模式描述的是这样一种情况:群

体中所有个体均为一般人,没有哪个个体被预先赋

予一个异于其他人的身份。在这种情况下,p_io_i和信任矩阵R几乎被随机设置,但 R需要满足两个条件:

  1. r_{i,i}=1,即一个人对自己的信任程度总是被设置为 1;

  2. r_{i,j}\approx r_{j,i},即关系中双方的信任关系不会偏差太远。在实践中,r_{j,i}[0.9\cdot r_{i,j},1.1\cdot r_{i,j}]的范围内随机取值,且不超过r_{j,j}

随机初始化一组人群后,对其进行观点传播的模拟。一个实例如图 1,横坐标为模拟轮次,纵坐标为观点数值。可以观察到,经过若干轮模拟后,各人的观点将趋于相同。这符合我们日常生活中观察到的现象,即经过一段时间的沟通交流以后,人群内的观点总是趋于达成共识。

该实例中的信任矩阵为:

\begin{bmatrix} 1 & 0.73 & 0.246 & 0.178 & 0.239 & 0.962 & 0.481 & 0.045 & 0.2 & 0.932 \\ 0.74 & 1 & 0.428 & 0.662 & 0.666 & 0.423 & 0.94 & 0.573 & 0.975 & 0.603 \\ 0.236 & 0.407 & 1 & 0.57 & 0.338 & 0.55 & 0.702 & 0.637 & 0.895 & 0.196 \\ 0.175 & 0.599 & 0.534 & 1 & 0.628 & 0.261 & 0.958 & 0.913 & 0.628 & 0.076 \\ 0.249 & 0.729 & 0.366 & 0.685 & 1 & 0.814 & 0.168 & 0.834 & 0.941 & 0.09 \\ 0.938 & 0.462 & 0.501 & 0.253 & 0.886 & 1 & 0.932 & 0.597 & 0.258 & 0.545 \\ 0.478 & 1 & 0.748 & 0.928 & 0.16 & 0.912 & 1 & 0.617 & 0.241 & 0.42 \\ 0.045 & 0.599 & 0.589 & 0.873 & 0.909 & 0.602 & 0.558 & 1 & 0.478 & 0.741 \\ 0.203 & 0.99 & 0.882 & 0.649 & 1 & 0.24 & 0.24 & 0.495 & 1 & 0.495 \\ 0.962 & 0.56 & 0.183 & 0.079 & 0.086 & 0.505 & 0.433 & 0.797 & 0.536 & 1 \\ \end{bmatrix}

另一个实例如下图,可见具有相似的演化模式:

其信任矩阵为:

\begin{bmatrix} 1 & 0.598 & 0.401 & 0.062 & 0.103 & 0.86 & 0.27 & 0.657 & 0.505 & 0.055 \\ 0.619 & 1 & 0.84 & 0.615 & 0.171 & 0.786 & 0.333 & 0.417 & 0.043 & 0.759 \\ 0.366 & 0.862 & 1 & 0.69 & 0.601 & 0.31 & 0.806 & 0.936 & 0.535 & 0.275 \\ 0.06 & 0.598 & 0.751 & 1 & 0.924 & 0.245 & 0.746 & 0.979 & 0.132 & 0.586 \\ 0.11 & 0.161 & 0.581 & 0.924 & 1 & 0.116 & 0.56 & 0.519 & 0.826 & 0.602 \\ 0.798 & 0.78 & 0.332 & 0.245 & 0.123 & 1 & 0.097 & 0.657 & 0.578 & 0.342 \\ 0.255 & 0.324 & 0.78 & 0.784 & 0.526 & 0.101 & 1 & 0.447 & 0.654 & 0.423 \\ 0.609 & 0.437 & 0.92 & 0.946 & 0.487 & 0.611 & 0.408 & 1 & 0.297 & 0.383 \\ 0.522 & 0.04 & 0.514 & 0.122 & 0.866 & 0.565 & 0.691 & 0.32 & 1 & 0.387 \\ 0.051 & 0.802 & 0.297 & 0.528 & 0.583 & 0.338 & 0.45 & 0.346 & 0.39 & 1 \\ \end{bmatrix}

异议者-倾听者模式

议者-倾听者模式描述的是这样一种情况:对于一个具体问题,群体中的某个人产生了一种新的意见,他将向群体中的其他人发表自己的观点。为了构成这种情况,我们令p_1=1p_2=p_3=\dots=p_10=0,并且o_1=1,即在每轮中其他人总是会受到u_1的影响。o_2,o_3,\dots o_n和信任矩阵R被随机设置。一个实例如下图。

信任矩阵略。可以看到,虽然异议者将在一定程度上被其他人“说服”,但他的观点将流入人群中。

异议者-倾听者模式的一种特例为“权威的异议者”。在这种情况下,提出新意见的人凭借以往的表现收获了其他人的信任,因此当他再次提出新的意见时,其他人对他的信任程度将会非常高。这种现象将表现在信任矩阵上。为此,在随机设置一个信任矩阵的基础上,将r_{2,1},r_{3,1},\dots, r_{n,1}均设置为 2,意味着其他人在该问题上对于 u_1的信任超过对自己的信任,即“权威的异议者”。一个实验的实例如下图。

该实例中的信任矩阵为:

\begin{bmatrix} 2 & 0.848 & 0.305 & 0.324 & 0.27 & 0.507 & 0.836 & 0.515 & 0.789 & 0.02 \\ 2 & 1 & 0.089 & 0.206 & 0.511 & 0.444 & 0.002 & 0.678 & 0.856 & 0.336 \\ 2 & 0.09 & 1 & 0.125 & 0.378 & 0.311 & 0.269 & 0.337 & 0.36 & 0.818 \\ 2 & 0.211 & 0.129 & 1 & 0.674 & 0.698 & 0.123 & 0.694 & 0.655 & 0.239 \\ 2 & 0.51 & 0.384 & 0.733 & 1 & 0.141 & 0.266 & 0.464 & 0.617 & 0.391 \\ 2 & 0.471 & 0.283 & 0.633 & 0.14 & 1 & 0.032 & 0.289 & 0.853 & 0.731 \\ 2 & 0.002 & 0.26 & 0.13 & 0.262 & 0.03 & 1 & 0.732 & 0.02 & 0.183 \\ 2 & 0.731 & 0.345 & 0.681 & 0.438 & 0.285 & 0.693 & 1 & 0.34 & 0.884 \\ 2 & 0.837 & 0.37 & 0.633 & 0.562 & 0.769 & 0.021 & 0.307 & 1 & 0.836 \\ 2 & 0.34 & 0.865 & 0.261 & 0.378 & 0.708 & 0.196 & 0.877 & 0.872 & 1 \\ \end{bmatrix}

与一般的异议者-倾听者模式相比,可以观察到权威的异议者能够更多地将自己的观点传播给其他人。

教育者-学习者模式

教育者-学习者模式可以被视为一种更加特殊的异议者-倾听者模式,它描述的是这样一种情况:持有异议的人扮演教师的身份,其他人对于此人的观点十分信任,且对除他以外的其他人的观点都不信任。这种情况下,除教师以外的其他人将作为学生,学习教师的观点。为了达成这一情况,我们将r_{2,1},r_{3,1},\dots, r_{n,1}均设置为 2,并且将其他位置设置为 0.1。这种模式下的一个实例如图。

它的信任矩阵为:

\begin{bmatrix} 2 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 \\ 2 & 1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 \\ 2 & 0.1 & 1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 \\ 2 & 0.1 & 0.1 & 1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 \\ 2 & 0.1 & 0.1 & 0.1 & 1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 \\ 2 & 0.1 & 0.1 & 0.1 & 0.1 & 1 & 0.1 & 0.1 & 0.1 & 0.1 \\ 2 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 1 & 0.1 & 0.1 & 0.1 \\ 2 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 1 & 0.1 & 0.1 \\ 2 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 1 & 0.1 \\ 2 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 0.1 & 1 \\ \end{bmatrix}

总结

本文从人群中的个人特征、人际关系和观点传播的抽象入手,建立了一个简易模型,对人群中的观点传播进行了一定程度的仿真与模拟。本文讨论了三种常见的传播模式,分别是一般人-一般人模式,异议者-倾听者模式和教育者-学习者模式,可以看到构建的模型均能在很大程度上反映这些模式的典型特征。

与其他更精确的方法相比,本文方法最明显的优势在于:计算简单,仿真所需求的计算资源和时间资源相当低。此外,本文的创新点还有:

  1. 考虑了个人表达观点的倾向程度o_i ,使得运行结果一定程度上体现了个人外向或内向的性格差异;

  2. 将人际关系抽象为信任矩阵R,极大地简化了计算,同时通过对 R的具体的、非对称的设定可以反映更多样人际关系。

但本文的模型仍然是一个过度简化的模型,对许多关系的处理过于粗糙。例如,不支持多个话题的同步传播;认为个人观点只会继承自己先前点或受到其他人影响而改变考虑到个人认识的不断演进;没有考虑到人际关系的动态变化⋯⋯等等。本文可以作为对传播模型的简单尝试;当用到精确的推理场景时,更细致、更完备的模型仍然是必要的。

代码

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>
using namespace std;

#define USER_NUM 10
#define TIME_STEP 10
#define N 999

class People {
   public:
    int id;
    double attitude;
    double outgoing;
    People(int id);
};

People::People(int id) {
    this->id = id;
    attitude = rand() % (N + 1) / (float)(N + 1);
    outgoing = rand() % (N + 1) / (float)(N + 1);
}

int main() {
    srand(time(NULL));
    vector<People> users;
    for (int i = 0; i < USER_NUM; i++) {
        People p(i);
        cout << p.attitude << '\t';
        users.push_back(p);
    }
    cout << endl;
    double relationship[USER_NUM][USER_NUM];
    for (int i = 0; i < USER_NUM; i++) {
        for (int j = 0; j < USER_NUM; j++) {
            if (i == j) {
                relationship[i][j] = 1;
            } else if (i < j) {
                relationship[i][j] = rand() % (N + 1) / (float)(N + 1);
            } else {
                double w = rand() % 100 / (float)100;
                w /= 10;
                if (rand() % 2 == 0) {
                    w = 1 + w;
                } else {
                    w = 1 - w;
                }
                double a = relationship[j][i] * w;
                double b = ((int)(a * 1000 + 0.5)) / 1000.0;
                if (b > 1) {
                    relationship[i][j] = 1;
                } else if (b < 0) {
                    relationship[i][j] = 0;
                } else {
                    relationship[i][j] = b;
                }
            }
        }
    }

    // 打印关系
    for (int i = 0; i < USER_NUM; i++) {
        for (int j = 0; j < USER_NUM; j++) {
            cout<<relationship[i][j]<< '\t';
        }
        cout<<endl;
    } 
    cout <<endl;

    // 传播信息
    double newAttitude[USER_NUM];
    for (int z = 0; z < TIME_STEP; z++) {
        for (int i = 0; i < USER_NUM; i++) {
            vector<int> anouncer;
            newAttitude[i] = 0;
            double tw = 0;
            for (int j = 0; j < USER_NUM; j++) {
                if (i == j) {
                    anouncer.push_back(j);
                    tw += relationship[i][j];
                    continue;
                } else {
                    if (rand() % (N + 1) / (float)(N + 1) <=
                        users[j].outgoing) {
                        anouncer.push_back(j);
                        tw += relationship[i][j];
                    }
                }
            }
            for (int j = 0; j < anouncer.size(); j++) {
                int index = anouncer[j];
                newAttitude[i] +=
                    relationship[i][index] / tw * users[index].attitude;
            }
            cout << newAttitude[i] << '\t';
        }
        cout << endl;
    }
    return 0;
}