Python学习笔记(二)

Python学习笔记(二)

前一篇请参考Python学习笔记(一)

数据分析

同过前一篇的内容,我们建立了Python环境,并且用Qt做了一个GUI界面。接下来,我们要用pandas这个库来实现对数据的分析。
先来说说我们要完成的功能:
1.数据是用Execl的方式来存储的,第一行是数据表头(用英文字母写的名称)
2.从做好的GUI界面上获取相关过滤条件,过滤掉不符合条件的数据
3.按照输出要求,从最后剩下的结果当中抽取出相应的结果,提供给Qt显示

数据表

pandas这个库很强大,可以通过第一行表头的名称来操作相关列,很方便。
pandas提供了Series,DataFrame这连个强大的数据操作类。我这里主要使用DataFrame。
关于pandas,下面这个不知哪个外国大神做的图,挺提纲挈领的。
在这里插入图片描述
使用pandas之前,需要像下面一样引用一下相关的库,这里要说明的是pandas使用xlread这个库来读execl所以除了安装pandas以外,还要手动安装xlread.

from pandas import Series,DataFrame
import pandas as pd
import numpy

然后像下面这样的一句话,就可以读入execl表格的内容了。是不是很方便。

self.DF = pd.DataFrame(pd.read_excel(execlFliePath))
or
self.DF = pd.DataFrame(pd.read_excel(execlFliePath,sheetName))

execlFilePath是execl文件的路径和文件名,如果不指定sheet名称,就打开默认active的sheet。

使用某一列的数据就可以用下面的方式

self.DF['Recruitment Time']

想要在DataFrame里面手动加一列可以通过下面这个方式

for payValue in range(4000,30000,500):
    self.DF.loc[(self.DF.Pay <= payValue)&(self.DF.Pay > payValue-500),'PayLable']="%04.1fK"%(payValue/1000.0)

这块代码实现了,在DataFrame里面新加入PayLable这一列的功能,PayLable是根据Pay这列的值,按照500为单位,转换成相应的“10.5K”这样字符串。
DataFrame的loc(location定位)函数,第一个参数是行,第二个参数是列。
在上面的这个代码当中,

self.DF.loc[(self.DF.Pay <= payValue)&(self.DF.Pay > payValue-500),'PayLable']

表示Pay这列的值在(payValue-500,payValue]范围内的行,列为’PayLable’的这些Cell单元。
这里再啰嗦几句,DataFrame每一行都有相应的索引,这些索引是在建立DataFrame的时候就指定的。我们这里是直接读的Execl做成的DataFrame,索引就是1,2,3…

条件过滤

DataFrame的另一个强大的地方,是我们不用自己做数据类型的转换。

过滤时间条件

execl数据当中有一列为Recruitment Time,格式是2019/12/12这样的时间
指定时间范围的数据过滤如下

def FilterDataBy_RecruitmentDate(self,sDate,eDate):
    self.DF = self.DF[(self.DF['Recruitment Time'] >= pd.Timestamp(sDate)) & (self.DF['Recruitment Time'] <= pd.Timestamp(eDate))]

其中,sDate,eDate是Python当中datetime的数据类型
下面是从Qt的时间控件当中取得时间值,转换成datetime数据类型的代码

import datetime

        startDataStringList = self.ui.dateEdit_SearchStart.date().toString(Qt.ISODate).split('-')
        endDataStringList = self.ui.dateEdit_SearchEnd.date().toString(Qt.ISODate).split('-')
        startData = datetime.date(int(startDataStringList[0]),int(startDataStringList[1]),int(startDataStringList[2]))
        endData = datetime.date(int(endDataStringList[0]), int(endDataStringList[1]), int(endDataStringList[2]))
过滤字符串

execl数据当中有一列为Score,格式是3,3.5这样的数值
但是我们从GUI画面上取到是’3’,'3.5’这样的字符串。
但是我们不用自己做相应的转换,直接用下面这样的方法来过滤掉不是’3.5’的相关行

def FilterDataBy_Score(self,scoreStr):
    self.DF = self.DF[self.DF['Score'].isin([scoreStr])]
过滤数字

execl数据当中有一列为Experience,格式是6,7,8这样的数字,
我们从GUI获得的是开始数字expStartValue和结束数字expEndValue

def FilterDataBy_Experience(self,expStartValue,expEndValue):
    self.DF = self.DF[(self.DF['Experience']>=expStartValue) &(self.DF['Experience']<=expEndValue)]

通过以上方式,就可以对输入的数据进行相应的过滤处理,而且实现起来也很方便快捷。

数据整理

通过上面的过滤,我们得到了想要的数据行。但是还不是我们想要得到的数据样式。

对数据进行排序

截取DataFrame当中的若干列,并且按照其中某一列进行排序

def GetData_NameRankPayList(self):
    NameRankPayList = self.DF[['Rank','Name','Pay']].sort_values(by='Rank', axis=0, ascending=True)
    return NameRankPayList.values.tolist()

上面这段代码实现了截取Rank,Name,Pay这三列数据,并且按照Rank这列安装从小到大的顺序排列。
要说明的是最后那个Return。DataFrame虽然强大,但是其他库并不认识这个数据结构,这就要我们把DataFrame转换成标准的Python格式。NameRankPayList.values.tolist()的结果长成如下的样子[[‘rank1’,‘name1’,pay1],[‘rank2’,‘name2’,pay2],…]。不是所有的值都是字符串的形式。

统计重复个数

下面这段代码会统计Rank这列当中所有重复的项,并且返回一个不重复的Rank列表和每个Rank下相应人数的列表。

def GetData_Rank2NumOfPeople(self):
    # sort it
    Rank2NumOfPeople = self.DF[['Rank','Name']].sort_values(by='Rank', axis=0, ascending=True)
    Rank2NumOfPeople = Rank2NumOfPeople.groupby(by='Rank').count()
    return (Rank2NumOfPeople.index.tolist(),Rank2NumOfPeople['Name'].values.tolist())

要说明的是Rank2NumOfPeople.groupby(by=‘Rank’)之后的结构,并不是DataFrame的。执行完groupby.count之后会形成以Rank为Index的一张新表格。
这里想和大家说的是,如果我们不是特别清楚每一步作为的数据是什么样子,可以利用print函数,把值打印出来。这样有助于我们理解相应的结构

来个复杂一点的

PayLable,Score,Name三列数据,统计每Pay范围下每个得分的人数
并形成以Rank为行,以Score为列,交叉点为人数的新表格
原表格

PayLableScoreName
06.5K3.0小王
11.5K4.5小黄
10.5K3.5小张
11.5K4.5小李

转换后的表格

PayLable3.03.54.5
06.5K100
10.5K010
11.5K020

实现的代码如下

    def GetData_Score2Pay2NumOfPeope(self):
        # Remove duplicated Paylabe and sort it
        PayLableDF = self.DF.drop_duplicates(subset=['PayLable'], keep='first')[['PayLable']]
        PayLableDF = PayLableDF.sort_values(by='PayLable', axis=0, ascending=True)
        # Get Score List
        ScoreDF = self.DF.drop_duplicates(subset=['Score'], keep='first')[['Score']]
        ScoreDF = ScoreDF.sort_values(by='Score', axis=0, ascending=True)

        # Create the new dataframe with new columns
        columnsList = ['PayLable']+ ScoreDF['Score'].values.tolist()
        Score2Pay2NumOfPeope = PayLableDF.reindex(columns=columnsList,fill_value=0)
        # Get the dataframe of num of poeple by 'PayLable', 'Score',
        PayScoreNumbertable = self.DF[['PayLable','Score','Name']].groupby(by=['PayLable', 'Score']).count()

        # Set the num of people of ('PayLable', 'Score') to the dataframe
        for index,data in PayScoreNumbertable.iterrows():
            Score2Pay2NumOfPeope.loc[Score2Pay2NumOfPeope.PayLable == index[0],index[1]]=PayScoreNumbertable.xs(index).values[0]

        return Score2Pay2NumOfPeope

咱们一点点看

  • 首先,我们要获得新表格当中所有行的(也就是PayLable当中不重复的项,并且排序)
self.DF.drop_duplicates(subset=['PayLable'], keep='first')

这个是将原来DF表格当中PayLable这列当中重复的行去掉,保留第一个非重复的项。所以这个函数返回的也是一个DataFrame并且列的名称不变。因此他后面的[[‘PayLable’]]就是将这个不重复的列单独取出来。
之后在通过下面的处理进行排序

PayLableDF = PayLableDF .sort_values(by='PayLable', axis=0, ascending=True)
  • 然后,我们要获取新表格当中所有列的名称(也就是Score当中不重复的项,并且排序)
    这个处理和上面的一样,不再重复说明
ScoreDF = self.DF.drop_duplicates(subset=['Score'], keep='first')[['Score']] 
ScoreDF = ScoreDF.sort_values(by='Score', axis=0, ascending=True)
  • 之后,我们要新建这个输出用的新表格
    做出新表格所有列的名称
columnsList = ['PayLable']+ ScoreDF['Score'].values.tolist()

这里要说明的是这个columnsList 的结果最终长成这个样子[‘PayLable’,3.0,3.5,4.5],也就是说列的名称其实也可以是非字符串的形式
做成新表格,表格里面的值默认成0

Score2Pay2NumOfPeope = PayLableDF.reindex(columns=columnsList,fill_value=0)

这步作为,表格就变成下面这样

PayLable3.03.54.5
06.5K000
10.5K000
11.5K000
  • 表格做好了之后,我们就要开始统计表格当中相同PayLable和Score的个数了
    统计方法和之前一样,还是利用Groupby的count函数,只不过这里我们用了两个条件去group.
PayScoreNumbertable = self.DF[['PayLable','Score','Name']].groupby(by=['PayLable', 'Score']).count()

这里要说明一下,PayScoreNumbertable是一个双Index的DataFrame,如下图(忽略数据和上面的不一致的事情)
在这里插入图片描述
其实和我们想要的表格很相近了,但是如何直接转换成我们想要的样子而不用像上面一样,先把表格做出来,我没有研究明白,哪位大神有经验麻烦给些Tips

  • 最后,把统计好的数据填写的上面建好的表格当中
 for index,data in PayScoreNumbertable.iterrows():
    Score2Pay2NumOfPeope.loc[Score2Pay2NumOfPeope.PayLable == index[0],index[1]]=PayScoreNumbertable.xs(index).values[0]

这里要说的是index,获得的是每一行的所有Index,所以index[0]就是PayLable,index[1]就是Score。
loc函数我们上面提过了,是用来定位DataFrame的Cell的。
xs(index)函数可以对复数Index来定位相应的行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值