Pandas进阶贰 pandas基础
pandas进阶系列根据datawhale远昊大佬的joyful pandas教程写一些自己的心得和补充,本文部分引用了原教程,并参考了《利用Python进行数据分析》、numpy官网、pandas官网
为了方便自己回顾和助教审阅,每一节先将原教程重要知识点罗列一下帮助自己回顾,在其后写一些自己的心得以及我的习题计算过程
本文的的函数总结中,
库函数使用 包名+函数名 命名,如pd.read_csv()
类方法用 类名简写或x + 函数名 命名,如df.to_csv()
另注:本文是对joyful pandas教程的延伸,完整理解需先阅读joyful pandas教程第二章
PPS:写给助教:task2学得有点晚了,目前上传的这个版本还没完全写好自己要写的内容,现在正在通宵爆肝中,会于12月20日凌晨三点前提交最终版,如果助教这段时间内审核的话希望您能稍微给我宽限一点时间,目前的版本有自己原创的部分,不过还没达到我满意的程度,谢谢!
补充内容
在上一个教程结束后我翻阅了《利用python进行数据分析》进一步学习了numpy相关的内容,有一些收获,暂时先放在这一章和大家分享
notebook 操作
经过最近的学习,对notebook的操作更快了些,主要是记了几个快捷键,让自己效率大大提升,和大家快速分享一下,通过几个快捷键解放双手再也不用鼠标
- notebook的每个单元格的读写模式和vim有些类似,使用
ESC
切换成命令模式,使用ENTER
切换成编辑模式 - 在命令模式下,可以通过
m
转换单元格为Markdown单元格,y
将单元格转换为代码单元格 - 在命令模式下,可以通过
a
在当前单元格上方新建单元格,b
在当前单元格下方新建单元格 - 另外除了常用的shift+enter, ctrl+enter外,还有
alt+enter
可以在运行当前单元格后在下方新建一个单元格也很常用 - 在命令模式下,通过
d d
(和vim删除一行的操作一样)可以删除当前单元格,使用z
可以撤销删除,试了下z也可以撤销好几次的删除,上限有多少不清楚(我试了下撤销11次都没问题)不查不知道,之前误删了好多次,都不知道用z然后就像个傻子一样再打一遍… - 在命令模式下,键入
1,2,3...
可以在第一行直接加入一级、二级、三级…标题
这些是我现在经常用到的命令,这些小技巧有点基于个人经验而谈,不过记住这些命令就不用鼠标了打起来很流畅。
更多notebook快捷键可以在命令模式下按 h
查询
numpy数组索引原理
在上一节的练习题中,远昊大佬的习题让我们充分感受到了numpy的高效与灵活,那么为什么numpy可以计算得这么快呢?
首先,np.ndarray与python的list相比,ndarray中的所有数据都是相同类型的,而list中的数据可以是各种类型的,因此ndarray效率更高;
另外也是非常重要的一点是,ndarray的本质是一个数据块的视图
我们通过观察ndarray的内部结构来详细了解以下,ndarray这个类的属性包含以下这些(链接中有全部属性,这里我摘抄一些重点的):
attributes | description |
---|---|
strides | 跨到下一个元素所需要的字节数 |
size | 数组中元素数量 |
dtype | 数据类型 |
data | 数据块的起始位置 |
学过C/C++的同学有没有熟悉的感觉!这些属性感觉就是新建了一个数组,然后建了一个指向数组元素类型的指针嘛!(我是这么觉得的,助教大大可以审阅一下看对不对)
因此ndarray的索引和切片并不是新开辟了一个内存空间去存数据,而只是一种视图,即改变了原有数据的访问方式。
具体举个例子验证一下:
现有数组a,数组b的索引方式是b=a[2:8:2],即b是a的第三个元素、第五个元素、第七个元素,按照刚刚的想法,b的实现逻辑应该是根据data、strides和b给出的起始索引,将指针移到第一个要读取的元素的位置,将这个位置赋值给b的data,紧接着根据步长和strides,决定b的每个元素要读取的步长,赋值给b的strides,所以生成b的时候完全没有数据的迁移,仅仅是根据a的属性生成了b的属性
下面的例子验证了这个想法
import numpy as np
import pandas as pd
a = np.arange(10)
b = a[2:8:2]
b[-1] = 999
print(f'a strides: {a.strides}')
print(f'b strides: {b.strides}')
a
a strides: (8,)
b strides: (16,)
array([ 0, 1, 2, 3, 4, 5, 999, 7, 8, 9])
Pandas 文件读写
函数总结
function | description |
---|---|
pd.read_csv() | |
pd.read_table() | 默认以\t为分隔符,可以自定义 |
df.to_csv() | 默认csv,可以自定义分隔符 |
df.to_markdown() | 天哪还有这种神奇函数(需要安装tabulate包) |
常用参数 | |
index_col | 用作索引的列号列名 |
usecols | 选择列 |
header | 定义列名 |
nrows | 读取前n行 |
parse_dates | 将某些列解析为datetime |
我目前经常会用到的读函数就是read_csv,不过根据read_table给出的参数sep, 说明read_csv也可以通过read_table实现,展示一下:
df_txt = pd.read_table('../data/my_csv.csv', sep=',')
df_txt
col1 | col2 | col3 | col4 | col5 | |
---|---|---|---|---|---|
0 | 2 | a | 1.4 | apple | 2020/1/1 |
1 | 3 | b | 3.4 | banana | 2020/1/2 |
2 | 6 | c | 2.5 | orange | 2020/1/5 |
3 | 5 | d | 3.2 | lemon | 2020/1/7 |
另外可以看出远昊大佬构造的表可谓用心良苦,每一列的数据类型由常识来判断都是不同的,通过常识判断,这五列在一般上下文中的数据类型应该是整形、字符型、浮点数、字符串、日期,那在不做任何预处理的情况下,看看pandas是如何认识数据的:
df_txt.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 col1 4 non-null int64
1 col2 4 non-null object
2 col3 4 non-null float64
3 col4 4 non-null object
4 col5 4 non-null object
dtypes: float64(1), int64(1), object(3)
memory usage: 288.0+ bytes
可以看出,对于整形和浮点型,pandas默认将其标记为int64
和float64
, 而其他类型一概标记为object
,因此在具体项目中对其他数据要分别定义好数据类型,对整形和浮点型应该根据语义或者数据,确定其具体的更小的数据类型以压缩数据。
数据写入
一般在数据写入中,最常用的操作是把index
设置为False
,特别当索引没有特殊意义的时候,这样的行为能把索引在保存的时候去除。
这点要特别注意,如果不设置为False,读取时会多一个Unnamed:0
列,我打比赛做特征工程的时候多次犯了这个错误提醒大家特别要小心:(
示例如下:
df_csv.to_csv('../data/my_csv_saved.csv')
df_unindexed = pd.read_csv('../data/my_csv_saved.csv')
df_unindexed.head(1)
Unnamed: 0 | col1 | col2 | col3 | col4 | col5 | |
---|---|---|---|---|---|---|
0 | 0 | 2 | a | 1.4 | apple | 2020/1/1 |
Pandas 基本数据结构
pandas
中具有两种基本的数据存储结构,存储一维values
的Series
和存储二维values
的DataFrame
,在这两种结构上定义了很多的属性和方法。
1. Series
Series
一般由四个部分组成,分别是序列的值data
、索引index
、存储类型dtype
、序列的名字name
。其中,索引也可以指定它的名字,默认为空。
s = pd.Series(data = [100, 'a', {
'dic1':5}],
index = pd.Index(['id1', 20, 'third'], name='my_idx'),
dtype = 'object',
name = 'my_name'