Pandas简单使用教程笔记


pandas,python+data+analysis的组合缩写,是python中基于numpy和matplotlib的第三方数据分析库,与后两者共同构成了python数据分析的基础工具包,享有数分三剑客之名。
pandas与numpy的关系不是替代,而是互为补充。二者之间主要区别是:

从数据结构上看:
numpy的核心数据结构是ndarray,支持任意维数的数组,但要求单个数组内所有数据是同质的,即类型必须相同;而pandas的核心数据结构是series和dataframe,仅支持一维和二维数据,但数据内部可以是异构数据,仅要求同列数据类型一致即可
numpy的数据结构仅支持数字索引,而pandas数据结构则同时支持数字索引和标签索引

从功能定位上看:
numpy虽然也支持字符串等其他数据类型,但仍然主要是用于数值计算,尤其是内部集成了大量矩阵计算模块,例如基本的矩阵运算、线性代数、fft、生成随机数等,支持灵活的广播机制
pandas主要用于数据处理与分析,支持包括数据读写、数值计算、数据处理、数据分析和数据可视化全套流程操作

pandas主要面向数据处理与分析,主要具有以下功能特色:
按索引匹配的广播机制,这里的广播机制与numpy广播机制还有很大不同
便捷的数据读写操作,相比于numpy仅支持数字索引,pandas的两种数据结构均支持标签索引,包括bool索引也是支持的
类比SQL的join和groupby功能,pandas可以很容易实现SQL这两个核心功能,实际上,SQL的绝大部分DQL和DML操作在pandas中都可以实现
类比Excel的数据透视表功能,Excel中最为强大的数据分析工具之一是数据透视表,这在pandas中也可轻松实现
自带正则表达式的字符串向量化操作,对pandas中的一列字符串进行通函数操作,而且自带正则表达式的大部分接口
丰富的时间序列向量化处理接口
常用的数据分析与统计功能,包括基本统计量、分组统计分析等
集成matplotlib的常用可视化接口,无论是series还是dataframe,均支持面向对象的绘图接口

pandas核心数据结构有两种,即一维的series和二维的dataframe,二者可以分别看做是在numpy一维数组和二维数组的基础上增加了相应的标签信息。正因如此,可以从两个角度理解series和dataframe:
series和dataframe分别是一维和二维数组,因为是数组,所以numpy中关于数组的用法基本可以直接应用到这两个数据结构,包括数据创建、切片访问、通函数、广播机制等
series是带标签的一维数组,所以还可以看做是类字典结构:标签是key,取值是value;而dataframe则可以看做是嵌套字典结构,其中列名是key,每一列的series是value。所以从这个角度讲,pandas数据创建的一种灵活方式就是通过字典或者嵌套字典,同时也自然衍生出了适用于series和dataframe的类似字典访问的接口,即通过loc索引访问。

数据结构Series

# 是一种类似于一维数组对象,由数据和相关的标签(索引)组成
# 第一种:默认左侧标签是从0开始的索引值
pd.Series([4,5,6,7,8])  
0    4
1    5
2    6
3    7
4    8
dtype: int64

# 第二种:还可以自定义左侧标签值
pd.Series([4,5,6,7,8],index=['a','b','c','d','e'])
a    4
b    5
c    6
d    7
e    8
dtype: int64

# 第三种:字典的key会自动变成左侧标签 值会变成数据
pd.Series({"a":1,"b":2})
a    1
b    2
dtype: int64

# 第四种:快速生成一个数据为0的Series结构
pd.Series(0,index=['a','b','c'])
a    0
b    0
c    0
dtype: int64

缺失值概念

st = {"tony":18,"yang":19,"bella":20,"cloud":21}
obj = pd.Series(st)

tony     18
yang     19
bella    20
cloud    21
dtype: int64
    
# 定义新索引
new_st = {'tony','yang','cloud','jason'}
# 修改原索引  字典有key做左侧标签了又人为指定了索引值
obj1 = pd.Series(st,index=new_st)

jason     NaN
cloud    21.0
yang     19.0
tony     18.0
dtype: float64
    
'''
NaN是一个关键字,就是用来表示缺失值的意思
并且NaN属于浮点类型数据
'''

缺失值处理

dropna()  # 过滤掉值为NaN的行
fillna()  # 填充缺失数据
isnull()  # 返回布尔数组
notnull()  # 返回布尔数组

对数据进行处理返回一个新的结果原数据不变,如果想要直接影响原数据需要加参数inplace=True

布尔选择器

# 布尔值索引使用方式与numpy一致

# 布尔值索引还可以结合逻辑运算符
|&'''注意:逻辑运算符连接的条件最好都加上括号'''
# 筛选出价格大于200小于900的价格
(price>200) & (price<900)

索引

se = pd.Series([111,222,333,444],index=['ab','bc','cd','ef'])
ab    111
bc    222
cd    333
ef    444
dtype: int64
    
price = pd.Series([111,222,333,444],index=[1,2,3,4])
1    111
2    222
3    333
4    444
dtype: int64

# 通过索引值获取元素
se[1]
# 通过左侧标签名获取元素
se['ab']
# 如果左侧标签是数字那么会优先采用左侧标签名获取数据
price[1]
# 获取左侧所有的标签名
se.index
Index(['ab', 'bc', 'cd', 'ef'], dtype='object')
'''在pandas中字符串类型用object表示'''

########################################################
sr = pd.Series(np.arange(6))
0    0
1    1
2    2
3    3
4    4
5    5
res = sr[3:]
3    3
4    4
5    5
# 如果左侧标签是数字那么会优先采用左侧标签名获取数据
res[1]  # 报错

*******************************************
'''自定义取值方式'''
res.loc[3]  # 按照左侧标签名取值
res.iloc[1]  # 按照从0开始的索引值依次往下取值

数据处理

res = pd.Series([11,22,33])
0    11
1    22
2    33
dtype: int64
    
res.iloc[1] = 777  # 修改已经存在的值   
0     11
1    777
2     33
dtype: int64
    
res['a'] = 111  # 如果左侧标签不存在则新增一个
0     11
1    777
2     33
a    111
dtype: int64
    
res.append(pd.Series([99]))  # 纵向合并Series
0     11
1    777
2     33
a    111
0     99
dtype: int64
    
del res[0]
1    777
2     33
a    111
dtype: int64

基本算术运算

"""
.add	加
.sub 减
.mul 乘
.div 除
"""
sr1 = pd.Series([12,23,34], index=['c','a','d'])
c    12
a    23
d    34
dtype: int64
    
sr3 = pd.Series([11,20,10,14], index=['d','c','a','b'])
d    11
c    20
a    10
b    14
dtype: int64
sr1.add(sr3)  # 会按照左侧标签对应做运算,没有对应的直接NaN
a    33.0
b     NaN
c    32.0
d    45.0
dtype: float64
    
    
sr1.add(sr3,fill_value=0)  # 计算之前将没有对应的标签数据设为0

数据结构之DataFrame

表格型数据结构,相当于一个二维数组,含有一组有序的列也可以看作是由Series组成的共用一个索引的字典

第一种:
res = pd.DataFrame({'one':[1,2,3,4],'two':[4,3,2,1]})
第二种:
pd.DataFrame({'one':pd.Series([1,2,3],index=['a','b','c']),'two':pd.Series([1,2,3],index=['b','a','c'])})
第三种:
pd.DataFrame(np.array([[10,20],[30,40]]),index=['a','b'],columns=['c1','c2'])
第四种:
pd.DataFrame([np.arange(1,8),np.arange(11,18)])
第五种:
s1 = pd.Series(np.arange(1,9,2))
s2 = pd.Series(np.arange(2,10,2))
s3 = pd.Series(np.arange(5,7),index=[1,2])
df5 = pd.DataFrame({'c1':s1,'c2':s2,'c3':s3})

"""
以上创建方式都仅仅做一个了解即可
因为工作中dataframe的数据一般都是来自于读取外部excel文件
而不是自己手动去创建
"""

DataFrame常用方法

res = pd.DataFrame(
             np.array([[10,20],[30,40]]),
             index=['a','b'],  # 自定义左侧标签名(行名称)
             columns=['c1','c2'])  # 自定义列名称
	c1	c2
a	10	20
b	30	40

# 获取行索引(左侧标签名)
res.index  # Index(['a', 'b'], dtype='object')

# 获取列名称
res.columns  # Index(['c1', 'c2'], dtype='object')

# 行列互换
res.T  
	a	b
c1	10	30
c2	20	40

# 获取表格中的数据  数组对象
res.values  
array([[10, 20],
       [30, 40]])
# 快速统计(默认只能统计数字)
res.describe()  
res.describe(include='object')  # 指定只统计字符串

数据读取方式1

pd.read_csv(filepath_or_buffer, sep=',', header='infer', names=None, usecols=None, skiprows=None, skipfooter=None, converters=None, encoding=None)
            
filepath_or_buffer:指定txt文件或csv文件所在的具体路径 
sep:指定原数据集中各字段之间的分隔符,默认为逗号”,id	name	income
        1   J		 10
header:是否需要将原数据集中的第一行作为列名称,默认将第一行用作列名称 
        如果原始数据没有表头需要将该参数设置为None 
names:如果原数据集中没有列名称,可以通过该参数在数据读取时给数据框添加具体的列名称 
usecols:指定需要读取原数据集中的哪些变量名 
skiprows:数据读取时,指定需要跳过原数据集开头的行数
         有一些表格开头是有几行文字说明的,读取的时候应该跳过
skipfooter:数据读取时,指定需要跳过原数据集末尾的行数 
converters:用于数据类型的转换(以字典的形式指定) 
encoding:如果文件中含有中文,有时需要指定字符编码

案例

import pandas as pd
data01 = pd.read_csv(r'data_test01.txt',
           skiprows = 2,  	 # python能自动过滤掉完全无内容的空行(写2、3都行)
           sep = ',', 		 # 默认就是逗号 写不写都行 
           skipfooter = 3, 
           )
           
# 1.针对id原本是01、02自动变成了1、2...
converters = {'id':str}

# 2.点击文件另存修改文件编码之后再次读取出现乱码
encoding='utf-8'

# 3.移除收入千分位非逗号的其他符号
thousands = '&'

# 4.手动将文件表头行删除再次读取
header = None  # 默认用索引
names = ['id','year','month','day','gender','occupation','income']

# 5.指定读取的字段
usecols = ['id','income']

数据读取方式2

pd.read_excel(io, sheet_name=0, header=0, skiprows=None, skip_footer=0, index_col=None, names=None,
na_values=None, thousands=None, convert_float=True)

io:指定电子表格的具体路径 
sheet_name:指定需要读取电子表格中的第几个Sheet,既可以传递整数也可以传递具体的Sheet名称 
header:是否需要将数据集的第一行用作表头,默认为是需要的 
skiprows:读取数据时,指定跳过的开始行数
skip_footer:读取数据时,指定跳过的末尾行数 
index_col:指定哪些列用作数据框的行索引(标签)
na_values:指定原始数据中哪些特殊值代表了缺失值 
thousands:指定原始数据集中的千分位符 
convert_float:默认将所有的数值型字段转换为浮点型字段 
converters:通过字典的形式,指定某些列需要转换的形式

pd.read_excel(r'data_test02.xlsx',
              sheet_name='***',
             header = None,
              names = ['ID','Product','Color','Size'], 
             converters = {'ID':str}
             )

数据读取方式3

"""
截至目前为止我们总共学习了三种存储数据的方式
1.文本文件
2.表格文件
3.MySQL数据库
"""
要想读取MySQL里面的数据,首先需要跳过代码连接到MySQL服务端
需要借助于python模块pymysql

下载
!pip3 install pymysql
!conda install pymysql
# 可能会出现报错 切换到国内源

导入使用
import pymysql

# 链接MySQL服务端
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123456',
    database='db3',
    charset='utf8'
)
# 利用pymysql创建好链接MySQL的链接之后即可通过该链接操作MySQL
pd.read_sql('select * from userinfo', con = conn)

数据概览

df = pd.read_csv(r'sec_cars.csv')
# 1.查看表格的前N条数据
df.head(5)  # 不写默认也是五条

# 2.查看表格的后N条数据
df.tail(5)  # 不写默认也是五条

# 3.查看表的行列
df.shape  # 结果是一个元组(行数,列数)

# 4.获取表中所有的列名称
df.columns

# 5.获取表中所有的行索引
df.index

# 6.查看数据的数据类型
df.dtypes  # 在处理数据之前应该用该方法查看一下数据类型

# 7.快速统计
df.describe()  # 默认只会统计数字类型的数据
df.describe(include='object') # 可以通过include参数指定统计的数据类型
df.describe(include='all') 

行列操作

df1 = pd.read_excel(r'data_test02.xlsx',header=None)

# 1.修改列名称
df1.rename(columns={0:'序号'})
df1.rename(columns={0:'序号',1:'类型',2:'颜色',3:'尺码'},inplace=True)
'''
# 能修改 但是会报个错误 可以添加下列配置
pd.set_option('mode.chained_assignment',None)
'''

df1['序号']  # 获取序号列对应的列数据
df1['库存'] = 666  # 加了赋值符号就是设值
 1.如果该列名称存在则修改列数据
 2.如果该列名称不存在则创建新的
df1['测试'] = df1['尺码']*df1['库存']
# 注意:新的列数据可以是直接写死的,也可以是通过其他字段动态计算

df1.insert(0,'插队',6969)
# 还可以控制插入列的位置

数据筛选

# 以二手车为例
# 1.获取列数据
df['Brand']  # 只获取一列数据
df[['Brand','Name','New_price']]  # 获取多列一定要是表格的形式

# 2.获取行数据
df.loc[df['Brand']=='众泰']  # 只有一个条件的
'''逻辑运算符在连接条件的时候 条件都必须加括号'''
df.loc[(df['Brand']=='众泰')&(df['Discharge']=='国4')]

# 3.针对筛选出来的行数据 做列数据的过滤
df.loc[(df['Brand']=='众泰')&(df['Discharge']=='国4'),['Brand','Name']]

数据处理

sec_car = pd.read_csv(r'sec_cars.csv')
sec_car.head()
sec_car.dtypes
# 日期应该是日期类型而不是字符串类型
# 新车价格应该是数字类型而不是字符串类型
sec_car['Boarding_time'] = pd.to_datetime(sec_car['Boarding_time'],
                                         format='%Y年%m月'
                                         )
# 常见的日期符号 %Y %m %d %H %M %S %X
sec_car.dtypes

sec_car.New_price  # 新车价格里面有字符串类型
# 1.需要先将字符串去除(方式1:字符串的替换 方式2:切片操作)
sec_car.New_price.str[:-1]  # 一定要加上关键字str
# 2.之后才能数据类型转换
sec_car.New_price.str[:-1].astype(float)  # astype数据类型转换

sec_car['New_price'] = sec_car.New_price.str[:-1].astype(float)


data = pd.read_excel(r'data_test04.xlsx')
data.head()
# 判断数据是否有重复项
data.duplicated()
# 删除重复的数据项
data.drop_duplicates()

缺失值处理

data05 = pd.read_excel(r'data_test05.xlsx')
# 1.当样本数据量特别多的时候,可以考虑直接删除个别缺失数据
# 2.当缺失数据占比较高的时候不能直接删除,而应该使用填充数据的方式

# 判断是否含有缺失值
data05.isnull()  # 不太好
data05.isnull().any(axis=0)  # 判断列是否有缺失数据
"""
axis=0表示列字段
axis=1表示行索引
"""

# 计算缺失数据的占比
data05.isnull().sum(axis = 0)/data05.shape[1]
# 不能够直接删除缺失数据data05.dropna()
# 也不能一股脑的瞎填充data05.fillna(66)
############################################################
data05.fillna(value = {
  'gender':data05.gender.mode()[0],  # 众数:可以有一个也可能是多个
  'age':data05.age.mean(),  		 # 平均值
  'income':data05.income.median()    # 薪资推荐使用:中位数
}, inplace = True)
############################################################
data05

数据汇总


data06 = pd.read_csv(r'diamonds.csv')

pd.pivot_table(data06, index = 'color', values='price', aggfunc='mean')

pd.pivot_table(data06, 
               index = 'color', 
               columns='clarity', 
               values='price', 
               aggfunc='size')
# 当数据量小于10万 基本上使用常用软件excel SPSS即可操作
# 高于10万之后才可能需要使用代码处理

分组与聚合

# 对颜色进行分组
data06.groupby(by=['color',])  # 按照单个字段分组
# 分组之后如果直接想看结果可以使用groups  粗略的查看
data06.groupby(by=['color',]).groups

# 分组一般都是配合聚合函数一起使用
gg = data06.groupby(by=['color',])  # 先分组
res = gg.aggregate({'color':np.size})  # 再聚合
res

# 可以对多个字段聚合    针对聚合函数最好都用np点出来
res1 = gg.aggregate({'color':np.size,
                     'price':np.mean,
                     'table':np.max
                      })
res1

# 还可以按照多个字段分组
######################################
gg1 = data06.groupby(by=['color','cut'])
res2 = gg1.aggregate({'color':np.size,
                     'price':np.mean,
                     'table':np.max
                    })
res2
######################################
# 调整变量名的顺序
result = pd.DataFrame(res2, columns=['price','color','table'])
result

# 数据集重命名
result.rename(columns={'color':'个数',
                       'price':'均价',
                       'table':'最大面积'}, 
              inplace=True)
result

练习

# pandas中的read_html可以爬取页面上table标签里面的数据
cp = pd.read_html(r'https://baike.baidu.com/item/NBA%E6%80%BB%E5%86%A0%E5%86%9B/2173192?fr=aladdin')
# 结果是一个列表数据类型 我们只需要第一个元素
ch = cp[0]

# 列名称数据处理
ch.columns = ch.loc[0]  # 将第一行数据替换成列名称


# 将第一行数据删除
ch.drop(axis=0,index=0,inplace=True) 
"""
这里规律相反
axis=0表示行
axis=1表示列
如果记不住以后直接先查看该方法的案例提示再操作
"""

# 1.统计每个球队夺冠的次数
cpm = ch.groupby(by=['冠军',])  # 先分组
res = cpm.aggregate({"冠军":np.size})
res.rename(columns={'冠军':'夺冠次数'},inplace=True)
# 对夺冠次数进行排序
res['夺冠次数'].sort_values(ascending=False)
#								降序	

cpm1 = ch.groupby(by=['冠军','FMVP'])
res1 = cpm1.aggregate({
        'FMVP':np.size,
})

数据的纵向合并(添加数据项)

df1 = pd.DataFrame({
  'name':['张三','李四','王二'], 
  'age':[21,25,22], 
  'gender':['男','女','男']}
)
df2 = pd.DataFrame({
  'name':['丁一','赵五'], 
  'age':[23,22], 
  'gender':['女','女']}
)

pd.concat([df1,df2])

pd.concat([df1,df2] , keys = ['df1','df2'])

pd.concat([df1,df2]).reset_index().drop(columns=['index'])
# reset_index 生成一个从0开始的新的索引项

df2 = pd.DataFrame({
  'Name':['丁一','赵五'], 
  'age':[23,22], 
  'gender':['女','女']}
)
****
变量名称必须相同
****

数据的横向合并(链表操作)

"""
dep
    id    name     desc

emp
    id    name     gender     dep_id
    
select * from emp inner join dep on emp.dep_id = dep.id;
"""
df3 = pd.DataFrame({
  'id':[1,2,3,4,5],
  'name':['张三','李四','王二','丁一','赵五'],
  'age':[27,24,25,23,25],
  'gender':['男','男','男','女','女']})
df4 = pd.DataFrame({
  'Id':[1,2,2,4,4,4,5], 
  'score':[83,81,87,75,86,74,88], 
  'kemu':['科目1','科目1','科目2','科目1','科目2','科目3','科目1']})
df5 = pd.DataFrame({
  'id':[1,3,5],
  'name':['张三','王二','赵五'],
  'income':[13500,18000,15000]})


merge1 = pd.merge(left = df3, 
                  right = df4, 
                  how = 'inner', 
                  left_on='id', 
                  right_on='Id')


merge2 = pd.merge(left = merge1, 
                  right = df5, 
                  how = 'left')  # 不指定默认找相同的字段
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值