实 验 目 的:
1、掌握pandas库的series和dataframe的增、删、改、查。
2、掌握灵活获取csv文件中的单元格、行、列数据。
3、掌握pandas的简单绘图。
4、掌握pandas进行数据的清晰。
实 验 环 境:
设备:PC机,建议个人PC,实验室计算机重启后不保留之前实验;
操作系统:Windows
软件:Anaconda3-2020.11-Windows-x86_64.exe(集成开发环境)
编程语言:python
OS:Windows
python:3.8.5
Pyecharts:1.8.1及以上版本
实 验 内 容 及 过 程:
任务一
Pandas提供了两种主要的数据结构Series和DataFrame。两者分别适用于一维和多维数据,是在Numpy的ndarray基础上加入了索引而形成的高级数据结构。
6.1.1 特殊包
导入下面两个包,以免每次运行都出现警告。
import pyecharts
pyecharts.globals._WarningControl.ShowWarning = False
import warnings
warnings.filterwarnings('ignore')
或者读取csv文件的时候进行设置
datacsv2=pd.read_csv("data/2/数据2.csv",encoding="gbk",low_memory=False,index_col="商品")
6.1.2 汉字和负号的设置(重要)
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"]="SimHei"#设置字体,防止中文乱码
plt.rcParams["axes.unicode_minus"]=False #防止负号乱码
6.1.3 Series序列
Series 用于保存一维数据,主要包含index和value。其基本语法如下:
pandas.Series(data=None, index=None, name=None)
参数说明如下:
data:接收array或dict。表示接收的数据。默认为None。
index:接收array或list。表示索引,必须与数据长度相同
name:接收string或list。表示Series对象的名称。默认为None
详细的序列的增删改查合并等操作参考课件。
Series的学习网址:Series — pandas 2.2.3 documentation
6.1.4 DataFrame数据框
DataFrame,,主要包含index、value、columns语法格式如下:
pandas.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)
参数说明如下所示:
data:接收ndarray、dict、list或DataFrame。表示输入数据。默认为None。
index:接收Index,ndarray。表示索引。默认为None。
columns:接收Index,ndarray。表示列标签(列名)。默认为None。
详细的数据框的增、删、改、查、合并、条件选取等操作参考课件。
数据框学习10分钟https://pandas.pydata.org/docs/user_guide/10min.html
6.1.5 pandas读取外部文件
Pandas库读取CSV、Excel等外部文件
详细的pandas读取文件部分的操作参考课件。
6.2 任务二(验证性操作)!
6.2.1 pandas验证操作
1、验证以下代码,并将结果附截图
import pandas as pd
A=[1,3,6,4,9,10,15]
weight=[67,66,83,68,79,88]
sex=['女','男','男','女','男', '男']
S1=pd.Series(A)#构建S1序列
print(S1)
S2=pd.Series(weight)#构建S2序列
print(S2)
S3=pd.Series(sex)#构建S3序列
print(S3)
print(S3[1])#或print(S3.iloc[1]
print(S2[2])#或print(S2.iloc[2])
#Series 提供了两种访问元素的方法:loc(基于标签的索引)和 iloc(基于位置的索引)
2、分别验证S2.loc[1]、S2[1]、S2.iloc[1],并附截图,说明序列变量.loc[i]、序列变量.iloc和序列变量[i]的作用
loc[i]指的是选取列表中标签(索引)为i的数据,而[:]的作用为左闭右闭的选取,而“,”的作用在于是行索引还是列索引
iloc[i]是通过位置去选取数据的,左闭右开,如iloc[1]会返回 Series 中位置为1的值
[i]默认情况下按位置,索引为标签时按标签访问
3、验证以下代码,并结果附截图
import pandas as pd
#以列表的形式传入数据
A=[1,3,6,4,9,10,15]
weight=[67,66,83,68,79,88]
sex=['女','男','男','女','男', '男']
B=pd.concat([S2,S3],axis=0)#一般来说,axis=0都是指行,但是在缺失值处理时指的是列
print(B)
S=pd.concat([S2,S3],axis=1)#按列合并序列,合并后为两列成为数据框
print(S)
print(S.loc[0])#第1行
print(S.iloc[0,:])#第1行
print(S[1])#第2列
print(S.iloc[:,1])#第2列
print(S.iloc[1,0])#第二行,第一列
print(S.loc[1,0])
print(S[0:3])#0,1,2行
print(S.iloc[1:3,0:1])#第1,2行,第0列
X=[1,3,6,4,9,8,6]
X=pd.DataFrame(X)#由列表创建数据框,dataframe有idex,value,columns
print(X)
print(X.loc[1])#默认索引为0,1,2,3,4,由索引号(下标)引用元素
print(X[0])
print(X.iloc[1,0])
4、验证以下代码,并将结果附截图,需要在每行备注上用法,并说明如何让sort_index()生效。
import pandas as pd
#3*7二维数组,有几个元素就有几行
weight=[[88,77,67,66,83,68,79],[880,770,670,660,830,680,790],[8,7,6,6,8,6,7]]
#dataframe框架,加入数据,列名,行索引标签abc
df=pd.DataFrame(weight,columns=['num1','num2','num3','num4','num5','num6','num7'],index=['A','C','B'])
print(df)
print(df.loc['A'])#用索引引用标签为A的数据
print(df.loc[['A','C'],:])#获取索引为 'A' 和 'C' 的行,并且包括所有列
print(df.loc['A':'B','num1':'num7'])#从行 'A' 到 'B' 选择,并选择从 'num1' 到 'num7' 的列(包含所有列)
print("-------")
print(df.iloc[0,:])#位置索引,索引位置为“0”的数据
print(df.iloc[[0,2],:])#位置索引,索引位置为“0”-“1”行,所有列的数据
print(df.iloc[:,0:6])#位置索引,索引所有行,“0”-“5”列的数据
df['weight2']=df['num1']*2#新增一列 weight2,其值为 num1 列的每个值乘以 2
print(df['weight2'])
print(df.iloc[:,1])#所有行,位置为“1”的列
df.sort_index()#按索引index排序
print("-----sort_index without inplace-----")#输出没有修改索引排序的数据
print(df)
df.sort_values(by='weight2',inplace=True)#按weight排序,inplace=True很关键
print("----sort_values------")
print(df)
del df['weight2']#删除'weight2'这一列
print("-----del-----")
print(df)
思考1:什么时候需要:inplace=True
何时使用 inplace=True
?
你通常需要在以下几种情况中使用 inplace=True
:
-
节省内存:
如果你希望修改原始数据框而不需要返回一个新的副本,可以使用inplace=True
来节省内存。对于大型数据集,避免创建不必要的副本可以提高性能。 -
直接修改数据框:
当你不需要原始数据框,而是希望直接修改它时,使用inplace=True
是一个简便的选择。这样你可以直接在原数据框上进行更改,而不必通过赋值操作来创建新的数据框。 -
避免重复赋值:
如果你不想将修改后的结果赋值给一个新变量或原变量,那么使用inplace=True
会使得操作更简洁。
常见的使用 inplace=True
的场景
-
删除列或行:
df.drop(columns=['num1'], inplace=True)
这将删除
df
中的num1
列,而不会返回新的数据框。 -
排序数据框:
df.sort_values(by='num1', inplace=True)
这将按
num1
列排序数据框,并直接修改df
。 -
重置索引:
df.reset_index(drop=True, inplace=True)
这将重置索引,并且删除原来的索引列(通过
drop=True
),直接修改df
。 -
替换缺失值(NaN):
df.fillna(0, inplace=True)
这将用
0
填充df
中的缺失值,操作会修改原始数据框。
不使用 inplace=True
时的行为:
当你不使用 inplace=True
,函数通常会返回一个新的数据框,你需要将其赋值给原变量或另一个变量:
df = df.sort_values(by='num1')
在这种情况下,df
会被修改,并赋值为排序后的数据框。
总结:
- 使用
inplace=True
可以直接修改原始数据框,避免生成新的副本,节省内存。 - 不使用
inplace=True
会返回一个新的数据框,适用于你需要保留原始数据框的情况。
你可以根据需求选择是否使用 inplace=True
,但要注意,使用 inplace=True
会直接修改原始数据,因此确保你不会丢失重要的数据。如果需要保留原数据框,最好不要使用 inplace=True
思考2:删除操作的drop和del有什么差别
在 Python 中,drop
和 del
都可以用来删除对象或数据结构中的元素,但它们有一些关键的区别,尤其是在与 Pandas 数据框(DataFrame
)打交道时。
1. drop
操作
drop
是 Pandas 中专门用于删除行或列的方法。
用法:
- 删除行或列时,
drop
返回一个新的数据框,并不会修改原始数据框,除非你指定inplace=True
。 - 它适用于删除行或列,并且支持更复杂的操作(例如按标签删除,支持多个列或行的删除等)。
示例:
import pandas as pd # 创建数据框 df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9]}) # 删除一列 df2 = df.drop('B', axis=1) # 删除列 'B' # 删除一行 df3 = df.drop(0, axis=0) # 删除第一行 print(df2) print(df3)
axis=1
表示删除列,axis=0
表示删除行。- 如果要修改原数据框,可以使用
inplace=True
:
df.drop('B', axis=1, inplace=True)
特点:
drop
支持删除多个行或列。- 可以选择删除行或列,灵活性较强。
- 默认不会修改原数据框,除非使用
inplace=True
。
2. del
操作
del
是 Python 的内置语句,用于从命名空间中删除对象。在 Pandas 中,它通常用于删除列或行,但它的应用范围不仅限于 Pandas,适用于所有 Python 数据类型。
用法:
del
用于删除 Python 变量或对象。- 当用于删除 Pandas 数据框的列时,它会直接修改原数据框,而不会返回新的数据框。
del
不能删除行,它只能删除列(因为数据框的列是 Pandas 数据框的属性)。
示例:
import pandas as pd # 创建数据框 df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9]}) # 删除一列 del df['B'] # 直接删除列 'B' print(df)
特点:
del
会直接修改原数据框,并且不能用来删除行。- 删除列时,
del
是直接操作,而不像drop
那样返回一个新的数据框。 del
删除的是数据框的列,无法像drop
一样按标签删除行。
总结
特点 | drop | del |
---|---|---|
适用范围 | 删除行或列 | 仅用于删除列 |
是否返回新对象 | 默认返回新对象,inplace=True 才直接修改原数据框 | 直接修改原数据框,不返回新对象 |
能否删除行 | 可以(使用 axis=0 ) | 不行,不能删除行 |
操作灵活性 | 支持删除多个行或列,可以选择轴 axis | 只能删除单列 |
是否修改原数据框 | 不修改原数据框,除非 inplace=True | 修改原数据框 |
- 如果你希望灵活地删除行或列,并且控制是否修改原数据框,
drop
是更常用的选择。 - 如果只是单纯删除列并且不需要返回新数据框,
del
可以简洁地完成任务。
5、验证以下代码,并将结果附截图
import pandas as pd
datacsv=pd.read_csv("Bsdata.csv")
# Bsdata.csv文件是研究生开课信息调查表从2600名学生按2%抽样52名调查情况
#r表示当前路径,文件可以从超星下载
print(datacsv.head())
#用pandas读取csv文件实例
datacsv.info()#输出结构信息
h=list(datacsv.身高)
print(h)
print(datacsv.身高.max())
print(datacsv.身高.min())
print(datacsv.loc[1])
print(datacsv.iloc[1,0])
print(datacsv.iloc[1:3,2:3])
print(datacsv.shape) #显示数据框的行数和列数
print(datacsv.shape[0]) #数据框行数
print(datacsv.shape[1]) #数据框列数
import pandas as pd
#pd.read_csv() 是 Pandas 中用来读取 CSV 文件的函数。它将 CSV 文件加载到一个 Pandas DataFrame
# Bsdata.csv文件是研究生开课信息调查表从2600名学生按2%抽样52名调查情况
datacsv=pd.read_csv("Bsdata.csv")
#datacsv.head() 返回 DataFrame 的前 5 行(默认情况下)
#用pandas读取csv文件实例
print(datacsv.head())
#datacsv.info() 输出数据集的基本信息,如:数据框的行数和列数,每列的数据类型,每列的非空值数量。
datacsv.info()
#使用 list() 将这一列转换为 Python 的列表(list 类型),并赋值给变量 h
h=list(datacsv.身高)
print(h)
print(datacsv.身高.max())
print(datacsv.身高.min())
print(datacsv.loc[1])
print(datacsv.iloc[1,0])
#第二和第三行的第三列数据
print(datacsv.iloc[1:3,2:3])
#(4)数据框维度
print(datacsv.shape) #显示数据框的行数和列数
print(datacsv.shape[0]) #数据框行数
print(datacsv.shape[1]) #数据框列数
6、验证以下代码,并将结果附截图,销售流水记录tmp.csv文件可在超星上下载。
import pandas as pd
datacsv=pd.read_csv('销售流水记录tmp.csv',index_col=2,usecols=['create_dt','order_id','sku_id','sku_name','sku_prc','sku_sale_prc','sku_cost_prc'])
print(len(datacsv))
datacsv.info()
datacsv.head()
datacsv['sku_sale_prc']=datacsv['sku_sale_prc'].astype(float)
datacsv.reset_index()
datacsv[['create_dt','sku_sale_prc']].groupby('create_dt').agg(sum)
import pandas as pd
#pandas.read_csv来读取CSV文件,指定了:
#index_col=2:将CSV文件的第三列(order_id)作为行索引。
#usecols:只选择指定的几列进行读取,避免加载不必要的列。
datacsv=pd.read_csv('销售流水记录1.csv',index_col=2,usecols=['create_dt','order_id','sku_id','sku_name','sku_prc','sku_sale_prc','sku_cost_prc'])
#len(datacsv):输出数据集的行数。
#datacsv.info():输出数据集的基本信息,如列名、数据类型和缺失值情况。
#datacsv.head():显示数据的前五行。
print(len(datacsv))
datacsv.info()
datacsv.head()
#将sku_sale_prc列的值转换为浮动类型
datacsv['sku_sale_prc']=datacsv['sku_sale_prc'].astype(float)
#将原来的索引(即order_id)重置为默认的整数索引。如果你不打算保存旧的索引,这行代码可以忽略inplace=True
datacsv.reset_index()
#选取了create_dt和sku_sale_prc两列,然后按create_dt(日期)进行分组,并对sku_sale_prc进行求和。agg(sum)指定了对每个组应用求和操作
datacsv[['create_dt','sku_sale_prc']].groupby('create_dt').agg(sum)
7、验证以下代码,并将结果附截图。
datacsv = pd.read_csv(r'销售流水记录tmp.csv', index_col=[0,1],low_memory=False,encoding='gb18030')#读取指定列,1,2列为索引
datacsv.info()
#pd.read_csv 来读取 CSV 文件,并指定了以下几个参数:
#index_col=[0,1]:表示将文件中的第 0 列和第 1 列作为索引。
#low_memory=False:避免内存优化,在处理大文件时能够提高处理准确性。
#encoding='gb18030':指定文件的编码格式为 gb18030,适合读取包含中文字符的文件。
datacsv = pd.read_csv(r'销售流水记录2.csv', index_col=[0,1],low_memory=False,encoding='gb18030')#读取指定列,1,2列为索引
# datacsv.info() 将返回一个关于数据框(DataFrame)的总结信息,包括:
# 数据框的类型:例如 pandas.DataFrame。
# 行数:即数据框的总行数。
# 列数:数据框中所有列的数量。
# 每列的数据类型:每列的数据类型(例如 int64, float64, object 等)。
# 缺失值:每列中非空(非NaN)值的数量。
datacsv.info()
8、验证以下代码,并将结果附截图。
datacsv = pd.read_csv(r'销售流水记录tmp.csv', usecols=["create_dt","order_id","sku_id","sku_name"], nrows=10)
datacsv.info()
datacsv.head(2)
datacsv.sku_name
# usecols=["create_dt","order_id","sku_id","sku_name"]: 这表示只读取 CSV 文件中的这四列:create_dt, order_id, sku_id 和 sku_name。
# nrows=10: 这会读取文件的前 10 行数据
datacsv = pd.read_csv(r'销售流水记录2.csv', usecols=["create_dt","order_id","sku_id","sku_name"], nrows=10,encoding='gb18030')
# datacsv.info():返回 DataFrame 的摘要信息,包括数据框的大小、列的类型、每列的非空值数量等。
# datacsv.head(2):返回 datacsv 数据框中的前两行数据。
# datacsv.sku_name:返回 datacsv 数据框中名为 sku_name 的列
datacsv.info()
datacsv.head(2)
datacsv.sku_name
9、验证以下代码,并将结果附截图,people.csv可在超星上下载。
import pandas as pd
datacsv=pd.read_csv(r'people.csv',names=["年度","Z","Z0_14","Z15_64","Z65_"],header=None,skiprows=1,index_col=0)#指定列标题
#"年度","Z","Z0_14","Z15_64","Z65_"为列标题,skiprows表示跳过第1行,index_col=0年度(第1列)作为时间序列索引,绘图作为x周
print(datacsv)
datacsv.columns.tolist()
import pandas as pd
#header=None:告诉 Pandas 数据文件本身没有列标题行,而是通过 names 参数手动设置列名
#skiprows=1:跳过 CSV 文件中的第一行,这通常用于跳过文件中的非数据行
#index_col=0:将 CSV 文件中的第一列(即 "年度" 列)设置为数据的行索引,这样就将年度作为时间序列的索引
datacsv=pd.read_csv(r'people.csv',names=["年度","Z","Z0_14","Z15_64","Z65_"],header=None,skiprows=1,index_col=0)#指定列标题
#"年度","Z","Z0_14","Z15_64","Z65_"为列标题,skiprows表示跳过第1行,index_col=0年度(第1列)作为时间序列索引,绘图作为x周
print(datacsv)
#datacsv.columns 返回一个列索引对象,其中包含数据框的所有列名称。
#tolist() 将列索引转换为 Python 列表形式
datacsv.columns.tolist()
10、利用people.csv文件验证以下代码,并将结果附截图
print(datacsv[datacsv['年度']>'2008'])#提取年度大于2008年的数据
print(datacsv[(datacsv['年度']>'2008')&(datacsv['年度']<'2018')])
#逻辑运算符与、或用&、|表示
import pandas as pd
#header=None:告诉 Pandas 数据文件本身没有列标题行,而是通过 names 参数手动设置列名
#skiprows=1:跳过 CSV 文件中的第一行,这通常用于跳过文件中的非数据行
#index_col=0:将 CSV 文件中的第一列(即 "年度" 列)设置为数据的行索引,这样就将年度作为时间序列的索引,但是这里'年度' 被设置为索引了,而不是列。所以你不能像普通列那样直接访问它
#如:使用 .index 来访问并进行筛选
#print(datacsv[datacsv.index > 2008]) # 使用索引进行比较
#print(datacsv[(datacsv.index > 2008) & (datacsv.index < 2018)])
#或者删除index_col=0
datacsv=pd.read_csv(r'people.csv',names=["年度" ,"Z","Z0_14","Z15_64","Z65_"],header=None,skiprows=1)
#指定列标题
#"年度","Z","Z0_14","Z15_64","Z65_"为列标题,skiprows表示跳过第1行,index_col=0年度(第1列)作为时间序列索引,绘图作为x周
print(datacsv[datacsv['年度']>'2008'])#提取年度大于2008年的数据
print(datacsv[(datacsv['年度']>'2008')&(datacsv['年度']<'2018')])
6.2.2 pandas工具包绘图
pandas包学习网址:Chart visualization — pandas 2.2.3 documentation
1、读取people.csv文件,指定列标题为"年度","Z","Z0_14","Z15_64","Z65_",利用pandas绘制年度与年末总人口折线图,并附截图,参考代码如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
datacsv=pd.read_csv('people.csv',names=["年度","Z","Z0_14","Z15_64","Z65_"],header=None,skiprows=1,index_col=0)
plt.rcParams['font.family']=['STSong']
plt.rcParams['font.size']=16
plt.rcParams['axes.unicode_minus']=False
datacsv['Z'].plot(xlabel='年度',ylabel='年末总人口(万人)',figsize=(10,6),alpha=0.5)
2、利用pandas绘制年度与年末总人口、0-14岁人口折线图,并附截图,参考代码如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
datacsv=pd.read_csv('people.csv',names=["年度","Z","Z0_14","Z15_64","Z65_"],header=None,skiprows=1,index_col=0)
plt.rcParams['font.family']=['STSong']
plt.rcParams['font.size']=16
plt.rcParams['axes.unicode_minus']=False
datacsv[['Z','Z0_14']].plot(xlabel='年度',ylabel='年末总人口(万人)',figsize=(10,6))
3、利用pandas绘制年度与各年龄阶段人口变化折线对比图,并附截图,参考代码如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
datacsv=pd.read_csv('people.csv',names=["年度","Z","Z0_14","Z15_64","Z65_"],header=None,skiprows=1,index_col=0)
plt.rcParams['font.family']=['STSong']
plt.rcParams['font.size']=16
plt.rcParams['axes.unicode_minus']=False
datacsv.plot(xlabel='年度',ylabel='年末总人口(万人)',figsize=(10,6))
4、利用pandas绘制年度与各年龄阶段人口变化对比复式柱状图,并附截图,参考代码如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
datacsv=pd.read_csv('people.csv',names=["年度","Z","Z0_14","Z15_64","Z65_"],header=None,skiprows=1,index_col=0)
plt.rcParams['font.family']=['STSong']
plt.rcParams['font.size']=16
plt.rcParams['axes.unicode_minus']=False
datacsv.plot(kind='bar',xlabel='年度',ylabel='年末总人口(万人)',figsize=(15,6))
5、提取csv文件Bsdata.csv中的身高和体重,利用DataFrame.plot绘制折线图和散点图。
import matplotlib.pyplot as plt
import pandas as pd
plt.style.use('seaborn')
plt.rcParams["font.sans-serif"]=['SimHei']#设置字体,防止中文乱码
plt.rcParams["axes.unicode_minus"]=False #防止负号乱码
# 引入matplotlib字体管理 FontProperties
# from matplotlib.font_manager import FontProperties
# 设置我们需要用到的中文字体(字体文件地址)
# my_font = FontProperties(fname=r"c:\windows\fonts\SimHei.ttf", size=12)
datacsv=pd.read_csv("Bsdata.csv")
plt.rcParams['font.sans-serif'] = ['SimHei']
datacsv["身高"].plot()#折线图
datacsv["体重"].plot(color="r")#折线图
plt.rcParams['font.sans-serif'] = ['SimHei']
datacsv.plot.scatter(x='身高',y="体重",color="r")#散点图
#提取csv文件Bsdata.csv中的体重,利用DataFrame.plot绘制直方图。
plt.rcParams['font.sans-serif'] = ['SimHei']
datacsv["体重"].hist(color="r")
#提取csv文件Bsdata.csv的开设情况,利用DataFrame.plot绘制开设统计分类柱状图。
# T=datacsv.开设.value_counts()#针对分类数据或定性数据统计
# T.plot(kind='bar')
import matplotlib.pyplot as plt
import pandas as pd
plt.style.use('seaborn')
plt.rcParams["font.sans-serif"]=['SimHei']#设置字体,防止中文乱码
plt.rcParams["axes.unicode_minus"]=False #防止负号乱码
# 引入matplotlib字体管理 FontProperties
# from matplotlib.font_manager import FontProperties
# 设置我们需要用到的中文字体(字体文件地址)
# my_font = FontProperties(fname=r"c:\windows\fonts\SimHei.ttf", size=12)
datacsv=pd.read_csv("Bsdata.csv")
plt.rcParams['font.sans-serif'] = ['SimHei']
datacsv["身高"].plot()#折线图
datacsv["体重"].plot(color="r")#折线图
plt.rcParams['font.sans-serif'] = ['SimHei']
datacsv.plot.scatter(x='身高',y="体重",color="r")#散点图
#提取csv文件Bsdata.csv中的体重,利用DataFrame.plot绘制直方图。
plt.rcParams['font.sans-serif'] = ['SimHei']
datacsv["体重"].hist(color="r")
#提取csv文件Bsdata.csv的开设情况,利用DataFrame.plot绘制开设统计分类柱状图。
# T=datacsv.开设.value_counts()#针对分类数据或定性数据统计
# T.plot(kind='bar')
7.3. 作业
实验的每一步都需要截图,养成良好的习惯,也是给自己做了一份很好的笔记。
数据源:数据1.csv和数据2.csv
- 读取无人售货机数据
在商场不同地点安放了5台自动售货机,编号分别为A、B、C、D、E。数据1提供了从2017年1月1日至2017年12月31日每台自动售货机的商品销售数据,数据2提供了商品的分类。现在要对两个表格中的数据进行合并。
- 使用pandas中的read_csv函数分别读取数据。
- 使用pandas中的merge函数或者join方法进行数据合并
- 保存合并后的结果
# (1)使用pandas中的read_csv函数分别读取数据。
# (2)使用pandas中的merge函数或者join方法进行数据合并
# (3)保存合并后的结果
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
sale=pd.read_csv('数据1.csv',encoding='gb18030')
categlories=pd.read_csv('数据2.csv',encoding='gb18030')
merged=pd.merge(sale,categlories,on="商品",how='inner')
merged.to_csv('12data_inner_merged.csv',encoding='gb18030')
2.对1中合并的数据进行数据校验、清洗,如重复值校验与处理、异常值校验与处理、缺失值校验与处理。对每一步的操作都做出说明分析。
- 查找重复记录并进行删除
- 查找异常数据,并在箱线图中绘制处理,最后对异常数据进行删除
- 查找缺失值并进行处理(删除、填充等)。
- 保存处理后的数据
import pandas as pd
import matplotlib.pyplot as plt
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 1. 读取CSV文件,指定编码
def load_data(file_path):
"""加载数据并指定编码"""
df = pd.read_csv(file_path, encoding='gb18030')
return df
# 2. 查找并删除重复记录
def remove_duplicates(df):
"""查找并删除重复记录"""
duplicate_count = df.duplicated().sum()
print(f"重复记录的数量: {duplicate_count}")
# 删除重复记录
df = df.drop_duplicates()
return df
# 3. 查找并处理异常值(箱线图与IQR法)
def remove_outliers(df, columns):
"""查找并删除异常值"""
for column in columns:
if column in df.columns:
# 确保该列是数字类型,强制转换为数字
df[column] = pd.to_numeric(df[column], errors='coerce')
# 如果列中有 NaN 值,填充为该列的均值(或者其他适合的填充值)
df[column].fillna(df[column].mean(), inplace=True)
# 绘制箱线图
plt.figure(figsize=(8, 6))
df[column].plot(kind='box', vert=False, patch_artist=True)
plt.title(f'箱线图 - {column}')
plt.show()
# 使用 IQR 法查找异常值
Q1 = df[column].quantile(0.25)
Q3 = df[column].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 统计异常值的数量
outliers = df[(df[column] < lower_bound) | (df[column] > upper_bound)]
print(f"列 '{column}' 中的异常值数量: {outliers.shape[0]}")
# 删除异常值
df = df[(df[column] >= lower_bound) & (df[column] <= upper_bound)]
return df
# 4. 查找并处理缺失值(删除或填充)
def handle_missing_values(df, columns, fill_value=None):
"""查找并处理缺失值"""
for column in columns:
if column in df.columns:
missing_count = df[column].isnull().sum()
print(f"列 {column} 中的缺失值数量: {missing_count}")
if missing_count > 0:
if fill_value is not None:
# 填充缺失值(用给定的值填充)
df[column].fillna(fill_value, inplace=True)
print(f"列 {column} 的缺失值已用 {fill_value} 填充")
else:
# 删除缺失值
df = df.dropna(subset=[column])
print(f"列 {column} 的缺失值已删除")
return df
# 5. 清洗数据的主函数
def clean_data(file_path, fill_missing_value=None):
"""加载并清洗数据"""
# 读取数据
df = load_data("12data_inner_merged.csv")
# 处理重复记录
df = remove_duplicates(df)
# 处理异常值(根据IQR法)
df = remove_outliers(df, ['应付金额', '实际金额'])
# 处理缺失值
df = handle_missing_values(df, ['应付金额', '实际金额'], fill_missing_value)
# 保存处理后的数据
output_file = 'cleaned_data.csv'
df.to_csv(output_file, encoding='gb18030', index=False)
print(f"清洗后的数据已保存到: {output_file}")
return df
# 示例:使用上面的函数来清洗数据
cleaned_data = clean_data(file_path, fill_missing_value=0) # 例如用0填充缺失值
3.针对数据1
- 绘制出每个月的订单量的柱状图,用pandas进行绘图展示(要求添加标题、X轴和Y轴名称)
- 绘制出每个月的销售额变化情况折线图,用pandas进行绘图展示(要求添加标题、X轴和Y轴名称)
- 绘制出A类自动售货机中商品名称为”怡宝纯净水”的商品,12个月中每个月的订单量饼图,用pandas进行绘图展示(要求添加标题、饼图按照订单量进行排序展示)
4.对五类自动售货机的实付金额数据,分别绘制出箱线图。
# (1)绘制出每个月的订单量的柱状图,用pandas进行绘图展示(要求添加标题、X轴和Y轴名称)
# (2)绘制出每个月的销售额变化情况折线图,用pandas进行绘图展示(要求添加标题、X轴和Y轴名称)
# (3)绘制出A类自动售货机中商品名称为”怡宝纯净水”的商品,12个月中每个月的订单量饼图,用pandas进行绘图展示(要求添加标题、饼图按照订单量进行排序展示)
# (4)对五类自动售货机的实付金额数据,分别绘制出箱线图。
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 假设 df 是你的订单数据 DataFrame
# 示例数据加载
# 使用此行代码加载数据文件(假设是CSV文件)
df = pd.read_csv('数据1.csv', encoding='gb18030')
# 确保订单日期是 datetime 类型
df['订单日期'] = pd.to_datetime(df['支付时间'], errors='coerce')
# 删除无效日期
df = df.dropna(subset=['订单日期'])
# 提取月份,转换为字符串类型
df['月份'] = df['订单日期'].dt.to_period('M').astype(str)
# 确保 '实际金额' 列是数值类型,非数值的会变为 NaN
df['实际金额'] = pd.to_numeric(df['实际金额'], errors='coerce')
# 删除 '实际金额' 列中的 NaN 值
df = df.dropna(subset=['实际金额'])
#(1)绘制每个月的订单量柱状图
monthly_orders = df.groupby('月份')['商品'].count()
plt.figure(figsize=(10, 6))
monthly_orders.plot(kind='bar', color='skyblue')
plt.title('每个月的订单量')
plt.xlabel('月份')
plt.ylabel('订单量')
plt.xticks(rotation=45)
plt.show()
#(2)绘制每个月的销售额变化情况折线图
monthly_sales = df.groupby('月份')['实际金额'].sum()
plt.figure(figsize=(10, 6))
monthly_sales.plot(kind='line', color='green', marker='o')
plt.title('每个月的销售额变化情况')
plt.xlabel('月份')
plt.ylabel('销售额')
plt.xticks(rotation=45)
plt.grid(True)
plt.tight_layout()
plt.show()
#(3)绘制A类自动售货机中商品名称为"怡宝纯净水"的商品,12个月中每个月的订单量饼图
df_filtered = df[(df['地点'] == 'A') & (df['商品'] == '怡宝纯净水')]
monthly_order_quantity = df_filtered.groupby('月份')['实际金额'].sum()
# 按订单量排序
monthly_order_quantity_sorted = monthly_order_quantity.sort_index() # 按月份排序
plt.figure(figsize=(10, 10))
monthly_order_quantity_sorted.plot(kind='pie', autopct='%1.1f%%', startangle=90)
plt.title('怡宝纯净水每个月的订单量')
plt.ylabel('') # 去掉y轴标签
plt.show()
#(4)绘制五类自动售货机的实付金额箱线图
fig, ax = plt.subplots(figsize=(15, 9))
# 绘制箱线图
df.boxplot(column='实际金额', by='地点', patch_artist=True, ax=ax)
# 添加标题和标签
ax.set_title('五类自动售货机的实付金额分布')
ax.set_xlabel('地点')
ax.set_ylabel('实际金额')
# 去掉默认的标题
plt.suptitle('')
# 显示图形
plt.show()
感兴趣的可以私聊我拿数据练练手。