一、为什么要学习pandas
numpy已经可以帮助我们处理数据,能够结合matplotlib进行数据分析,那学习pandas的目的又是什么呢?numpy只能够帮我们处理数值型的数据,但这还不够。很多时候,我们处理的数据中除了数值型的数据,还有字符串、时间序列等等,这个时候就需要使用pandas来处理这些特殊类型的数据。当然了pandas是基于numpy的,也可以处理数值型的数据
二、什么是pandas
引用官方文档的一句话:
pandas is an open source, BSD-licensed library providing high-performence, easy-to-use data structures and data analysis tools for the Python programming language.
pandas是BSD许可的开源库,为Python编程语言提供了高性能,易于使用的数据结构和数据分析工具
三、pandas常用数据类型
- Series:一维,带标签的数组,标签也就是索引
- DataFrame :二维,Series容器,一列是一个Series
四、Series一维容器
1、创建Series
import pandas as pd
# 创建时传入可迭代对象即可
s1 = pd.Series(range(10, 20)) # 不指定索引,索引默认从0开始递增
s2 = pd.Series(range(6), index=list("ABCDEF")) # 指定索引
也可通过字典创建Series,键为索引,对应的值为数据
# 字典创建
temp_dict = {'name': 'wang', 'age': 20, 'tel':10010, 'like':'sleep'}
s3= pd.Series(temp_dict) # 键为索引,对应的值为数据
2、索引和切片
通过索引取值
name = s3["name"]
age = s3["age"]
tel = s3["tel"]
通过位置取连续的值
name, age = s3[0:2]
like = s3[3]
age, tel, like = s3[1:]
取不连续的值(方括号嵌套方括号的形式)
s3[[0,2]] # 获取0行和2行
s3[["name", "like"]]) # 获取name行和like行
布尔索引
s = pd.Series(range(10, 20))
s < 13 # s中数值小于13的返回True,大于等于13的返回False
s[s < 13] # bool索引,返回值小于13的行组成的Series
s.where(s > 13, 100) # s中小于等于13的替换为100
s.where(s > 13) # 返回Series对象,其中值大于13保持原值,小于等于13的变成NaN
index和values的相关操作
temp_dict = {'name': 'wang', 'age': 20, 'tel':10010, 'like':'sleep'}
s3= pd.Series(temp_dict) # 键为索引,对应的值为数据
name, age, tel, like = s3.index # 返回索引,pandas.core.indexes.base.Index类型的对象
s3.values # 返回values,numpy.ndarray类型的对象
len(s3.index) # 获取可迭代对象长度
len(s3.values)
list(s3.index) # 可迭代对象转换为列表
list(s3.values)
五、DataFrame (二维容器)
DataFrame是二维的,有index(横向索引)和column(纵向索引),对应axis=0和axis=1,不指定索引也是默认从0递增
1、创建DataFrame
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.arange(12).reshape(3,4), index=list("abc"), columns=list("wxyz"))
print(df1)
df1 如下:
通过字典创建DataFrame
temp_dict = {'name': ['wang', "zhang"], 'age': [20, 34], 'tel':[10010,10086]}
df2 = pd.DataFrame(temp_dict) # 键为索引,对应的值为数据
通过列表创建DataFrame
temp_list = [{'name': 'wang', 'age': 20, 'tel':10086},{'name': 'huang', 'tel':10086},{'name': 'wang','like':'sleep', 'tel':10086}]
df2 = pd.DataFrame(temp_list)
df2 如下:
可以看到,若有的数据没有对应的列则用NaN(Not a Number)表示
2、DataFrame的基础属性
- df.shape # 返回行数和列数
- df.dtypes # 返回列数据类型
- df.index # 返回行索引
- df.column # 返回列索引
- df.values # 返回数据值,不包含索引
- df.info() # 返回相关信息,行数、列数、列非空个数、列类型、内存占用等
- df.describe() # 快读统计综合结果,计数、均值、标准差、最大最小值等
- df.head(3) # 返回数据的前3行,默认5行
- df.tail(3) # 返回数据的后3行,默认5行
df2["age"].argmax() # 指定列最大值的索引
df2["age"].argmin() # 指定列最小值的索引
df2["age"].max() # 指定列最大值
df2["age"].min() # 指定列最小值
df2["age"].median() # 指定列中位数
df2["age"].mean() # 指定列平均值
df2["hobby"] # 获取hobby列
3、索引和切片
df1 如下:
loc通过 标签 获取数据
df1.loc["a"] # 取a行
df1.loc["a",:] # 取a行,同上
df1.loc["W"] # 报错,只能取行,不能取列
df1.loc[:,"W"] # 取W列
df1.loc["a","W"] # 取a行和W列相交的元素
df1.loc[["a", "b"]] # 取a列和b行
df1.loc[["a","b"], :] # 取a行和b行,同上
# 取a行、c行和W列、Y列相交的4个元素,在numpy中只能取出两个元素
df1.loc[["a", "c"], ["W", "Y"]]
df1.loc["a":"c", ["W"]] # 使用loc进行切片索引时,最后一个c是可以选中的,从a到c,和w列相交的3个数据
iloc通过 位置 获取数据
df1.iloc[1,:] # 取第1行数据
df1.iloc[:,1:] # 取第1列以及往后的所有数据
# 取1行、2行和2列、2列相交的4个元素,若在numpy中取得是df1[1][2]和df1[2][3]
df1.iloc[[1,2],[2,3]]
df1.iloc[:,[0,2]] # 取第0列和第2列
# 把0行和1行赋值成NaN,在numpy中直接赋值会报错,应转换为float
df1.iloc[:2] = np.nan
注意区分:
df1[0] # 获取第0列
df1.loc[0] # 获取第0行
df1.iloc[0] # 获取第0行
4、关于缺失值的处理
-
isnull():值为NaN的数据则返回True,否则返回False
-
notnull():值为NaN的数据则返回False,否则返回True
-
dropna():删除DataFrame中含有NaN行
- axis参数:可选0、1,表示删除谋和轴的NaN
- how参数:可选all、any,all表示删除全为NaN的行,any表示删除含有
NaN的行
-
fillna():用其他值填充NaN
df2 如下:
pd.isnull(df2) # NaN返回True
pd.notnull(df2) # NaN返回False
df2[pd.notnull(df2["hobby"])] # 选取hobby列不为NaN的所在行
df2.dropna(axis=0, how="all") # 删除0轴全为NaN的行
df2.dropna(axis=0, how="any") # 删除0轴有NaN的行
df2.dropna(axis=0, how="any", inplace=True) # 原地修改
# 用df2每一列的均值(不算NaN)填充对应列的NaN,pandas计算比numpy计算智能
df2.fillna(df2.mean()) # 用数字列的平均值填充改列的NaN
df2["age"] = df2["age"].fillna(df2["age"].mean()) # 用age列的平均值填充age列的NaN
六、pandas常用方法
- contains 返回表示各字符串是否含有指定模式的布尔型数组
- count 模式的出现次数
- endswith, startswith 相当于对各个元索执行x.endswith(pattern)或 x.startswith(pattern)
- findall 计算各字符串的模式列表
- get 获取各元素的第i个字符
- join 根据指定的分隔符将Series中各元索的字符串连接起来
- len 计算各字符串的长度
- lower, upper 转换大小写,相当于对各个元素执行x.lower()或x.upper()
- match 根裾指定的正则表达式对各个元素执行re.match
- pad 在字符串的左边、右边或左右两边添加空白符
- center 相当于pad(side=_both)
- repeat 重复值,例如,s.str.repeat(3)相当于对各个字符串执行x*3
- replace 用指定字符串替换找到的裉式
- slice 对Series中的各个字符串进行子串截取
- split 根据分隔符或正则表达式对字符串进行拆分
- strip, rstrip, Istrip 去除空白符,包括换行符.相当于对各个元索执行x.strip()、 x.rstrip(), x.lstrip()
七、案例
分析狗名字的使用次数
数据来源:https://www.kaggle.com/new-york-city/nyc-dog-names/data
首先读取CSV文件,并打印数据有关信息,以便后续操作
file_path = './dogNames2.csv'
df = pd.read_csv(file_path)
print(df.head())
print("-"*100)
print(df.info())
通过打印的信息,我们得到相关信息如下
查看被用得最多的前10个狗名字以及使用次数
这时我们得先按照名字被使用的次数降序排列,然后取前10行
df = df.sort_values(by="Count_AnimalName", ascending=False)
print(df.iloc[:10])
得到名字以及使用次数:
获取使用次数在区间[800,1000]内的名字
print(df[(df["Count_AnimalName"]>=800) & (df["Count_AnimalName"]<=1000)]["Row_Labels"])
获取名字长度大于10的数据
print(df[df["Row_Labels"].str.len()>10])