Python, Pandas,跨行求不同类别的百分比

《求更好解决办法》

1. 问题描述

1.1 相关材料

CSV文档:

  每一行包含一个候选人,和他参选选区的相关信息,详情如下:

              "election_year": 选举年份。可能的取值为 “2011” 和 "2015年" ;

                "cacode" :    选区编号。2011年和2015年的 “选区编号”,可能不一致,例如,A11选区在2011年出现,但在2015年则没有该选区;

                “camp”:        阵营。每个候选人可能来自三个不同的阵营(泛,建,其它);

                "is_elected":    是否当选。Y: 当选,N: 落选;

                "candidate_num":    候选人编号;

                “vote”:    所得票数。

图1. 2011年,选区A01-A04
图2. 2015年,选区A01-A04

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"): "泛"/ “建”/ “其它” ,各自所得票数的百分比

图3. 期待结果


1.3 难点总结

1.3.1 如 “图4. 自动当选,没有票数”  所示,如果候选人的编(“candidate_num”)是 “noCompetitor” ,则不需要计算,该选区,在该选举年份中,各个阵营("camp")所得票数的百分比。

图4. 自动当选,没有票数

1.3.2 选举年份2011 和 2015 包含的选区可能不完全相同。 即,选区A09在2011年出现,但可能在2015年没有该选区。

2. 现有解决思路

Step 1.  对 CSV 表格中列 “cacode” 和 列 "election_year" 按照 A-Z 升序排列,确保某年,某个选区的所有候选人,依次排列在一起, 而不是散落到CSV文档的不同位置。效果如图1,图2;

Step 2. 用Pandas 读入CSV文档

图5. 读入排序后的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”的值。

图6. DataFrame.iloc[ ]

Step 3.3 得到所有行,这些行有着相同的列(“election_year” 和 “cocode”的)值,分别为 “yearInit” 和 "cacodeInit"。

即,取得读入的DataFrame: dataPure中,所有相同的选举年份,和选区编号的行。接着,计算所得到DataFrame的行数,并赋值给 输出参数:groupLength,如图7

图7. 取得某年,某选区的所有参选人所在的行

Step 3.4 在某年,某个选区所有候选人组成的, 变量名为“candidates” 的DataFrame中,取得

    “winnerCamp”:    当选者来自的阵营(camp)

    "isAutowin":        当选者的候选编号(canditate_num)

    "commonCacode":    所有候选人,共同的选区编号(cacode)

    "commonYear":        所有候选人,共同的选举年份(election_year)


图8. 取得某年,某选区,参选者的相关信息

Step 3.5  若变量“isAutowin”的值,不等于“noCompetitor”,则代表该年,该选区,有多于1位候选人,需要选民投票,可以计算各个阵营(camp)所得票数的百分比;

反之,若变量“isAutowin”的值,等于“noCompetitor”,则代表该年,该选区,只有一个人参与,不需要投票,不需要计算各个阵营的所得票数的百分比。

Step 3.5.1  变量“isAutowin”的值,不等于“noCompetitor”, 需计算各个阵营( camp )所得票数的百分比,代码如下:

if isAutowin != 'noCompetitor':

得到某年、某选区里,每个候选人所得票数。根据每个候选人,各自所属的阵营(camp)将该票数,追加到相应的数组里面,代码如图9:

图9. 取得某年,某选区,所有候选人的=所得票数,和各自所属阵营

计算某年,某选区,所有阵营(Camp)所得票数的百分比,代码如图10:

图10. 计算各个阵营所得票数的百分比

将上述计算求得的结果:

            "fanTotal":     某年,某选区,所有阵营(camp)为“泛” 的候选人,得票总和

          "jinaTotal":    某年,某选区,所有阵营(camp)为“建” 的候选人,得票总和

            "otherTotal":    某年,某选区,所有阵营(camp)为“其它” 的候选人,得票总和

  "fanPercent" / "jianPercent" / "otherPercent" : 某年,某选区,三大阵营的得票率

通过Pandas 创建DataFrame,并追加到指定路径的CSV文档中,如图11:

图11. 将计算结果追加到CSV文档

Step 3.5.2  变量“isAutowin”的值,等于“noCompetitor”, 该年,该选区,只有以为参选人:

    不需要计算各个阵营(camp)的得票率;

    但,需要将输出参数:“groupLength” 设为:1。即,某年,某选区,只有一位候选人

如图12:

图12: 某年,某选区,只有一位候选人,不需要计算各个阵营得票率

Step 3.6

        返回输出参数:“groupLength”(下一行要重复Step3.1 -Step 3.6)的DataFrame的下标

return groupLength

该方法的完整代码如下图13

图13: 完整的代码

Step 4.  遍历 Step2 中读入的DataFrame,并使用 Step 3定义的方法,如下图14:

当指针" i " 的数值,小于 Step2 中读入的DataFrame的行数时,会使用Step 3 中定义的方法,先判断该年,该选区,是否只有一人参选,

若是,则返回将“moveStep”赋值为1;

若否,则计算并保存某年、某个选区(cacode),不同阵营(Camp)的得票率,将“moveStep” 赋值为该区,这次选区的参选人数。

图14. 遍历要处理的CSV




最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容