1.3 Brightkite数据集处理

目的

      从snap上下载的Brightkite数据集已经是图结构,但它并不满足实验的要求,在进行社区挖掘前要先对数据进行规范化处理,使数据按照我们设定的格式进行存储。
      首先是原数据集中有一些id对应的点不存在,但边数据集中有以此点为端点的边。在处理过程中应删除这些边。
      其次是我们使用一个id对应的一条签到信息来构造一个点,此id的其它签到信息应删除。
      然后是我们在程序中使用图结构保存数据,在处理数据时最好建立一个图数据结构。此数据结构只用于处理数据。
      在进行社区挖掘时需要用到点的度,原数据中没有直接给出每个点的度信息,需要我们在处理数据时计算。
      原数据集中有些数据还有可能是不正确的,我们应剔除那些不正确的信息。

处理过程及代码

舍去无用签到信息

介绍
      在本部分对Brightkite数据集中的签到信息进行处理,即对Brightkite_totalCheckins.txt进行处理。一个id对应的用户会有多条签到信息,即一个人可能会多次签到,我们只需要一个id的一条信息即可。
      Brightkite_totalCheckins.txt文件中每条签到信息是一行数据,每个id对应的多条签到信息是相邻的,id从前到后是递增的。我们取每个id对应的签到信息的第一条信息。
      在此步骤中,会对所取的信息进行判断,如果此id对应的第一条签到信息不正确,则会再选择此id对应的下一条签到信息。如果此id对应的所有签到信息都不正确,则舍弃此id对应的信息。
处理代码

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 处理Brightkite中的签到数据
 * Brightkite数据构建的网络由由58228个节点和214078个边缘组成。
 * @author dxt
 *
 */
public class getDatas {
	/**
	 * 从签到数据文件src中获取所需数据,并复制到文件dest中
	 * 获取的数据:
	 * id--唯一标识签到的人
	 * 坐标--位置信息
	 * 由于同一个人会存在多次签到信息,我们只取第一条签到信息。
	 * @param src
	 * @param dest
	 */
	public static int copyData(File src, File dest){
		//使用缓冲字节流来进行读取写入操作
		BufferedReader br;
		BufferedWriter bw;
		//计数器:记录复制了多少条数据
		int count = 0;
		try {
			br = new BufferedReader(new FileReader(src));
			bw = new BufferedWriter(new FileWriter(dest, true));
			//进行读取,信息组合,写入操作操作
			String line = null;
			String message = null;
			String id = null;
			String x = null;
			String y = null;
			String temp_id = null;
			while((line=br.readLine()) != null){
				//分格数据
				String[] parts = line.split("	");
				//获取数据
				temp_id = parts[0];	//将当前行的id赋给temp_id
				if(temp_id.equals(id)){	//保证只读取相同id的第一次签到数据
					continue;
				}
				id = parts[0];
				x = parts[2];
				y = parts[3];
				
				//对数据进行判断使其合法
				if(x.equals("0.0") || y.equals("0.0")){	//如果位置信息不合法,则此条信息废除
					id = null;	//重新读取对应id的数据
					continue;	
				}
				//将数据按照对应格式拼接
				if(id != null && x != null && y != null){
					message = id + "\t" + x + "\t" + y;
				}else{
					System.out.println("出现错误");
				}
				//将数据写入目标文件
				bw.write(message);
				bw.newLine();
				count++;	//写一条数据,计数器+1
			}
			bw.flush();
			br.close();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e){
			e.printStackTrace();
		}
		return count;
	}
	
	public static void main(String[] args){
		//源文件
		File src = new File("F://brightkite数据集//loc-brightkite_totalCheckins//Brightkite_totalCheckins.txt");
		//目的文件
		File dest = new File("F://brightkite数据集//loc-brightkite_totalCheckins//brightkite.txt");
		//获取数据
		int count = copyData(src, dest);
		System.out.println(count);
	}
}

结果
      经过处理后,我们获得的brightkite.txt文件中有50686条数据。

创建数据结构

介绍
      建立点结构,边结构和图结构,便于之后的数据处理。采用面向对象的方式,建立点类、边类。处理数据只需要点类和边类就足够了,不需要再建立图类。
      点类:其属性有id,经度x,纬度y,还有点的度degree。其中id,经度,维度都可以直接从签到信息中获取,度需要我们计算。
      边类:我们通过保存两点的方式保存一条边,因为两点确定一条边。同时还记录此边的长度。

代码
点类:

/**
 * 空间网络节点类
 * 每个节点由三个属性:id 、 位置 、度
 * @author dxt
 *
 */
public class Node {
	private int id;	//唯一确定空间中的一个节点
	private double x;	//位置 x--纬度
	private double y;	//位置y--经度
	private int degree;	//度:邻接点的个数
	
	//构造方法
	public Node(){}
	public Node(int id){
		super();
		this.id = id;
	}
	public Node(int id, double x, double y){
		super();
		this.id = id;
		this.x = x;
		this.y = y;
	}
	public Node(int id, double x, double y, int degree){
		super();
		this.id = id;
		this.x = x;
		this.y = y;
		this.degree = degree;
	}
	
	//javabean
	public void setId(int id){
		this.id = id;
	}
	public int getId(){
		return this.id;
	}
	public void setX(double x){
		this.x = x;
	}
	public double getX(){
		return this.x;
	}
	public void setY(double y){
		this.y = y;
	}
	public double getY(){
		return this.y;
	}
	public void setDegree(int degree){
		this.degree = degree;
	}
	public int getDegree(){
		return this.degree;
	}
}

边类:

/**
 * 边类
 * 一条边有两个端点,边有长度
 * 边的长度可由两点的位置来计算
 * @author dxt
 *
 */
public class Edge {
	private Node n1;	//边的一个端点
	private Node n2;	//边的另一个端点
	private double length;	//边的长度
	
	//构造方法
	public Edge(){}
	public Edge(int id1, int id2){
		this.n1 = new Node(id1);
		this.n2 = new Node(id2);
	}
	public Edge(Node n1, Node n2){
		this.n1 = n1;
		this.n2 = n2;
		//this.length = this.computeLength();	//调用自身方法来计算length
	}
	
	//javabean
	public void setLength(double length){
		this.length = length;
	}
	public double getLength(){
		return this.length;
	}
	public Node getFirstNode(){
		return n1;
	}
	public Node getSecondNode(){
		return n2;
	}
	/**
	 * 计算两点间的距离
	 * 因为数据是基于位置的
	 * 可以依据经纬度计算出两点间的距离
	 * @return
	 */
	public double computeLength(){
		double earth_radius = 6378.137;	//将地球看作圆,地球的平均半径,单位km
		double lat1 = n1.getX();	//获取位置1的纬度,北纬为正,南纬为负
		double lon1 = n1.getY();	//获取位置1的经度,东经为正,西经为负
		double lat2 = n2.getX();	//获取位置2的纬度
		double lon2 = n2.getY();	//获取位置2的经度
		
		double radLon1 = lon1 * (float)(Math.PI /180.0);	//转换为弧度
		double radLon2 = lon2 * (float)(Math.PI /180.0);
		double a = radLon1 - radLon2;
		double radLat1 = lat1 * (float)(Math.PI /180.0);	//转换为弧度
		double radLat2 = lat2 * (float)(Math.PI /180.0);
		double b = radLat1 - radLat2;
		double dis =  2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)+  
                Math.cos(radLon1) * Math.cos(radLon2)* Math.pow(Math.sin(b / 2), 2)));  
		dis = dis * earth_radius;
		dis = Math.round(dis * 1000) / 1000.0;//保留三位小数,精确到米  
		return dis;
	}
	
	/**
	 * 测试computeDistance()方法
	 * @param args
	 */
	public static void main(String[] args){
		Node n1 = new Node(1, 0.0, -90.0);
		Node n2 = new Node(2, 0.0, 0.0);
		Edge e = new Edge(n1, n2);
		System.out.println(e.computeLength());
		
	}
}

解释
      在边类中我们使用了一种基于经纬度计算距离的方法,这种计算方法参考了谷歌地图中的距离计算方法。

固定格式存储数据

介绍
      我们处理Brightkite数据集的点文件和边文件,是为了得到符合我们使用要求的点集文件和边集文件。
      其中点集文件要求:每行数据表示一个点;每个点具有四个属性:id,经度x,纬度y,度degree。
      其中边集文件要求:每行数据表示一条边;每行数据有两个id构成,表示id对应的两个点之间有此边。
代码

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import algorithm.Edge;
import algorithm.Node;


/**
 * 处理brightkite.txt和Brightkite_edges.txt
 * 1. 如果点集中没有点u,但边集中有以u为顶点的边,则去除此边
 * 2. 依据边集文件计算点的度
 * @author dxt
 *
 */
public class getAvailableDatas {
	//点集
	private List<Node> nodeList;
	//边集
	private List<Edge> edgeList;
	//图的点的个数
	private int size;
	
	//空构造方法
	public getAvailableDatas(){}
	//javabean
	public int getSize(){
		return this.size;
	}
		
	/**
	 * 从nodeList中找出对应id的点
	 * 返回一个顶点 或 null
	 * @param id
	 * @return
	 */
	public Node getNode(int id){
		for(int i=0; i<this.nodeList.size(); i++){
			if(id == this.nodeList.get(i).getId()){
				return this.nodeList.get(i);
			}
		}
		return null;
	}
	/**
	 * 对点数据文件(nodeSrc)和边数据文件(edgeSrc)进行处理
	 * 1. 如果点集中没有点u,但边集中有以u为顶点的边,则去除此边
	 * 2. 依据边集文件计算点的度
	 * 然后将处理后的数据保存到nodeDest和edgeDest文件中
	 * @param nodeSrc
	 * @param edgeSrc
	 * @param nodeDest
	 * @param edgeDest
	 */
	public void getData(File nodeSrc, File edgeSrc, File nodeDest, File edgeDest){
		//1. 首先获取有哪些节点(以id唯一标识)
		nodeList = new ArrayList<Node>();
		//1.1 选择流
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(nodeSrc));
			//1.2进行读取操作
			String line = null;	//保存读到的每一行信息
			Node temp_node = null;
			int id;
			double x;
			double y;
			while((line = br.readLine()) != null){
				String[] datas = line.split("\t");
				id = Integer.valueOf(datas[0]);
				x = Double.valueOf(datas[1]);
				y = Double.valueOf(datas[2]);
				//开始构造图的点集
				temp_node = new Node(id, x, y);	//建立节点
				nodeList.add(temp_node);			//添加到点集中
			}
			//释放资源
			br.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e){
			e.printStackTrace();
		}
		
		//2. 处理边集, 删除不符合的边,同时计算对应点的度
		edgeList = new ArrayList<Edge>();
		//2.1 选择处理流
		BufferedReader br_edge = null;
		try {
			br_edge = new BufferedReader(new FileReader(edgeSrc));
			//2.2 进行读取
			String line = null;
			int id_one, id_two;
			Node n_one = null, n_two = null;
			int id_one_temp = -1;	//初始设为-1, 用于在查找时提高效率
			int degree = 0;		//节点的度
			while((line=br_edge.readLine()) != null){
				String[] datas = line.split("\t");
				id_one = Integer.valueOf(datas[0]);
				id_two = Integer.valueOf(datas[1]);
				
				//从nodeList中找出对应的点,依据数据格式进行判断,提高其效率
				if(id_one != id_one_temp){	//如果id_one改变,则表示n_one改变,否则一直为之前的
					//首先要将id_one_temp对应点的度初始化
					if(this.getNode(id_one_temp) != null){
						this.getNode(id_one_temp).setDegree(degree);
					}
					degree = 0;	//度的计数从零开始
					
					n_one = this.getNode(id_one);	//找到对应id的点
					n_two = this.getNode(id_two);
				}else{	//否则id_one不变
					n_two = this.getNode(id_two);	//n_two是经常改变的
				}
				
				//如果已经找出两点,则构造边,并添加到边集中
				if(n_one != null && n_two != null){
					//构造边
					Edge e = new Edge(n_one, n_two);
					e.setLength(e.computeLength());
					//将边添加到边集中
					this.edgeList.add(e);
					
					if(id_one != id_one_temp){
						//id_one的度为1
						degree = 1;
					}else{
						//修改n_one的度
						degree++;
					}
					
					//保存此次的id_one,用于下一次查找
					id_one_temp = id_one;
				}
				else{	//否则(可能点集中没有对应的点),则舍去此行信息,读取下一行信息
					//保存此次的id_one,用于下一次查找
					id_one_temp = id_one;
					continue;
				}
			}
			this.getNode(id_one_temp).setDegree(degree);	//对最后一个id_one设置度
			//关闭字节流
			br_edge.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e){
			e.printStackTrace();
		}
		
		//3. 将点集写入点集文件
		//3.1 选择流
		BufferedWriter bw_node = null;
		try {
			bw_node = new BufferedWriter(new FileWriter(nodeDest, true));
			//3.2 获取信息,并写入文件
			for(int i=0; i<this.nodeList.size(); i++){
				int id = this.nodeList.get(i).getId();
				double x = this.nodeList.get(i).getX();
				double y = this.nodeList.get(i).getY();
				int degree = this.nodeList.get(i).getDegree();
				String datas = id + "\t" + x + "\t" + y + "\t" + degree;
				
				bw_node.write(datas);
				bw_node.newLine();
			}
			bw_node.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} 
		
		//4. 将边集写入边集文件
		BufferedWriter bw_edge = null;
		try {
			bw_edge = new BufferedWriter(new FileWriter(edgeDest, true));
			for(int i=0; i<this.edgeList.size(); i++){
				int id_one = this.edgeList.get(i).getFirstNode().getId();
				int id_two = this.edgeList.get(i).getSecondNode().getId();
				String datas = id_one + "\t" + id_two;
				
				bw_edge.write(datas);
				bw_edge.newLine();
			}
			bw_edge.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args){
		File nodeSrc = new File("src//source//brightkite.txt");
		File edgeSrc = new File("src//source//Brightkite_edges.txt");
		File nodeDest = new File("src//source//brightkite_nodes_available.txt");
		File edgeDest = new File("src//source//brightkite_edges_available.txt");
		
		getAvailableDatas g = new getAvailableDatas();
		g.getData(nodeSrc, edgeSrc, nodeDest, edgeDest);
	}
}

解释
      在此步骤中输入的点集文件为brightkite.txt,这是我们在 舍去无用签到信息 步骤中获得的点集文件,不是原数据文件。输入的边集文件为原数据文件。
结果
      brightkite_nodes_available.txt文件为处理后的点集文件,有50686条数据,说明有50686个点。数据具体格式如下:

0	39.747652	-104.99251	119
1	37.579963	-122.343908	39
2	39.747652	-104.99251	81
3	38.94511	-77.451706	229
4	37.824562	-122.368844	26
5	37.797691	-122.430553	47
6	42.057777	-87.749627	68
7	37.591126	-122.383322	217
8	39.74832	-105.000522	3
9	37.579001	-122.344753	23
10	49.613146	6.12731	35
11	37.580304	-122.343679	71

      brightkite_edges_available.txt文件为处理后的边集文件,有388180条数据,说明有388180条边。数据具体格式如下:

0	118
0	119
0	120
0	121
0	122
1	0
1	3
1	4
1	5
1	7
1	9

处理结果

      经过 舍去无用签到信息固定格式存储数据 两个步骤,我们已得到用于构建空间网络图的数据。所需的点集和边集就是固定格式存储数据中获得的点集和边集。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 20
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值