- 组员信息:陈泽彬(有组但单干)
- 组员分工:陈泽彬
- 指导老师:彭伟龙
广州大学某班有同学100人,现要从两个数据源汇总学生数据。第一个数据源在Excel中,第二个数据源在txt文件中,两个数据源课程存在缺失、冗余和不一致性,请用C/C++/Java/Python程序实现对两个数据源的一致性合并以及每个学生样本的数值量化。
- Excel表:ID (int), 姓名(string), 家乡(string:限定为Beijing / Guangzhou / Shenzhen / Shanghai), 性别(string:boy/girl)、身高(float:单位是cm))、课程1成绩(float)、课程2成绩(float)、...、课程10成绩(float)、体能测试成绩(string:bad/general/good/excellent);其中课程1-课程5为百分制,课程6-课程10为十分制。
- txt文件:ID(string:6位学号),性别(string:male/female)、身高(string:单位是m))、课程1成绩(string)、课程2成绩(string)、...、课程10成绩(string)、体能测试成绩(string:差/一般/良好/优秀);其中课程1-课程5为百分制,课程6-课程10为十分制。
一.数据源1.xlsx
| ID | Name | City | Gender | Height | C1 | ... | C10 | Constitution |
|---|---|---|---|---|---|---|---|---|
| 1 | Marks | Shenzhen | boy | 166 | 77 | general | ||
| 2 | Wayne | Shenzhen | girl | 159 | 77 | good | ||
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
一.数据源2-逗号间隔.txt
ID,Name,City,Gender,Height,C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,Constitution 202001,Marks,Shenzhen,male,1.66,77,100,84,71,91,6,7,6,8,,general
两个数据源合并后读入内存,并统计:
- 学生中家乡在Beijing的所有课程的平均成绩。
- 学生中家乡在广州,课程1在80分以上,且课程9在9分以上的男同学的数量。(备注:该处做了修正,课程10数据为空,更改为课程9)
- 比较广州和上海两地女生的平均体能测试成绩,哪个地区的更强些?
- 学习成绩和体能测试成绩,两者的相关性是多少?(九门课的成绩分别与体能成绩计算相关性)
参考数据结构:
Student{
int id;
string id;
vector data;
}
可能用到的公式:
| 均值公式 | ![]() |
|---|---|
| 协方差公式 | ![]() |
| z-score规范化 | ![]() |
| 数组A和数组B的相关性 | ![]() 这里A=[a1, a2,...ak,..., an],B=[b1, b2,...bk,..., bn] mean(A)代表A中元素的平均值std是标准差,即对协方差的开平方. 点乘的定义: ![]() |
注意:计算部分不能调用库函数;画图/可视化显示可以用可视化API或工具实现。
-
Windows10
-
Anaconda Python3.6(IDE为pycharm)
-
「main.py」是源代码
-
「一.数据源1.xlsx」是数据源1
-
「一.数据源2-逗号间隔.txt」是数据源2
-
「运行结果截图.jpg」是运行结果
- 输出合并后数据源
- 输出学生中家乡在Beijing的所有课程的平均成绩
- 输出学生中家乡在广州,课程1在80分以上,且课程9在9分以上的男同学的数量
- 输出比较广州和上海两地女生的平均体能测试成绩并判断哪个地区的更强些
- 输出学习成绩和体能测试成绩两者的相关性
运算结果截图.jpg:
def AVG(df):
C_avg = sum(df)/len(df)
C_avg = float('%0.1f' %C_avg) # 设置精度
return(C_avg)输入类型可为numpy.ndarray,结果输出float类型的一个平均数
结果不希望要那么多小数点于是设置了精度,保留一位小数
def STD(df):
sum = 0
for j in df:
sum = sum + pow(j-AVG(df),2)
return pow(sum/(len(df)-1),0.5)输入类型可为numpy.ndarray,结果输出float类型的一个标准差,其中调用了AVG(df)平均数函数
def CORRELATION(df1,df2):
STD_df1df2 = sum([(i - AVG(df1)) * (j - AVG(df2)) for i, j in zip(df1, df2)])/(len(df1)-1)
return STD_df1df2/(STD(df1)*STD(df2))输入类型可为numpy.ndarray,结果输出float类型的一个相关系数,其中调用了AVG(df)平均数函数、STD(df)标准差函数
- pandas
| 调用的函数 | 函数说明 |
|---|---|
| panda.set_option | 用于设置dataframe的输出显示 |
| pandas.read_excel | 将Excel文件读入pandas数据框 |
| pandas.DataFrame.drop_duplicates | 返回删除了重复行的DataFrame |
| pandas.DataFrame.to_numpy | 将DataFrame转换为NumPy数组 |
| pandas.DataFrame.replace | 将DataFrame的值动态替换为其他值 |
| pandas.Series.map | 用于将Series中的每个值替换为可以从函数、字典或Series获取的数据 |
| pandas.read_csv | 将逗号分隔值(csv)文件读取到DataFrame中 |
| pandas.DataFrame | 做一个复制此对象的索引和数据 |
| pandas.concat | 将pandas对象与其他轴上的可选集合逻辑连接起来 |
| pandas.DataFrame.merge | 使用数据库的样式联接合并DataFrame或命名的Series对象(取交集) |
| pandas.DataFrame.combine_first | 通过将一个DataFrame中的空值与其他DataFrame中的非空值一起填充来组合两个DataFrame对象。所得DataFrame的行索引和列索引将是两者的并集 |
| pandas.DataFrame.sort_values | 沿任一轴的值排序 |
| pandas.DataFrame.fillna | 使用指定的方法填充NA / NaN值 |
前言:非常惭愧做本次实验基本是从0开始,除了理解实验要求不是难题,其余一切代码实现几乎都是难题,无论是简单的导入还是复杂的清洗、合并、查询,都花费了大量的时间和精力用于各种百度上,也从中收集了一些个人认为很不错的文章,同时也在源代码中做好了标记,下面会根据标记处所遇到的问题以及解决办法罗列在下方,今后一定洗心革面好好学习天天向上
本次实验所要求的内容并不复杂,难就难在代码实现上,由于没有什么基础可言,90%的时间都拿去搜索各种文档恶补相关知识去了,可谓是受益匪浅,了解到了Python中的Numpy库以及Pandas库,也在不断捣鼓的过程中摸索出了一些相通的方法,第一次将项目推到GitHub上,也开始意识到要对自己写出的代码负责,这份沉甸甸的责任感使我不断优化自身代码,虽然学习Git语法也花费了我不少时间,整个实验花费了远多于以往实验的精力和时间,但结果总归是好的,相信接下来的实验会更加有的放矢更加得心应手,期间非常感谢彭老师的悉心指导
- 组员信息:陈泽彬(有组但单干)
- 组员分工:陈泽彬
- 指导老师:彭伟龙
基于实验一中清洗后的数据练习统计和视化操作,100个同学(样本),每个同学有11门课程的成绩(11维的向量);那么构成了一个100x11的数据矩阵。以你擅长的语言C/C++/Java/Python/Matlab,编程计算:
- 请以课程1成绩为x轴,体能成绩为y轴,画出散点图。
- 以5分为间隔,画出课程1的成绩直方图。
- 对每门成绩进行z-score归一化,得到归一化的数据矩阵。
- 计算出100x100的相关矩阵,并可视化出混淆矩阵。(为避免歧义,这里“协相关矩阵”进一步细化更正为100x100的相关矩阵,100为学生样本数目,视实际情况而定)
- 根据相关矩阵,找到距离每个样本最近的三个样本,得到100x3的矩阵(每一行为对应三个样本的ID)输出到txt文件中,以\t,\n间隔。
计算部分不能调用库函数;画图/可视化显示可可视化工具或API实现。
- Windows10
- Anaconda Python3.6(IDE为pycharm)
-
「main.py」是源代码
-
「Merge Data.csv」是实验一最后数据处理过后的学生成绩单
-
「Nearest.txt」是第五题要求输出的txt文件
-
「直方图.jpg」
-
「散点图.jpg」
-
「可视化混淆矩阵.jpg」
-
「矩阵.jpg」是第三题、第四题、第五题运行后的矩阵结果
- 归一化数据矩阵
- 相关矩阵
- 100*3矩阵
直方图.jpg:
散点图.jpg:
可视化混淆矩阵.jpg:
矩阵.jpg:
def AVG(df):
C_avg = sum(df)/len(df)
C_avg = float('%0.1f' %C_avg) # 设置精度
return(C_avg)输入类型可为numpy.ndarray,结果输出float类型的一个平均数
结果不希望要那么多小数点于是设置了精度,保留一位小数
def STD(df):
sum = 0
for j in df:
sum = sum + pow(j-AVG(df),2)
return pow(sum/(len(df)-1),0.5)输入类型可为numpy.ndarray,结果输出float类型的一个标准差,其中调用了AVG(df)平均数函数
def z_score(df):
score=[]
for i in df:
score.append((i-AVG(df))/STD(df))
return score输入类型可为numpy.ndarray,结果输出numpy.ndarray类型的数组,其中调用了AVG(df)平均数函数、STD(df)标准差函数
def CORRELATION(df1,df2):
STD_df1df2 = sum([(i - AVG(df1)) * (j - AVG(df2)) for i, j in zip(df1, df2)])/(len(df1)-1)
return STD_df1df2/(STD(df1)*STD(df2))输入类型可为numpy.ndarray,结果输出float类型的一个相关系数,其中调用了AVG(df)平均数函数、STD(df)标准差函数
def correlation_matrix(df):
result = np.zeros((len(df),len(df)))
for i in range(len(df)):
for j in range(len(df)):
result[i][j] = CORRELATION(df[i],df[j])
return result输入类型可为numpy.ndarray,结果输出numpy.ndarray类型
def Nearest(df):
value = [0,0,0]
result_value = np.zeros((len(df),3))
result_ID = np.zeros((len(df),3))
for i in range(len(df)):
temp = sorted(df[i])
value[0],value[1],value[2] = temp[-2],temp[-3],temp[-4]
result_value[i][0],result_value[i][1],result_value[i][2] = value[0],value[1],value[2]
result_ID[i][0],result_ID[i][1],result_ID[i][2] = df[i].tolist().index(result_value[i][0]),df[i].tolist().index(result_value[i][1]),df[i].tolist().index(result_value[i][2])
return result_ID输入类型可为numpy.ndarray,结果输出numpy.ndarray类型
- pandas
- matplotlib
- seaborn
- numpy
| 调用的函数 | 函数说明 |
|---|---|
| pandas.read_csv(filename) | 从CSV文件导入数据 |
| matplotlib.rcParams | 返回是否在每个绘图命令后重绘。 |
| matplotlib.pyplot.title | 为坐标轴设置标题 |
| matplotlib.pyplot.xlabel | 设置 x 轴的标签 |
| matplotlib.pyplot.ylabel | 设置 y 轴的标签 |
| matplotlib.pyplot.scatter | 用不同的标记大小和/或颜色绘制 y 与 x 的散点图 |
| matplotlib.pyplot.yticks | 获取或设置 y 轴的当前刻度位置和标签 |
| matplotlib.pyplot.show | 显示所有打开的图像 |
| matplotlib.pyplot.hist | 画一个直方图 |
| pandas.DataFrame | 创建DataFrame对象 |
| pandas.DataFrame.values | 返回 DataFrame 的 Numpy 表示形式 |
| numpy.zeros | 返回给定形狱和类型的新数组,并用零填充 |
| seaborn.heatmap | 将矩形数据绘制为颜色编码矩阵。 |
| pandas.Series.str.len | 计算Series/Index 中每个元素的长度。 |
| numpy.savetxt | 将数组保存到文本文件中 |
本次实验主要是进行可视化以及进行数据统计,可视化用了Python库matplotlib,里面内置了一系列所需要的图,矩阵方面主要思想是先建立Dataframe类型的格式化数据,再利用pandas.Dataframe.values函数很方便地转为矩阵类型(ndarray),混淆矩阵用热力图的方式来表示,保存txt文件利用numpy.savetxt函数,难点主要在于写计算部分的函数。
- 组员信息:陈泽彬(有组但单干)
- 组员分工:陈泽彬
- 指导老师:彭伟龙
在实现可视化中「类半径」和「标签显示」两个内容借鉴了软件182班吴富乐同学的代码,吴富乐同学GitHub地址为https://github.com/Chimaeras/Data_Mining_ex
用C++实现k-means聚类算法,
- 对实验二中的z-score归一化的成绩数据进行测试,观察聚类为2类,3类,4类,5类的结果,观察得出什么结论?
- 由老师给出测试数据,进行测试,并画出可视化出散点图,类中心,类半径,并分析聚为几类合适。
样例数据(x,y)数据对:
| 3.45 | 7.08 |
|---|---|
| 1.76 | 7.24 |
| 4.29 | 9.55 |
| 3.35 | 6.65 |
| 3.17 | 6.41 |
| 3.68 | 5.99 |
| 2.11 | 4.08 |
| 2.58 | 7.10 |
| 3.45 | 7.88 |
| 6.17 | 5.40 |
| 4.20 | 6.46 |
| 5.87 | 3.87 |
| 5.47 | 2.21 |
| 5.97 | 3.62 |
| 6.24 | 3.06 |
| 6.89 | 2.41 |
| 5.38 | 2.32 |
| 5.13 | 2.73 |
| 7.26 | 4.19 |
| 6.32 | 3.62 |
找到聚类中心后,判断(2,6)是属于哪一类?
除文件读取外,不能使用C++基础库以外的API和库函数。
- Windows10
- Anaconda Python3.6(IDE为pycharm)
- Question1文件夹:题目一的CPP代码
- 归一化数据矩阵.txt:实验二导出的归一化数据矩阵
- Q1结果图文件夹:Question1结果图片截图
- Q1聚类2.jpg
- Q1聚类3.jpg
- Q1聚类4.jpg
- Q1聚类5.jpg
-
Question2文件夹:题目二的CPP代码
-
train.txt:训练集,即上述样例数据对
-
test.txt:测试集,即(2,6)
-
result2、3、4、5.csv:Qusetion2中CPP代码导出的分成不同类的数据,用于可视化程序.py,数据样式如下表
X Y Center_X Center_Y Class 数据的x 数据的y 数据所在类的质心的x 数据所在类的质心的y 数据所在类 -
可视化程序.py:用于数据可视化
-
Q2结果图文件夹:Question1结果图片截图
- Q2聚类2.png
- Q2聚类2可视化.png
- Q2聚类3.png
- Q2聚类3可视化.png
- Q2聚类4.png
- Q2聚类4可视化.png
- Q2聚类5.png
- Q2聚类5可视化.png
Q1聚类2.jpg:
Q1聚类3.jpg:
Q1聚类4.jpg:
Q1聚类5.jpg:
Q2聚类2.png:
Q2聚类2可视化.png:
Q2聚类3.png:
Q2聚类3可视化.png
Q2聚类4.png
Q2聚类4可视化.png
Q2聚类5.png
Q2聚类5可视化.png
void CTestKMeans::LoadFeatureFile(const string strFileName, std::vector<Tuple> &lDataList)
{
double C1, C2, C3,C4,C5,C6,C7,C8,C9,C10, Constitution;
ifstream iFile;
iFile.open(strFileName.c_str(), ios::in);
if (!iFile.is_open()) //文件无法正确打开
cout << "open file failure!" << endl;
if (iFile.peek() == EOF) //文件若为空
{
cout << "file is empty!" << endl;
return;
}
while (!iFile.eof()) // 若未到文件结束一直循环
{
iFile >> C1 >> C2 >> C3>>C4>>C5>>C6>>C7>>C8>>C9>>C10>> Constitution;
struct Tuple sData;
sData.C1 = C1;
sData.C2 = C2;
sData.C3 = C3;
sData.C4 = C4;
sData.C5 = C5;
sData.C6 = C6;
sData.C7 = C7;
sData.C2 = C2;
sData.C8 = C8;
sData.C9 = C9;
sData.C10 = C10;
sData.Constitution = Constitution;
lDataList.push_back(sData);
iFile.get();//获取之后一个字符(后面这几行代码理解为会判断到最后是否为空即可)
//peek方法可以返回下一个却不移动指针
if (iFile.peek() == '\n')
{
break;
}
}
iFile.close(); //关闭文件
}输入参数为文件名(即归一化数据矩阵.txt)和Tuple类型的数据容器,最终结果为将txt数据全部导入数据容器中,Tuple为结构体,结构如下
//定义结构体,包含11科成绩
struct Tuple {
double C1;
double C2;
double C3;
double C4;
double C5;
double C6;
double C7;
double C8;
double C9;
double C10;
double Constitution;
};float CTestKMeans::GetDistXY(Tuple t1, Tuple t2)
{
return sqrt((t1.C1 - t2.C1) * (t1.C1 - t2.C1) + (t1.C2 - t2.C2) * (t1.C2 - t2.C2) + (t1.C3 - t2.C3) * (t1.C3 - t2.C3) + (t1.C4 - t2.C4) * (t1.C4 - t2.C4) + (t1.C5 - t2.C5) * (t1.C5 - t2.C5) + (t1.C6 - t2.C6) * (t1.C6 - t2.C6) + (t1.C7 - t2.C7) * (t1.C7 - t2.C7) + (t1.C8 - t2.C8) * (t1.C8 - t2.C8) + (t1.C9 - t2.C9) * (t1.C9 - t2.C9) + (t1.C10 - t2.C10) * (t1.C10 - t2.C10) + (t1.Constitution - t2.Constitution) * (t1.Constitution - t2.Constitution));
}输入参数为两个Tuple类型的变量,返回两个变量之间的欧氏距离
int CTestKMeans::ClusterOfTuple(Tuple tCentroid[], Tuple vDataList)
{
float fDistance = GetDistXY(tCentroid[0], vDataList);//当前元组与第一个质心的欧式距离
float fTmp;
int nLabel = 0;//标示属于哪一个簇
for (int i = 1; i < FEATURE_DIM; i++)
{
fTmp = GetDistXY(tCentroid[i], vDataList);//当前元组与第i个质心的欧氏距离
if (fTmp < fDistance)//取最近的欧氏距离
{
fDistance = fTmp;
nLabel = i;
}
}
return nLabel;
}输入参数为各类质心位置以及当前项,结果返回一个int型整数,为当前项所属类
float CTestKMeans::GetVar(vector<Tuple> vCluster[], Tuple tCentroid[]) {
float fVar = 0;
for (int i = 0; i < FEATURE_DIM; i++)
{
vector<Tuple> vTuple = vCluster[i];
for (int j = 0; j < vTuple.size(); j++)
{
fVar += GetDistXY(vTuple[j], tCentroid[i]);
}
}
return fVar;
}输入参数为每类所有项以及质心位置,返回当前分类情况下的平方误差
Tuple CTestKMeans::GetMeans(vector<Tuple> vCluster) {
int nNum = vCluster.size();
double dMeansC1 = 0, dMeansC2 = 0, dMeansC3 = 0, dMeansC4 = 0, dMeansC5 = 0, dMeansC6 = 0, dMeansC7 = 0, dMeansC8 = 0, dMeansC9 = 0, dMeansC10 = 0, dMeansConstitution = 0;
Tuple tTmp;
for (int i = 0; i < nNum; i++)
{
dMeansC1 += vCluster[i].C1;
dMeansC2 += vCluster[i].C2;
dMeansC3 += vCluster[i].C3;
dMeansC4 += vCluster[i].C4;
dMeansC5 += vCluster[i].C5;
dMeansC6 += vCluster[i].C6;
dMeansC7 += vCluster[i].C7;
dMeansC8 += vCluster[i].C8;
dMeansC9 += vCluster[i].C9;
dMeansC10 += vCluster[i].C10;
dMeansConstitution += vCluster[i].Constitution;
}
tTmp.C1 = dMeansC1 / nNum;
tTmp.C2 = dMeansC2 / nNum;
tTmp.C3 = dMeansC3 / nNum;
tTmp.C4 = dMeansC4 / nNum;
tTmp.C5 = dMeansC5 / nNum;
tTmp.C6 = dMeansC6 / nNum;
tTmp.C7 = dMeansC7 / nNum;
tTmp.C8 = dMeansC8 / nNum;
tTmp.C9 = dMeansC9 / nNum;
tTmp.C10 = dMeansC10 / nNum;
tTmp.Constitution = dMeansConstitution / nNum;
return tTmp;
}输入参数为某一类所有项,返回这一类的质心
void CTestKMeans::TrainData(std::vector<Tuple> &vDataList, Tuple tCentroid[FEATURE_DIM])
{ //vDataList:所有数据项 tCentroid[FEATURE_DIM]:有FEATURE_DIM项数据,为每一类的质心位置
vector<Tuple> vClusters[FEATURE_DIM]; //可以理解为是个二维链表,存储某一类中的所有项
//默认一开始将前FEATURE_DIM个元组的值作为FEATURE_DIM个簇的质心
for (int i = 0; i < FEATURE_DIM; i++)
{
tCentroid[i].C1 = vDataList[i].C1;
tCentroid[i].C2 = vDataList[i].C2;
tCentroid[i].C3 = vDataList[i].C3;
tCentroid[i].C4 = vDataList[i].C4;
tCentroid[i].C5 = vDataList[i].C5;
tCentroid[i].C6 = vDataList[i].C6;
tCentroid[i].C7 = vDataList[i].C7;
tCentroid[i].C8 = vDataList[i].C8;
tCentroid[i].C9 = vDataList[i].C9;
tCentroid[i].C10 = vDataList[i].C10;
tCentroid[i].Constitution = vDataList[i].Constitution;
}
int nLable = 0; //标注这一项为哪一类
//根据默认的质心给簇赋值
for (int i = 0; i < vDataList.size(); i++)
{
//ClusterOfTuple:返回项所属类
nLable = ClusterOfTuple(tCentroid, vDataList[i]);
//将此项放至对应类中
vClusters[nLable].push_back(vDataList[i]);
}
float fOldVar = -1;//第一次初始化为-1确保至少迭代一次
float fNewVar = GetVar(vClusters, tCentroid);//获得给定簇集的平方误差
while (fabs(fNewVar - fOldVar) > 0.1) //当新旧函数值相差不到1即准则函数值不发生明显变化时,算法终止
{
for (int i = 0; i < FEATURE_DIM; i++) //更新每个簇的中心点
{
//GetMeans返回每一类的质心
tCentroid[i] = GetMeans(vClusters[i]);
//cout<<"means["<<i<<"]:"<<tCentroid[i].Height<<" "<<tCentroid[i].Weight<<endl;
}
fOldVar = fNewVar;
//获得给定簇集的平方误差
fNewVar = GetVar(vClusters, tCentroid); //计算新的准则函数值
for (int i = 0; i < FEATURE_DIM; i++) //清空每个簇
{
vClusters[i].clear();
}
//根据新的质心获得新的簇
for (int i = 0; i < vDataList.size(); i++)
{
//ClusterOfTuple:返回项所属类
nLable = ClusterOfTuple(tCentroid, vDataList[i]);
//将此项放至对应类中
vClusters[nLable].push_back(vDataList[i]);
}
}
//打印质心位置
for (int i = 0; i < FEATURE_DIM; i++)
{
cout << "tCentroid"<< i + 1 <<": "<<"("<< tCentroid[i].C1 << "," << tCentroid[i].C2 << "," << tCentroid[i].C3 << "," << tCentroid[i].C4 << "," << tCentroid[i].C5 << "," << tCentroid[i].C6 << "," << tCentroid[i].C7 << "," << tCentroid[i].C8 << "," << tCentroid[i].C9 << "," << tCentroid[i].C10 << "," << tCentroid[i].Constitution<<")" << endl;
}
}输入参数为Tuple类型的数据容器和质心的位置
std::vector<double> CTestKMeans::Prediect(Tuple tCentroid[FEATURE_DIM], std::vector<Tuple> vTestList)
{
//一维链表
std::vector<double> vdResult;
for (int i = 0; i < vTestList.size(); i++) {
Tuple tTest;
tTest.C1 = vTestList[i].C1;
tTest.C2 = vTestList[i].C2;
tTest.C3 = vTestList[i].C3;
tTest.C4 = vTestList[i].C4;
tTest.C5 = vTestList[i].C5;
tTest.C6 = vTestList[i].C6;
tTest.C7 = vTestList[i].C7;
tTest.C8 = vTestList[i].C8;
tTest.C9 = vTestList[i].C9;
tTest.C10 = vTestList[i].C10;
tTest.Constitution = vTestList[i].Constitution;
int nRet = ClusterOfTuple(tCentroid, tTest);
vdResult.push_back(nRet+1);//类从1开始
std::cout <<"ID:"<<i<<"\t"<< vdResult[i] << endl;
}
return vdResult;
}输入参数为质心位置和Tuple类型的数据容器
def plot(k, assignment, center):
# 初始坐标列表
x = []
y = []
for i in range(k):
x.append([])
y.append([])
# 填充坐标 并绘制散点图
for j in range(k):
for i in range(len(assignment[j])):
x[j].append(assignment[j][i][0]) # 横坐标填充
for i in range(len(assignment[j])):
y[j].append(assignment[j][i][1]) # 纵坐标填充
plt.scatter(x[j], y[j], c=color[j],marker='o',label=("类别%d" % (j + 1)))
if(j==(k-1)):
plt.scatter(center[j][0], center[j][1], c='red', marker='*', label="中心点") # 画聚类中心
else:
plt.scatter(center[j][0], center[j][1], c='red', marker='*') # 画聚类中心
# 画出类半径
for i in range(k):
# 定义圆心和半径
x = list_center[i][0]
y = list_center[i][1]
r = radius[i]
# 点的横坐标为a
a = np.arange(x - r, x + r, 0.0001)
# 点的纵坐标减掉质心的y为b
b = np.sqrt(abs(pow(r, 2) - pow((a - x), 2)))
# 绘制上半部分
plt.plot(a, y + b, color=color[i], linestyle='-')
# 绘制下半部分
plt.plot(a, y - b, color=color[i], linestyle='-')
plt.scatter(2, 6, c='violet', marker='x', label="(2,6)") # 画(2,6)
# 设置标题
plt.title('K-means Scatter Diagram')
#
plt.legend()
# 设置X轴标签
plt.xlabel('X')
# 设置Y轴标签
plt.ylabel('Y')
# 显示散点图
plt.show()| include的头文件 |
|---|
| fstream |
| iostream |
| vector |
| math.h |
| 调用的python库 |
|---|
| pandas |
| matplotlib |
| numpy |
| 函数说明 | 调用的函数 |
|---|---|
| 指定模式打开文件 | ifstream::open() |
| 查看下一个字符 | istream::peek() |
| 查看是否为空 | ios::eof() |
| 从流中提取字符,作为未格式化的输入 | istream::get |
| 关闭文件 | ifstream::close |
| 返回容器大小 | vector::size |
| 在最后添加元素 | vector::push_back |
| 清除内容 | vector::clear |
| 调用的函数 | 函数说明 |
|---|---|
| matplotlib.rcParams | 返回是否在每个绘图命令后重绘 |
| pandas.read_csv(filename) | 从CSV文件导入数据 |
| dataframe.iat | 取某列某行的值 |
| list.append | 将数据添加到list尾部 |
| matplotlib.pyplot.scatter | 用不同的标记大小和/或颜色绘制 y 与 x 的散点图 |
| matplotlib.pyplot.plot | 将y和x绘制为线条、标记 |
| numpy.arange | 函数返回一个有终点和起点的固定步长的排列 |
| matplotlib.pyplot.title | 为坐标轴设置标题 |
| matplotlib.pyplot.xlabel | 设置 x 轴的标签 |
| matplotlib.pyplot.ylabel | 设置 y 轴的标签 |
| matplotlib.pyplot.legend | 给图加上图例 |
| matplotlib.pyplot.show | 显示所有打开的图像 |
| numpy.zeros | 返回给定形狱和类型的新数组,并用零填充 |
本次实验主要目的是实现k-means算法及可视化,算法有c++语言完成,可视化有python语言完成,第一题训练集为实验二的z-score规范化后的学生数据,第二题有训练集以及测试集,需要训练完模型后再进行测试集的测试,题目二最终导出各聚类的情况保存到csv中,可视化程序用导出的csv文件作为数据集进行相应的可视化,难点在如何绘制出类半径,其中借鉴了吴富乐同学的python代码,特别鸣谢,由第二题的可视化图像可以看出题目所给数据集分成2类会比较合适,其他类都出现分类过多、区限不明显的问题,综合考虑我认为分成2类会更合适
- 组员信息:陈泽彬(有组但单干)
- 组员分工:陈泽彬
- 指导老师:彭伟龙
学习sigmoid函数和逻辑回归算法。将实验三.2中的样例数据用聚类的结果打标签{0,1},并用逻辑回归模型拟合。
- 学习并画出sigmoid函数
- 设计梯度下降算法,实现逻辑回归模型的学习过程。
- 根据给定数据(实验三.2),用梯度下降算法进行数据拟合,并用学习好的模型对(2,6)分类。
对2,3实现有难度的同学,可以直接调用sklearn中LogisticRegression进行学习
- Windows10
- Anaconda Python3.8.3(IDE为pycharm)
-
sigmoid.png:sigmoid函数导出
-
result2.csv:Qusetion2中CPP代码导出的分成不同类的数据,用于可视化程序.py,数据样式如下表
X Y Center_X Center_Y Class 数据的x 数据的y 数据所在类的质心的x 数据所在类的质心的y 数据所在类 -
main.py:源代码
sigmoid.png
def Sigmoid(x):
return 1.0 / (1.0 + np.exp(-x))| 调用的函数库 |
|---|
| pandas |
| matplotlib |
| numpy |
| sklearn |
| 调用的函数 | 函数说明 |
|---|---|
| numpy.arange | 函数返回一个有终点和起点的固定步长的排列 |
| matplotlib.pyplot.plot | 将y和x绘制为线条、标记 |
| matplotlib.pyplot.axvline | 坐标轴上加一条竖直的线 |
| matplotlib.pyplot.axhline | 坐标轴上加一条横向的线 |
| matplotlib.pyplot.yticks | y轴标度 |
| matplotlib.pyplot.ylim | y轴范围 |
| matplotlib.pyplot.show | 显示所有打开的图像 |
| pandas.read_csv | 将逗号分隔值(csv)文件读取到DataFrame中 |
| numpy.array | 创建arrary |
| pandas.DataFrame.to_numpy | 将DataFrame转换为NumPy数组 |
| sklearn.preprocessing.StandardScaler | 去均值和方差归一化 |
| sklearn.preprocessing.StandardScaler.fit | 用于计算训练数据的均值和方差, 后面就会用均值和方差来转换训练数据 |
| sklearn.preprocessing.StandardScaler.transform | 进行转换,把训练数据转换成标准的正态分布 |
| linear_model.LogisticRegression | 根据现有数据对分类边界线建立回归公式,以此进行分类 |
| linear_model.LogisticRegression.fit | 根据给出的训练数据来训练模型。 |
| linear_model.LogisticRegression.predict_proba | 概率估计 |
本次实验主要是完成逻辑回归算法,直接调用sklearn中LogisticRegression进行学习,其算法思想以及LogisticRegression的用法在#逻辑回归(Logistic Regression)中有详细的介绍,其调用代码的主要流程为归一化——计算均值和方差——标准化——进行训练建立回归公式进行分类,最后的输出结果为[[0.00000017 0.99999983]],它代表(2,6)属于第一类的概率为0.00000017 ,属于第二类的概率为0.99999983,所以(2,6)属于第二类,这与实验三的结果吻合,由于逻辑回归只能处理两类,所以只能调用实验三的result2结果,其他的聚类结果不能调用






















