Pandas小知识

1. pandas的概述

pandas基于list,将各个series结合的更好,使数据更加结构化,利于观察。

2. Pandas的索引

2.1 索引对象

2.1.1 索引对象是什么

pandas的索引对象其实就是Index对象,可以理解理解为每一行的独特标识,我们可以通过该标识取得我们想要的数据。

通常来说,pandas自动生成的索引是一个连续的整形数字。

2.1.2 pandas自动生成的索引有什么弊端

我们已经知道了pandas自动生成的索引是连续整形数字,那么这会带来什么问题?

试想,索引代表的是什么意思呢?这里的索引仅仅能够帮助我们定位,但我们不知道该索引对应的数据到底是什么。通常在使用了Pandas的自动生成的索引后,每次修改删除操作都会伴随着重置索引reset_index(drop = True)。

所以,在实际工作过程中,我们会更愿意找数据集中单独一个id列作为我们的索引。

2.1.3 索引值的修改 

通常我们在将索引改为我们需要的id列时,都会使用这样一条语句,比如data.index = data["id"]。

这样的修改是可行的,将data.index的引用变为了data["id"]的内存地址。

但是对index对象内的单个索引值进行修改,这是不可行的,如data.index[1] = "001"。这里的修改只能对整个index对象改引用。

字符串也是一个类似的例子,如string = "abcde",我们是不能够修改string[1] = “q”的,但是能够直接将string的引用修改,如在string = "abcde" 的操作后string = "fghij"。

2.2 取数操作

2.2.1 取出第四列的数据(category)

方法:

  • data.category
  • data.iloc[:,4]
  • data.loc[:,"category"]

注意点:开发过程中尽量使用.loc的方式查询数据,可读性会更好

2.2.2 取出第四行的数据

方法:

  • data[3:4]
  • data.iloc[3:4,:]

错误写法:

  • data[4]

错误原因:如果列字段名也是数字,data[4]容易造成歧义,而拥有符号" : "的写法,是一个完整的声明,python可以知道这是一个没有歧义的写法。

2.2.3 取出多列数据

方法:

  • data.loc[:,["category", "investment_strategy", "investment_type"]]
  • data.loc[:, "category" : "investment_type"]

注意点:

  • 在第一个方法中,之所以里边又加了一个中括号,是由于loc底层的实现是一个迭代器,我们需要传一个列表过去迭代。另外,若不加中括号,由于有多个逗号,语法也会发生错误。
  • 在第二个方法中,我们使用了符号" : "达到了相同效果,由此可以带冒号的完整声明返回的是一个list对象。

2.2.4 bool索引

数据完美的情况下

注意点:bool索引值在比较后通过判断bool值筛选我们需要的数据

如现在有一列字段"fund_symbol",我们需要筛选该列大于1310的数据,我们可以这样判断:

data.loc[:,"fund_symbol"] > 1310,这会返回一个含bool值的series,再根据这个series筛选出我们需要的数据即可,如:data[data.loc[:,"fund_symbol"] > 1310]

数据不完美的情况下

通常来说,我们的数据并不是完美的,比如该列其实是个str对象,所以直接比较是会报错的,如刚才的语句:data.loc[:,"fund_symbol"] > 1310。

首先,假设该字段只包含数字形式的字符串,那么我们可以用以下方法解决这个问题:

  • data.loc[:,"fund_symbol"].astype(int) > 1310
  • data.loc[:,"fund_symbol"].apply(lambda x: int(x))

另外,如果该字段并不只包含数字形式的字符串怎么办?我们可以用以下方式解决,将字符串根据我们的需要转换为可以使用的数字,在这里会转换为1310

  • data.loc[:,"fund_symbol"].apply(lambda x: int(x) if x.isdigit() else 1310)

值得注意的是,在很多语言中支持的三元表达式的写法在这里并不被支持,如data.loc[:,"fund_symbol"].apply(lambda x: x.isdigit() ? int(x) : 1310)会报错

3. 多层索引(层次索引)

3.1 举例

多层索引如字面所述,使用多列进行索引,如下所示:

其中,活跃程度和性别是我们的多层索引

3.2 生成方式

通常,我们使用set_index()来生成我们的多层索引,如我们的原始数据为:

接着,使用data.set_index(["活跃程度","性别"]),就可以得到我们3.1中的数据结果了。

3.3 取数操作

在对含有层次索引的数据集取数据的时候,我们需要根据元组进行索引,因为层次索引的索引值是以元组为基本单位的。如:data.loc[("高活跃","男"),:],会取到如下数据

3.4 层次索引的意义

层次索引其实代表的是一种流转,如3.1中的结果所示,代表的是不同活跃程度的人群到不同性别的流转,如果将层次索引颠倒过来,就可以代表不同性别的群体到不同活跃程度的流转。

比如电商等行业,就会特别关注不同活跃程度的人群到不同地区的流转。

3.5 层次索引的聚合

在确认了流转的方向后,我们便可以根据这个方向,对数据进行聚合。比如,我们想知道高活跃,性别男的平均年龄,具体操作如图所示:

3.6 层次索引聚合和group by聚合的区别

在这个层次索引中,我们可以清晰看到流转的情况,但是如果使用group by来聚合数据,我们仅能看到聚合后的结果,对中间过程没有一个详细的认知。

4. series和dataframe在apply时的不同

4.1 使用apply时的粒度

使用apply时,如果是dataframe对象使用apply,那么会对dataframe中的每个series进行运算。

如果是series使用apply,那么会对series中的每一行(即每一个对象)进行运算。

4.2 错误使用示例

需求:对之前例子的结果进行聚合运算

基于刚才的temp = data.loc[:,"fund_symbol"].apply(lambda x: int(x) if x.isdigit() else 1310),我们获得了完整的仅含int对象的数据列,类型为series,如果我们打算对这个series进行聚合操作,会产生报错,如:temp.apply(lambda x: x.max() - x.min())。原因在于series对象在实现apply方法时,传入的是该列中的每一行的int对象(即例子中的x),而int对象并不包含max()等聚合方法,因此会报错。

4.3 解决方法

针对刚才的错误,我们可以发现是粒度引起的问题,如果要解决问题,这里需要将series对象重新转换为dataframe对象,再apply,此时就可以完成聚合操作了,如下:

temp = pd.DataFrame(temp.values)

temp.apply(lambda x: x.max() - x.min)

此时,这个x就代表的是一列数据,即series,我们可以正常调用聚合函数来计算结果。

4.4 apply中axis的问题

首先值得一提的是,axis=0指多行操作,axis=1指对多列操作。什么意思呢?继续使用刚才的案例,temp.apply(lambda x: x.max() - x.min)的完整形式应该是temp.apply(lambda x: x.max() - x.min, axis = 0),只不过axis = 0是默认的,所以我们并没有声明。

axis = 0和axis = 1时到底有何不同呢?

在这个案例中,

当axis = 0时,会对纵轴方向的数据进行处理。这里会获得该series的所有行,如500行(个)不同数字的数据,再对这些数据进行max()和min()聚合运算,最终求得的值为单独的一个确定值。

当axis = 1时,会对横轴方向的数据进行处理。这时候进行max()和min()聚合运算时,横向只有单独的一个x值,如果这时对x进行操作,会发生广播运算。如x.max()的操作,会将max()广播到每一个x。因此在聚合后x.max()-x.min()=0。运算完成后,我们会获得计算结果全为0(500个0)的一个series对象。

5. Series的小知识

5.1 pd.Series

temp = pd.Series()可以创建一个空的Series,且dtype为float64,这是一个很反常的事,不过在执行语句时,官方声明在未来版本本会将初始化的空Series类型改为object,这会更符合常理。

5.2 空Series的添加

5.2.1 正确写法

  • temp.append(pd.Series([1]))

5.2.2 错误写法

  • temp.append(1)
  • temp.append("a")
  • temp.append(pd.Series(1))

错误原因:

  • Series对象的增加操作只能增加Series和DataFrame类型的对象,不支持其它对象
  • 在第三个错误写法中,Series支持通过list对象转变为Series,而不支持单独的数字转变,这是Series在封装时的规定。

5.3 空Series在添加元素后的类型问题

在4.1中,我们知道了空Series对象的类型为float64,那么为什么依然能添加其它包含不同类型的数据的Series对象呢?原因在于所有类型的对象都有一个共同的超类祖宗Object(即父类或祖宗类),python可以根据这一特效进行类型转换,在Series新增数据,类型更改为Object,即满足了不同类型对象共存的问题。

6. 其他补充

在dataframe进行apply操作时,是针对每一列或每一行Series进行操作,但是如果我们需要操作每一个单元格,这时可以使用applymap()方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值