Geo Word Clouds 论文复现 (2020.8)

准备阶段

  • 地图准备: 用 echarts.js 绘制山东省地图,并修改图片大小为 800×500 并保存,作为词云背景 在这里插入图片描述
  • 初步确定 Geo Map 范围 实验初始阶段的想法是用山东的17个地级市(这样做结果更加直观)作为输入的标签数据,来测试词云对地理信息的反映程度,所以先用 Matlab App 中的 Image Viewer 大致测取各地级市的范围(单位为像素点),结果如下

City	min_x	max_x	min_y	max_y
威海		617		742		111		209
烟台		471		675		81		226
青岛		468		594		162		342
潍坊		354		509		141		324
日照		391		480		290		401
东营		360		448		42		183
淄博		311		380		147		301
临沂		285		439		275		479
滨州		276		364		26		210
莱芜		281		330		235		290
济南		186		310		115		284
泰安		170		335		240		321
济宁		153		302		299		474
枣庄		235		315		375		473
德州		144		301		79		246
聊城		108		209		177		319
菏泽		66		187		313		460
  • 最后根据各地市的面积比例以及限定的坐标范围来生成随机数据
  • 确定实验流程

实验阶段

这一部分只简要介绍实验流程,实现的具体细节见代码实现部分

初始随机数据集在地图上的分布情况如下 在这里插入图片描述 首先使用 Python 中的 wordcloud 库对生成的随机数据进行可视化,结果如下: 可以看出单词的分布比较随机杂乱,没有包含任何地理信息,且单词的大小几乎相同,难以读出频率信息 在这里插入图片描述 在不聚类的情况下,只加入地理信息因素,绘制的词云图如下: 可以看出,虽然现在的词云图已反映出了地理信息,但在地图中为每个点放置一个单词,很难找到出现频率高的单词,同时相邻近的单词颜色比较相近,难以区分,视觉效果不佳 在这里插入图片描述

加入原论文中的颜色分配算法,结果如下: 在这里插入图片描述

之后对初始数据集进行 K-means 聚类,继续绘制词云图,结果如下: 其中各单词的位置与实际地理位置相吻合,同时,单词的大小也在一定程度上反映了该地市的面积 (由于这里只着重测试地理位置,聚类较少,所以地图形状空缺较大,用户可以自定义填充单词进行形状填充) 在这里插入图片描述 叠加图层观察可视化结果,可以看出,各聚类中心大部分被单词所覆盖,虽有个别点出现偏差,但也在可接受的范围之内。 在这里插入图片描述 接下来再对另一个的数据集进行测试: 数据大小为 9935 ,执行 K-means 聚类后生成 126 个聚类 运行结果如下: 在这里插入图片描述 再对几个出现频率较高的单词进行叠加图层比较,结果如下:

Edith

单词覆盖基本准确 在这里插入图片描述 Alice

左边的聚类覆盖基本吻合,右边的聚类由于单词 Nick 在聚类中心,同时如果在聚类中心放置的话,由于 Alice 的字体较大,无法放置,所以偏移到了左边 在这里插入图片描述 Bettina

左边的聚类基本吻合,右边的聚类由于与 Gasol 冲突,进行了左移调整 在这里插入图片描述 可视化衡量指标的结果将在下一部分进行描述

代码实现部分

生成初始数据集

为了方便实验,这里的坐标单位均为像素,实际应用的话,只需将经纬度坐标按一定比例转换即可。 输入山东省各地市的地理位置信息以及自己所指定的标签名称,来生成包含地理位置坐标的标签数据集

使用 C++ 中的 random_device 随机数引擎生成服从正态分布的随机数据: RandomData.cpp

<div class="highlight highlight-source-c++ position-relative overflow-auto" data-snippet-clipboard-copy-content="#include
using namespace std;

//Geo Info
struct Region{
int min_x,max_x,min_y,max_y,area;
void Output(){
cout<<min_x<<" "<<max_x<<" "<<min_y<<" "<<max_y<<" "<<area<<endl; } }geo[20]; tags info struct tags{ string name; int num,sz; idx[10]; void output(){ cout<<num<<" "<<name<<" "; for(int i="1;i<=sz;i++){" cout<<idx[i]<<" cout<
>city; in>>Geo[i].min_x>>Geo[i].max_x>>Geo[i].min_y>>Geo[i].max_y>>Geo[i].area; } in.close(); /* for(int i=1;i<=17;i++){ Geo[i].Output(); } */ freopen(“TagsInfoVer2.txt”,”r”,stdin); freopen(“CityTags3.txt”,”w”,stdout); // Total Points int Count=0; //Input Tags Region vector
a; string str; stringstream ss; bool flag=false; for(int i=1;i<=60;i++){ str=””; getline(cin,str); ss.clear(); ss<

>tags[i].num; ss>>tags[i].name; while(ss){ int t; ss>>t; a.push_back(t); } a.pop_back(); tags[i].sz=a.size(); for(int j=0;j
<a.size();j++){ tags[i].idx[j+1]="a[j];" } a.clear(); count+="tags[i].num*tags[i].sz;" tags[i].output(); generate data for(int i="1;i<=60;i++){" j="1;j<=tags[i].sz;j++){" frequency int num="((double)tags[i].num/(double)Count)*10000;" cout<<num<<endl; random_device rd; mt19937_64 eng(rd()); coordinate uniform_int_distribution
distrx(Geo[tags[i].idx[j]].min_x, Geo[tags[i].idx[j]].max_x); uniform_int_distribution

distry(Geo[tags[i].idx[j]].min_y, Geo[tags[i].idx[j]].max_y); // Tags x y frequency for(int k=0;k
<num;k++){ cout<<tags[i].name<<" "<<distrx(eng)<<" "<<distry(eng)<<" "<<tags[i].idx[j]<

#include <bits/stdc++.h>
using namespace std;

//Geo Info
struct Region{
	int min_x,max_x,min_y,max_y,area;
	void Output(){
		cout<
        <<
        " "<
        
         <<
         " "<
         
          <<
          " "<
          
           <<
           " "<
           <
           <endl; } }geo[
            20];


            //Tags Info

            struct 
            Tags{
	string name;
	
            int num,sz;
	
            int idx[
            10];
	
            void 
            Output(){
		cout<
            
             <<
             " "<
             
              <<
              " "; 
              for(
              int i=
              1;i<=sz;i++){ cout<
              
               <<
               " "; } cout<
               <endl; } }tags[
                100]; 
                int 
                main() { string city,TagName; 
                int min_x,max_x,min_y,max_y,area; ifstream in; in.
                open(
                "SDCities.txt"); 
                //Input Geo Info 
                for(
                int i=
                1;i<=
                17;i++){ in>>city; in>>Geo[i].
                min_x>>Geo[i].
                max_x>>Geo[i].
                min_y>>Geo[i].
                max_y>>Geo[i].
                area; } in.
                close(); 
                /* 
                 for(int i=1;i<=17;i++){ 
                 Geo[i].Output(); 
                 } 
                 */ 
                freopen(
                "TagsInfoVer2.txt",
                "r",stdin); 
                freopen(
                "CityTags3.txt",
                "w",stdout); 
                // Total Points 
                int Count=
                0; 
                //Input Tags Region  vector<
                int> a; string str; stringstream ss; 
                bool flag=
                false; 
                for(
                int i=
                1;i<=
                60;i++){ str=
                ""; 
                getline(cin,str); ss.
                clear(); ss<
                
                 >tags[i].
                 num; ss>>tags[i].
                 name; 
                 while(ss){ 
                 int t; ss>>t; a.
                 push_back(t); } a.
                 pop_back(); tags[i].
                 sz=a.
                 size(); 
                 for(
                 int j=
                 0;j
                 
                  size();j++){ tags[i].
                  idx[j+
                  1]=a[j]; } a.
                  clear(); Count+=tags[i].
                  num*tags[i].
                  sz; 
                  //tags[i].Output(); } 
                  //Generate Data 
                  for(
                  int i=
                  1;i<=
                  60;i++){ 
                  for(
                  int j=
                  1;j<=tags[i].
                  sz;j++){ 
                  // Frequency 
                  int num=((
                  double)tags[i].
                  num/(
                  double)Count)*
                  10000; 
                  //cout<
                   
                    <
                    
                    random_device rd; mt19937_64 
                  eng(
                  rd()); 
                  // Coordinate uniform_int_distribution<
                  unsigned 
                  long 
                  long> 
                  distrx(Geo[tags[i].
                  idx[j]].
                  min_x, Geo[tags[i].
                  idx[j]].
                  max_x); uniform_int_distribution<
                  unsigned 
                  long 
                  long> 
                  distry(Geo[tags[i].
                  idx[j]].
                  min_y, Geo[tags[i].
                  idx[j]].
                  max_y); 
                  // Tags x y frequency 
                  for(
                  int k=
                  0;k
                  <num;k++){ cout<<tags[i].
                   name<<
                   " "<<
                   distrx(eng)<<
                   " "<<
                   distry(eng)<<
                   " "<
                   
                    idx[j]<
                    <endl; } 
                     return 
                     0; }