《求更好解决办法》
1. 问题描述
1.1 相关材料
CSV文档:
每一行包含一个候选人,和他参选选区的相关信息,详情如下:
"election_year": 选举年份。可能的取值为 “2011” 和 "2015年" ;
"cacode" : 选区编号。2011年和2015年的 “选区编号”,可能不一致,例如,A11选区在2011年出现,但在2015年则没有该选区;
“camp”: 阵营。每个候选人可能来自三个不同的阵营(泛,建,其它);
"is_elected": 是否当选。Y: 当选,N: 落选;
"candidate_num": 候选人编号;
“vote”: 所得票数。
1.2 要解决的问题
对每一年(2011,2015)每个选区(例. A01, B03)中的所有参选人,基于每位参选人的阵营(“camp”),和每个阵营(“camp”)所得票数(vote)。
计算出,某年,某个选区中,不同阵营(“camp”)的得票率。
如 “图3. 期待结果” 所示:希望得到一个CSV 文档,里面的新增的列名和含义为:
“winnerCamp”: 当选者("is_elected=Y") 所属的阵营(“camp”)
"fanTotal": 该选区,在该选举年份(2011,或2015),阵营("camp")为“泛” 的所有候选人,所得票数总和
“jianTotal": 该选区,在该选举年份(2011,或2015),阵营("camp")为“建” 的所有候选人,所得票数总和
“otherTotal": 该选区,在该选举年份(2011,或2015),阵营("camp")为“其它” 的所有候选人,所得票数总和
"fanPercent"/ "jianPercent"/ "otherPercent": 该选区,在该选举年份(2011,或2015),三个阵营("camp"): "泛"/ “建”/ “其它” ,各自所得票数的百分比
1.3 难点总结
1.3.1 如 “图4. 自动当选,没有票数” 所示,如果候选人的编(“candidate_num”)是 “noCompetitor” ,则不需要计算,该选区,在该选举年份中,各个阵营("camp")所得票数的百分比。
1.3.2 选举年份2011 和 2015 包含的选区可能不完全相同。 即,选区A09在2011年出现,但可能在2015年没有该选区。
2. 现有解决思路
Step 1. 对 CSV 表格中列 “cacode” 和 列 "election_year" 按照 A-Z 升序排列,确保某年,某个选区的所有候选人,依次排列在一起, 而不是散落到CSV文档的不同位置。效果如图1,图2;
Step 2. 用Pandas 读入CSV文档
Step 3. 定义一个方法,
def groubCacodeByYear(startRow, dataPure):
Step 3.1 该方法的输入和输出为:
输入参数:"startRow", 数据类型为: int ,用来定位,“dataPure” 中的DataFrame(即,CSV文档中的行)
输入参数:“dataPure”,数据类型为:DataFrame,稍后会用被遍历
输出参数:“groupLength”, 数据类型为:int, 用于刷新遍历DataFrame的下标
return groupLength
Step 3.2 该方法的实现细节:
根据输入参数“startRow”,通过Pandas.DataFrame.iloc[]方法,得到下标等于“startRow”的DataFrame(行)。从而,得到该DataFrame(行)中,列名“election_year” 和列名“cacode”的值。
如下“ 图6. DataFrame.iloc[ ] “ 所示: 得到给定下标的DataFrame(行),列名为 “election_year”和“cacode”的值。
Step 3.3 得到所有行,这些行有着相同的列(“election_year” 和 “cocode”的)值,分别为 “yearInit” 和 "cacodeInit"。
即,取得读入的DataFrame: dataPure中,所有相同的选举年份,和选区编号的行。接着,计算所得到DataFrame的行数,并赋值给 输出参数:groupLength,如图7
Step 3.4 在某年,某个选区所有候选人组成的, 变量名为“candidates” 的DataFrame中,取得
“winnerCamp”: 当选者来自的阵营(camp)
"isAutowin": 当选者的候选编号(canditate_num)
"commonCacode": 所有候选人,共同的选区编号(cacode)
"commonYear": 所有候选人,共同的选举年份(election_year)
Step 3.5 若变量“isAutowin”的值,不等于“noCompetitor”,则代表该年,该选区,有多于1位候选人,需要选民投票,可以计算各个阵营(camp)所得票数的百分比;
反之,若变量“isAutowin”的值,等于“noCompetitor”,则代表该年,该选区,只有一个人参与,不需要投票,不需要计算各个阵营的所得票数的百分比。
Step 3.5.1 变量“isAutowin”的值,不等于“noCompetitor”, 需计算各个阵营( camp )所得票数的百分比,代码如下:
if isAutowin != 'noCompetitor':
得到某年、某选区里,每个候选人所得票数。根据每个候选人,各自所属的阵营(camp)将该票数,追加到相应的数组里面,代码如图9:
计算某年,某选区,所有阵营(Camp)所得票数的百分比,代码如图10:
将上述计算求得的结果:
"fanTotal": 某年,某选区,所有阵营(camp)为“泛” 的候选人,得票总和
"jinaTotal": 某年,某选区,所有阵营(camp)为“建” 的候选人,得票总和
"otherTotal": 某年,某选区,所有阵营(camp)为“其它” 的候选人,得票总和
"fanPercent" / "jianPercent" / "otherPercent" : 某年,某选区,三大阵营的得票率
通过Pandas 创建DataFrame,并追加到指定路径的CSV文档中,如图11:
Step 3.5.2 变量“isAutowin”的值,等于“noCompetitor”, 该年,该选区,只有以为参选人:
不需要计算各个阵营(camp)的得票率;
但,需要将输出参数:“groupLength” 设为:1。即,某年,某选区,只有一位候选人
如图12:
Step 3.6
返回输出参数:“groupLength”(下一行要重复Step3.1 -Step 3.6)的DataFrame的下标)
return groupLength
该方法的完整代码如下图13:
Step 4. 遍历 Step2 中读入的DataFrame,并使用 Step 3定义的方法,如下图14:
当指针" i " 的数值,小于 Step2 中读入的DataFrame的行数时,会使用Step 3 中定义的方法,先判断该年,该选区,是否只有一人参选,
若是,则返回将“moveStep”赋值为1;
若否,则计算并保存某年、某个选区(cacode),不同阵营(Camp)的得票率,将“moveStep” 赋值为该区,这次选区的参选人数。