数学建模---华为杯---对大量文件进行数据清洗

1、前言

  本科的时候还没参加过数模比赛,还是等到读研的时候才参加的,研一的时候本着锻炼的目的参加了一次中青杯,一次数维杯,一次数模省赛,由于省赛拿了个二等,因此有机会在研二有了第一次参加数模国赛的经历。不得不说,ABCDEF题都挺难的,第一天上午初略的浏览了一遍题目,发现E题的超宽带定位问题挺适合我们(通信专业),不过做到后面发现挺难的。由于记错截止时间了(华为杯的时间段很多,一不注意就容易搞错),因此最后一天晚上和两个队友熬了个通宵(话说,哪怕没记错时间,估计也要通宵)。这次比赛学到了很多,也是第一次对大数据进行清洗,人工手动清洗不知道要搞到猴年马月,有机会要学学神经网络,对预测分类太有用了。不过下次估计是不会参加国赛了,省赛还是可以混一混。

2、题目描述

 一共有624个txt文件,其中又分为324个正常txt文件和324个异常txt文件,以1.正常.txt为例,我们主要关注的是 时间戳四个锚点编号以及各个锚点到靶点的距离。从图1可以看到,在左侧给出的还未清洗过的1.正常.txt文件中,第一行的时间戳只有一个,缺失了三个,并且第一行的数据还是乱码,这种数据明显要剔除掉。从第二行到第五行,这四行就是正常的数据,四个锚点A0、A1、A2、A3处于同一时间戳。清洗过的数据如右侧所示,一行包含四个锚点,并且每个的时间戳都一样。图1                图1
但是我们会发现,这样看起来还是不够直观,因此我们还进行了二次处理,如图2所示,这样看起来是不是清楚多了呢!
在这里插入图片描述                图2

3、具体分析

  对数据进行清洗,首先要知道数据存在哪些异常,之后再对症下药,采用合适的筛选机制,整理出我们想要的数据。通过观察附件1给出的648个数据文件中的其中几个,我们发现在正常.txt和异常.txt文件中存在着如下几个数据异常的地方:
  (1)每个文件的第一行,皆存在着类似图3所示的无效数据,这行包含特殊字符的文字并不能为我们提供有效的信息,因此要将其剔除。
在这里插入图片描述
                图3

  (2)以附件1中的1.正常.txt文件为例,从图4中可以发现红色部分圈出的A0、A1、A2、A3处于同一时间戳,而蓝色部分圈出的数据由于时间戳的最后一位数不一样,可以判定其来自不同的时间戳,这样的一组A0、A1、A2、A3应该被筛选掉。
在这里插入图片描述
                图4

  (3)在正常数据的txt文件中,由于A0、A1、A2、A3到靶点Tag的距离不受干扰,因此每个时间戳所检测出的距离应该类似,但是在有些文件中个别锚点到靶点Tag的距离出现了异常。如图5所示,可以看到右侧的1.正常.txt文件中A3锚点到靶点Tag的检测距离是差不多的,但是左侧的109.正常.txt中存在着一组数据,相比于其他时间戳的A3,这组A3所采集到的数值70明显出现了异常,因此这一组数据也是必须要筛选掉的。
在这里插入图片描述
                图5

4、解决方法

  由于附件1中有正常数据和异常数据两个文件夹,每个文件夹中有324个txt文档,我们设计的程序每次运行的时候可以对其中一个文件夹的324个txt文档进行遍历,读取一次txt文档,然后在另外一个路径中创建一个新的清洗过后的txt文件。当324个txt文档全部遍历完之后,我们会在另外一个路径中得到清洗过后的324个txt文档。对应在每个txt文档中具体清洗方式如下:
   初始化: 我们定义了两个时间戳数组记为F0[4]、F1[4],用于存放时间戳的最后两位数;定义了四个中间变量数组记为L0[100]、L1[100]、L2[100]、L3[100],用于存放A0、A1、A2、A3四个锚点到靶点Tag的距离。定义了一个最终输出数组,记为L[100],用于存放清洗后的相同时间戳下A0、A1、A2、A3四个锚点到靶点Tag的距离。
  针对具体分析中的(1),我们给出了限制一:通过判断txt文件的每一行是否出现过D以及?等异常字符,如果出现了,那么这一行就不允许被采用。
  针对具体分析中的(2),我们给出了限制二:从第一行开始,我们通过数组保存当前行的时间戳的最后两位数分别保存到F0[0]、F1[0],以及距离L0[100]。然后跳转到下一行,比较下一行的时间戳的最后两位F0[1]、F1[1]和当前行是否一致,如果一致,那么继续保存当前行时间戳的最后两位和距离L1[100],如果比较到四行时间戳最后两位F0[4]、F1[4]和F0[3]、F1[3]都一致且满足限制一和限制三的情况下,这时才能将四个距离矩阵L0[100]、L1[100]、L2[100]、L3[100]中存放着的距离信息写入到最终输出数组L[100]中,再写入新的txt文件中。如果在比较四行数据的过程中出现了下一行的时间戳后两位和当前行的时间戳后两位不一致的情况,那么下一行之前的时间戳需要被抛弃,下一行时间戳的后两位作为新的校准,分别保存到F0[0]、F1[0],同时清空F0[1]、F1[1]、F0[2]、F1[2] 、F0[3]、F1[3]中的数据,然后继续按上面的方式与接下来的三行进行比较。
  针对具体分析中的(3),我们给出了限制三,如果四个锚点的时间戳都一样,但是其中一个锚点到靶点的距离和前几组的锚点到靶点的距离存在着较大的误差,那么我们将这组数据舍弃。

5、代码(C语言)

5.1、核心思想

  还是利用了C语言中的文件读写操作,对于不同的题目,只需把读取路径以及一些细节的东西改一改,还是可以直接拿来用的。

#include <stdio.h>   
#include<stdlib.h>
#include<string.h>
#define MAX_LINE 100                   //每行最大字节数  
int main()
{
    
    
	FILE *fp;
	char strLine[MAX_LINE];
	char sentence[MAX_LINE];                          //读取缓冲区  
	FILE * pFile;                 //写入文件
	char filename[40];   //要读取的文件
	char endname[40];   //存放读取后的文件
	char temp1[100]="";
	char lianjie1[100] = "";
	char lianjie2[100] = "";
	char lianjie3[100] = "";
	char lianjie4[100] = "";
	char lianjie[100] = "";

	int h = 0;     //用于记录4个时间戳是否一致
	int k = 0;    //用于记录4个时间戳是否一致
	int m = 0;    //用于保存4行数据
	char flag_0[4] = {
    
     0, 0, 0, 0 };  //用于保存时间戳倒数第二位数
	char flag[4] = {
    
     0, 0, 0, 0 };

	for (int i = 1; i < 325; i++)
	{
    
    

		sprintf(endname, "F:\\国赛数模\\matlab计算正常数据\\%d.正常.txt", i);
		pFile = fopen(endname, "a");    //获取要保存的文件指针
		sprintf(filename, "F:\\国赛数模\\正常数据\\%d.正常.txt", i);
		if ((fp = fopen(filename, "r")) == NULL)      //判断文件是否存在及可读  
		{
    
    
			printf("Open Falied!");
			return -1;
		}
		pFile = fopen(endname, "a");    //获取要保存的文件指针
		while (!feof(fp))                                   //循环读取每一行,直到文件尾  
		{
    
    

			fgets(strLine, MAX_LINE, fp);                     //将fp所指向的文件一行内容读到strLine缓冲区  
			int x = 0;    //用于记录要保留的最后一位数

			for (int j = 0; j <100; j++)                    //获取每行第1到第20个字符 
			{
    
    
				sentence[j] = strLine[j];
				if (':' == strLine[j])   //如果x为:   计数
				{
    
    
					x = x + 1;
				}
				if (9 == j)    //如果j=8,记录当前时间戳的最后一位数
				{
    
    
					flag_0[h] = strLine[j];    //将时间戳的最后一位,放入flag中
					h = h + 1;
				}
				if (10 == j)    //如果j=8,记录当前时间戳的最后一位数
				{
    
    
					flag[k] = strLine[j];    //将时间戳的最后一位,放入flag中
					k = k + 1;
				}
				if (x == 7)  //这一行就读取到这里过
				{
    
    
					sentence[j + 1] = '\n';
					break;
				}
			}

			if (m == 3)
			{
    
    
				if ((flag[2] == flag[3]) && (flag_0[2] == flag_0[3]) && (sentence[21]!=':'))  //如果前四行相等
				{
    
    
					char temp[100] = "";
					//填写lianjie4的值
					for (int o = 0; o<23; o++)
					{
    
    
						if (sentence[o] == '?')
						{
    
    
							break;
						}
						lianjie4[o] = sentence[o];
						if (o == 22 && sentence[22] == ':')
						{
    
    
							lianjie4[o] = ' ';
						}
					}
					//写入四行语句
					//pFile = fopen(endname, "a");
					for (int o = 0; o<23; o++)
					{
    
    
						if (lianjie1[o] == '?')
						{
    
    
							break;
						}
						temp1[o] = lianjie1[o];
					}
					for (int o = 0; o<23; o++)
					{
    
    
						if (temp1[o] == 'R')
						{
    
    
							lianjie[o] = temp1[o+7];
							lianjie[o+1] = temp1[o+8];
							lianjie[o+2] = temp1[o+9];
							lianjie[o+3] = temp1[o+10];
							lianjie[o + 4] = temp1[o + 11];
							break;
						}
						else
						{
    
    
							lianjie[o] = temp1[o];
						}
					}
					fputs(lianjie, pFile);//输入A0的数据
					lianjie[0] = '\0';


					for (int o = 0; o<5; o++)
					{
    
    
						if (lianjie2[o] == '?')
						{
    
    
							break;
						}
						lianjie[o] = lianjie2[o+18];
						temp[o] = lianjie[o];
					}
				
					fputs(temp, pFile);//输入A1的数据
					lianjie[0] = '\0';

					for (int o = 0; o<5; o++)
					{
    
    
						if (lianjie3[o] == '?')
						{
    
    
							break;
						}
						lianjie[o] = lianjie3[o+18];
						temp[o] = lianjie[o];
					}
					
					fputs(temp, pFile);//输入A2的数据
					lianjie[0] = '\0';

					for (int o = 0; o<5; o++)
					{
    
    
						if (lianjie4[o] == '?')
						{
    
    
							break;
						}
						lianjie[o] = lianjie4[o+18];
						temp[o] = lianjie[o];
					}
					fputs(temp, pFile);//输入A3的数据
					lianjie[0] = '\0';
					lianjie[0] = '\n';
					fprintf(pFile, "\n");

					//输出完之后还需要重新开始
					lianjie1[0] = '\0';
					lianjie2[0] = '\0';
					lianjie3[0] = '\0';
					lianjie4[0] = '\0';
					lianjie[0] = '\0';
					for (unsigned int n = 0; n < 100; n++)
					{
    
    
						sentence[n] = '\0';
					}

					flag[0] = {
    
     0 };
					flag[1] = {
    
     0 };
					flag[2] = {
    
     0 };
					flag[3] = {
    
     0 };
					flag_0[0] = {
    
     0 };
					flag_0[1] = {
    
     0 };
					flag_0[2] = {
    
     0 };
					flag_0[3] = {
    
     0 };
					h = 0;
					k = 0;
					m = -1;
					//continue;
				}
				else  //如果第四行和前三行不相等,那么第四行的值变为第一行,后三行重新开始
				{
    
    
					for (int o = 0; sentence[o] != '\n'; o++)
					{
    
    
						if (sentence[o] == '?')
						{
    
    
							break;
						}
						lianjie1[o] = sentence[o];
						if (o == 22 && sentence[22] == ':')
						{
    
    
							lianjie1[o] = ' ';
						}
					}
					lianjie2[0] = '\0';
					lianjie3[0] = '\0';
					lianjie[0] = '\0';

					flag[0] = flag[3];
					flag[1] = {
    
     0 };
					flag[2] = {
    
     0 };
					flag[3] = {
    
     0 };
					flag_0[0] = flag_0[3];
					flag_0[1] = {
    
     0 };
					flag_0[2] = {
    
     0 };
					flag_0[3] = {
    
     0 };
					h = 1;
					k = 1;
					m = 1;
				}
			}
			if (m == 2)
			{
    
    
				if ((flag[1] == flag[2]) && (flag_0[1] == flag_0[2]) && (sentence[21] != ':'))  //如果第三行和前两行相等
				{
    
    
					for (int o = 0; sentence[o] != '\n'; o++)
					{
    
    
						if (sentence[o] == '?')
						{
    
    
							break;
						}
						lianjie3[o] = sentence[o];
						if (o == 22 && sentence[22] == ':')
						{
    
    
							lianjie3[o] = ' ';
						}
					}

					m++;
				}
				else  //如果前三行不相等,那么这一行的值给第一行,第二第三行清零
				{
    
    
					for (int o = 0; sentence[o] != '\n'; o++)
					{
    
    
						if (sentence[o] == '?')
						{
    
    
							break;
						}
						lianjie1[o] = sentence[o];
						if (o == 22 && sentence[22] == ':')
						{
    
    
							lianjie1[o] = ' ';
						}
					}
					lianjie2[0] = '\0';
					lianjie[0] = '\0';


					flag[0] = flag[2];
					flag[1] = '\0';
					flag[2] = '\0';
					flag_0[0] = flag_0[2];
					flag_0[1] = {
    
     0 };
					flag_0[2] = {
    
     0 };
					h = 1;
					k = 1;
					m = 1;
				}
			}

			if (m == 1)
			{
    
    
				if ((flag[0] == flag[1]) && (flag_0[0] == flag_0[1]) && (sentence[21] != ':'))  //如果前两行相等
				{
    
    
					for (int o = 0; sentence[o] != '\n'; o++)
					{
    
    
						if (sentence[o] == '?')
						{
    
    
							break;
						}
						lianjie2[o] = sentence[o];
						
						if (o == 22 && sentence[22] == ':')
						{
    
    
							lianjie2[o] = ' ';
						}
					}
					m++;
				}
				else  //如果前两行不相等,那么上一行应该抛弃,用这一行取代上一行,这一行的数据清零
				{
    
    

					for (int o = 0; sentence[o] != '\n'; o++)
					{
    
    
						if (sentence[o] == '?')
						{
    
    
							break;
						}
						lianjie1[o] = sentence[o];
						if (o == 22 && sentence[22] == ':')
						{
    
    
							lianjie1[o] = ' ';
						}
					}
					for (unsigned int n = 0; n < 100; n++)
					{
    
    
						sentence[n] = '\0';
					}
					lianjie[0] = '\0';
					if (flag[1] != '\0')   //等于空说明是从上面跳转过来的
					{
    
    
						flag[0] = flag[1];
						flag[1] = {
    
     0 };
						flag_0[0] = flag_0[1];
						flag_0[1] = {
    
     0 };
					}
					h = 1;
					k = 1;
					m = 1;
				}
			}

			if (m == 0)
			{
    
    
				for (int o = 0; sentence[o] != '\n'; o++)
				{
    
    
					if (sentence[o] == '?')
					{
    
    
						break;
					}
					if (sentence[o] == 'D')
					{
    
    
						break;
					}
					lianjie1[o] = sentence[o];
					if (o == 22 && sentence[22] == ':')
					{
    
    
						lianjie1[o] = ' ';
					}
					if ((o == 21) && (lianjie1[o] == ':'))
					{
    
    
						lianjie1[0] = '\0';
						lianjie2[0] = '\0';
						lianjie3[0] = '\0';
						lianjie4[0] = '\0';
						lianjie[0] = '\0';
						for (unsigned int n = 0; n < 100; n++)
						{
    
    
							sentence[n] = '\0';
						}
						flag[0] = {
    
     0 };
						flag[1] = {
    
     0 };
						flag[2] = {
    
     0 };
						flag[3] = {
    
     0 };
						flag_0[0] = {
    
     0 };
						flag_0[1] = {
    
     0 };
						flag_0[2] = {
    
     0 };
						flag_0[3] = {
    
     0 };
						h = 0;
						k = 0;
						m = -1;
						break;
					}
				}
				m++;
			}
			if (m == -1)
			{
    
    
				m = m + 1;
			}

		}
		fclose(fp);                                         //关闭文件  
		fclose(pFile);
		//重置,防止后续文件收到前面文件的影响
		h = 0;
		k = 0;    //用于记录4个时间戳是否一致
		m = 0;    //用于保存4行数据
		flag[0] = {
    
     0 };
		flag[1] = {
    
     0 };
		flag[2] = {
    
     0 };
		flag[3] = {
    
     0 };
		for (unsigned int n = 0; n < 100; n++)
		{
    
    
			sentence[n] = '\0';
		}
		lianjie1[0] = '\0';
		lianjie2[0] = '\0';
		lianjie3[0] = '\0';
		lianjie4[0] = '\0';
		lianjie[0] = '\0';

	}
	system("pause");
	return 0;
}

6、最后

  码字不易,如果觉得本篇文章对您有所帮助的话,感谢您能点赞收藏哦!

猜你喜欢

转载自blog.csdn.net/qq_40077565/article/details/120902633