numpy
一、创建ndarray
import numpy as np
print(np.__version__)
1. 使用np.array()由python list创建
import numpy as np
n1 = np.array([1,2,3,4,5])
print(n1)
print(type(n1))
2. 使用np的函数创建
1. np.ones(shape, dtype=None, order=’C’)
- 生成由1组成的数组
- shape可以指定数字或元祖
import numpy as np
n1 = np.ones(shape = (2,3),dtype=np.int16)
print(n1)
2. np.zeros(shape, dtype=float, order=’C’)
- 生成由0组成的数组
- shape可以指定数字或元祖
import numpy as np
n1 = np.zeros(shape=(4,5),dtype=np.int16)
print(n1)
3. np.full(shape, fill_value, dtype=None, order=’C’)
- 生成自定义填充内容的数组
- shape可以指定数字或元祖
- fill_value指定填充内容,格式为数字
import numpy as np
n1 = np.full(shape = (3,5),fill_value=9,dtype=int)
print(n1)
4. np.eye(N, M=None, k=0, dtype=float)
- 对角线为1其他的位置为0
- N,M指定行数列数
- k代表偏移值,为正右偏移,为负左偏移
import numpy as np
n1 = np.eye(5,5,-1)
print(n1)
5. np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
- 对一个数值区间进行等分
- start,stop起始值
- num等分的份数
- endpoint是否使用末尾值
- retstep是否显示步长
import numpy as np
n1 = np.linspace(0,100,20)
print(n1)
6. np.arange([start, ]stop, [step, ]dtype=None)
- 生成一个等差数列
- start,stop起始值
- step步长默认为1
import numpy as np
n1 = np.arange(0,100,10)
print(n1)
7. np.random.randint(low, high=None, size=None, dtype=’l’)
- 在一个指定的数值区间内生成随机整数的数组
- low,high最大值最小值
- size数组样式,可以为数字或数组
import numpy as np
n1 = np.random.randint(10,20,size = 10)
print(n1)
8.np.random.random(size=None)
- 生成0到1的随机数
import numpy as np
n1 = np.random.random(size = 10)
print(n1)
9. np.random.randn(d0, d1, …, dn)
- 生成标准正态分布的样本集
- 标准正太分布 np.random.normal()
import numpy as np
n1 = np.random.randn(4,4)
print(n1)
二、ndarray属性
- ndim : 维度(数组每次新增的轴,也就是最外围的维度,都为 0,也就是axis = 0都是新增的维度)
- shape : 形状
- size : 数组元素的个数
- dtype : 元素类型
1)int
(整数):包括 8-64 位的长度;
2)float
(浮点数):包括 16-64 位的长度;
3)unit
(无符号整数):包括 8-64 位的长度;
4)bool
(布尔类型)。
import numpy as np
n1 = np.array([[1,2,3,4,5,6],[10,11,12,13,14,15]])
print(n1.ndim,n1.shape,n1.size,n1.dtype)
三、操作
1. 索引
下标索引
import numpy as np
l1 = [[1,2,3,4,5],[10,11,12,13,14]]
n1 = np.array(l1)
#两种方法等效
print(n1[0][0])
print(n1[0,0])
布尔索引
import numpy as np
l1 = [[1,2,3,4,5],[10,1,12,13,14]]
n1 = np.array(l1)
# 通过数组的逻辑运算后,我们得到的结果是一个与原数组维度和长度都一样的布尔数组
print(n1<3)
# 布尔索引即通过一个布尔数组来索引目标数组,找出目标数组中与布尔数组中值为 True 的对应的数据
print(n1[n1<3])
注意:符合条件的元素会以一维数组的形式返回,通过布尔索引,我们可以很快找出数组中满足既定条件的部分元素。
2. 切片
import numpy as np
n2 = np.arange(10)
print(n2)
print(n2[-3:])
print(n2[::-1])
print(n2[4:7])
n3 = np.ones(shape = (5,5),dtype=np.int16)
print(n3)
print(n3[-3:,-1:])
print(n3[:,2:4])
print(n3[:,::-1])
3. 变形
- n1.reshape()
- 传入一个元祖
- 改变的size必须和原size相同
import numpy as np
n4 = np.random.randint(100,150,size = 24).reshape((5,5))
print(n4)
print(n4.shape)
- 参数-1为自动计算
- 不能两个参数都为-1
import numpy as np
n4 = np.random.randint(100,150,size = 24).reshape((4,-1))
print(n4)
print(n4.shape)
4. 级联
np.concatenate()
级联需要注意的点:
- 级联的参数是列表:一定要加中括号或小括号
- 维度必须相同
- axis方向对应的形状可以不相符
- 级联的方向默认是shape这个tuple的第一个值所代表的维度方向
- 可通过axis参数改变级联的方向
函数 | 说明 | 备注 |
---|---|---|
np.concatenate((n1,n2),axis=None) | 级联 | # axis指定级联方向取值0 or 1 |
np.hstack((n1,n2)) | 水平级联 | \ |
np.vstack((n1,n2)) | 垂直级联 | \ |
n1 = np.ones(shape = (2,3),dtype=np.int16)
print(n1)
n2 = np.zeros(shape=(2,3),dtype=np.int16)
print(n2)
print(np.concatenate((n1,n2),axis=0))
5. 切分
函数 | 说明 |
---|---|
np.split | 切分 |
np.vsplit | 竖向切分 |
np.hsplit | 横向切分 |
x = np.array([0,1,2,3,4,5,6,7,8])
print(np.split(x,3))
6. 副本
n2 = n1.copy()
四、方法
函数 | NaN-safe Version | 说明 |
---|---|---|
n1.sum() | np.nansum() | 求和 |
n1.max() | np.nanmax() | 求最大值 |
n1.min() | np.nanmin() | 求最小值 |
n1.mean() | np.anmean() | 求平均数 |
n1.argmax() | np.nanaremax() | 最大值的索引 |
n1.argmin() | np.nanargmin() | 最小值的索引 |
np.prod() | np.nanprod() | 连乘 |
np.std() | np.nanstd() | 方差 |
import numpy as np
x = np.array([10,11,12,13,14])
print(x.sum())
五、向量运算
1.形状相同时
两个数组 a 和 b 形状相同,即满足a.shape == b.shape
时
import numpy as np
# 创建数组 a
a = np.array([[0, 0, 0],
[10, 10, 10],
[20, 20, 20]])
# 创建数组 b
b = np.array([[0, 0, 0],
[10, 10, 10],
[20, 20, 20]])
# 加法
result_1 = a + b
print(result_1)
# 乘法
result_2 = a*b
print(result_2)
2.形状不同时(广播机制)
广播:两个形状不同数组间运算时,它们对应维度的长度必须相同,或者其中一方为 1,才可以运算成功,否则就会报错。
#【重要】ndarray广播机制的两条规则
#规则一:为缺失的维度补1
#规则二:假定缺失元素用已有值填充
import numpy as np
# 创建数组 a
a = np.array([1, 2, 3])
# 创建标量 b
b = 2
# 数组 a 与标量 b 相乘,并将结果赋值给 result_3
result_3 = a*b
print(result_3)
import numpy as np
# 创建数组 a
a = np.array([[0, 0, 0],
[10, 10, 10],
[20, 20, 20],
[30, 30, 30]])
print(a.shape)
# 创建数组 b
b = np.array([0, 1, 2])
print(b.shape)
result_4 = a + b
print(result_4)
六、排序
函数 | 说明 | 备注 |
---|---|---|
n.sort() | 快速排序 | np.sort()不改变输入 |
np.sort(n) | 快速排序 | ndarray.sort()本地处理,不占用空间,但改变输入 |
np.partition(a,k) | 部分排序 | 当k为正时,我们想要得到最小的k个数 当k为负时,我们想要得到最大的k个数 |
import numpy as np
# 创建数组 a
a = np.array([1, 7, 3])
print(np.sort(a))
# 没有改变原数据
print(a)
print(a.sort())
# 改变原数据
print(a)
Pandas
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
一、Series
Series是一种类似与一维数组的对象,由下面两个部分组成:
- values:一组数据(ndarray类型)
- index:相关的数据索引标签
1. Series的创建
1. 由列表或numpy数组创建
l2 = np.array([150,150,150,300])
s1 = Series(data = l2,index = ['语文','数学','英语','理综'])
print(s1)
还可以通过设置index参数指定索引
#默认索引为0到N-1的整数型索引
s1 = Series(np.arange(0,6,1),index = list('abcdef'))
print(s1)
s1.index = list('abcdef')
print(s1.index)
特别地,由ndarray创建的是引用,而不是副本。对Series元素的改变也会改变原来的ndarray对象中的元素。(列表没有这种情况)
# 列表
n1 = [1,2,3,4,5]
s1 = Series(n1)
print(s1)
n1[0] = 100
print(s1)
# numpy数组
n2 = np.array([10,11,12,13,14,15])
s2 = Series(n2)
print(s2)
n2[0] = 100
print(s2)
2. 由字典创建
- Key作为index,value作为values
d1 = {'语文':150,'数学':150,'英语':150,'理综':300}
s1 = Series(d1)
print(s1)
- 必须传入一维的数据,多维会报错
# 多维的数组 error
n1 = np.random.randn(3,2)
Series(n1)
2. Series的索引和切片
1. 索引
可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的仍然是一个Series类型)。分为显示索引和隐式索引:
(1) 显式索引:
- 使用index中的元素作为索引值
s1 = Series(data = [1,2,3,4,5],index = list('ABCDE'))
print(s1['A'])
print(s1.loc['A'])
(2) 隐式索引:
- 使用整数作为索引值
s1 = Series(data = [1,2,3,4,5],index = list('ABCDE'))
print(s1.iloc[0])
d1 = {'yuwen':150,'shuxue':150,'yingyu':150,'lizong':300}
s8 = Series(d1)
s8.index = ['理综','数学','英语','语文']
print(s8['数学'],s8.loc['数学'],s8.iloc[1])
2. 切片
a1 = np.array([1,2,3,4,5])
print(a1[1:3])
s1 = Series(data = [1,2,3,4,5],index = list('ABCDE'))
print(s1['A':'D'])
print(s1.loc['A':'D'])
# 使用.iloc[]注意,此时是右开区间
print(s1.iloc[0:4])
3. Series属性和方法
可以把Series看成一个定长的有序字典
可以通过shape、size、index、values等得到series的属性
可以使用
head()
、tail()
分别查看前n个和后n个值(当索引没有对应的值时,可能出现缺失数据显示NaN(not a number)的情况)
s1 = Series(data = [1,2,3,4,5,6,7],index = list('abcdefg'))
print(s1.head())
print(s1.tail())
- 可以使用
pd.isnull()
,pd.notnull()
,或自带isnull()
,notnull()
函数检测缺失数据
# 返回的仍然是一个Series对象
s.isnull()
s.notnull()
- 求和函数
s1 = Series(data = [1,2,3,4],index = list('abcd'))
print(np.sum(s1))
4. Series的运算
- 适用于numpy的数组运算也适用于Series
- Series之间的运算
- 在运算中自动对齐不同索引的数据
- 如果索引不对应,则补NaN
- NaN和任何数运算,结果都为NaN
s1 = Series(data = [1,2,3,4],index = list('abcd'))
s2 = Series(data = [5,6,7,8],index = list('cdef'))
s = s1 + s2
print(s)
print(s.isnull())
print(s.notnull())
我在这里补充一下
Series和列表类型都是用来装一列一维数据的容器,但其不仅运算速度快很多,也提供了很多方便的方法,做数据运算更加有效率,我们先来看看如果让列表中每个元素相加。
list1 = [1, 2, 3, 4]
list2 = [5, 6, 2, 3]
list_new = []
# 直接相加是列表的拼接
# list_new = list1 + list2
# print(list_new)
# 实现列表中的每一个元素相加
for i in range(len(list1)):
list_new.append(list1[i] + list2[i])
print(list_new)
再看看Series是如何实现的,提供了哪些方法。
n1 = np.array([np.nan,2,3,4])
n2 = np.array([3,4,3,np.nan])
s1 = Series(n1)
s2 = Series(n2)
s1.add(s2,fill_value = 0) #加
s1.sub(s2,fill_value = 0) #减
s1.mul(s2,fill_value = 1) #乘
s1.div(s2,fill_value = 1) #除
#fill_value在元素中包nan时所替代的值
5.Series数据处理
import pandas as pd
series = pd.Series([1, 2, 3, 4])
# 使用 add 方法将每个元素加1
result = series.add(1)
print(result)
series = pd.Series(["Hello", "World", "!"])
# 使用 str.cat 方法将每个元素拼接成一个字符串
result = series.str.cat(sep=" ")
print(result)
data = pd.Series(['ABC123', 'DEF456', 'GHI789'])
# 使用正则表达式提取部分字符
pattern = r'(\d+)' # 提取连续的数字
extracted_data = data.str.extract(pattern)
print(extracted_data)
二、DataFrame
DataFrame是一个【表格型】的数据结构,可以看做是【由Series组成的字典】(共用同一个索引)。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。
- 行索引:index
- 列索引:columns
- 值:values(numpy的二维数组)
1. DataFrame的创建
- 最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。
- 字典中的键所对应的值的长度是一样的,不然会报错。
- 此外,DataFrame会自动加上每一行的索引(和Series一样)。
- 同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。
- DataFrame属性:values、columns、index、shape
通过字典创建
dic1 = {'name':['dancer','lucy','mery'],'age':[19,19,20],'address':['beijing','shanghai','guangzhou']}
# columns 列索引
df1 = DataFrame(data = dic1,index = [0,1,2])
print(df1)
dic1 = {'张三':[150,150,150,300],'李四':[0,0,0,0]}
indexs = ['语文','数学','英语','理综']
df1 = DataFrame(data = dic1,index = indexs)
print(df1)
通过numpy.ndarray创建
data = np.random.randint(0,150,size = 5*5).reshape((5,5))
index = ['dancer','lucy','mery','tom','jack']
columns = ['python','c++','c#','php','java']
df2 = DataFrame(data = data, index = index, columns = columns)
print(df2)
# 这里做一个实验,DataFrame的一列或者一行其实就是一个Series
print(type(df2))
print(type(df2['python']))
print(type(df2.loc['dancer']))
通过Series创建
s1 = Series(data = np.arange(0,10,1),index = list('abcdefghij'))
s1 = DataFrame(s1)
print(s1)
通过多维列表创建
data = [[150,0],[150,0],[150,0],[300,0]]
columns = ['张三','李四']
indexs = ['语文','数学','英语','理综']
df = DataFrame(data = data,columns = columns,index = indexs)
print(df)
注意:DataFrame的一列或者一行其实就是一个Series,Series可以看作一维的DataFrame。
2.DataFrame的索引
dic1 = {'张三':[120,130,140,300],'李四':[0,0,0,0]}
indexs = ['语文','数学','英语','理综']
df1 = DataFrame(data = dic1,index = indexs)
# 列索引返回的Series拥有原DataFrame相同的索引,且name属性就是相应的列名。
# 通过类似字典的方式
print(df1['张三'])
# 通过属性的方式
print(df1.张三)
# 行索引只支持loc或iloc方法进行索引
# 行索引返回一个Series,index为原来的columns。
# loc只能是显式索引
# iloc只能是隐式索引
print(df1.loc['数学'])
print(df1.iloc[3])
# 对元素索引
print(df1.loc['语文']['张三'])
print(df1.iloc[0]['张三'])
print(df1.loc['语文'].张三)
# 直接用中括号切片,[行切片,列切片]
print(df1.iloc[1:3,:1])
data = np.random.randint(0,150,size = (5,5))
columns = ['小明','小芳','小花','小红','小蔡']
indexs = ['语文','数学','英语','思想品德','社会']
df = DataFrame(data = data, columns = columns, index = indexs)
# 索引
print(df['小花'])
print(df.loc['语文'])
print(df.iloc[:,2:3])
# 赋值
df.loc['语文']['小明'] += 100
print(df)
# 求平均值
print(df.loc['社会'].mean())
print(df['小花'].mean())
# 副本
xiaoming = df['小明'].copy()
print(xiaoming)
df['小明'] = df['小花']
print(df)
3.DataFrame的级联
n1 = np.random.randint(0,100,25).reshape(5,5)
df1 = DataFrame(n1)
print(df1)
n2 = np.random.randint(0,100,36).reshape(6,6)
df2 = DataFrame(n2)
print(df2)
df3 = pd.concat((df1,df2),axis=1)
print(df3)
三、Pandas文件读写
1.读取
pandas提供了一些用于将表格型数据读取为DataFrame对象的函数,期中read_csv和read_table这两个使用最多
file = pd.read_csv("movie_data.csv")
print(file)
file = pd.read_json('movie_data.json')
print(file)
# sheet_name可以指定工作表
file = pd.read_excel('movie_data.xlsx')
print(file)
注意:如果读出来乱码,可能是编码问题,可选参数 encoding
,常用编码utf-8
2. 写入
data = np.random.randint(0,150,size = (100,5))
df = DataFrame(data = data,columns=['python','c++','oc','java','php'])
# index默认为True,会默认把行索引也写入到文件
df.to_excel('score.xlsx',encoding = 'utf-8',index = False)
注意点
在以下的案例中,pd.read_csv
在读取的时候给我们又重新生成一个从 0 开始的整数索引,但是我们并不需要新的index,我们就希望存进去的时候什么样,读出来就什么样,你可以通过index_col
指定哪一列为index。
import pandas as pd
from pandas import Series,DataFrame
data = [[150,0],[150,0],[150,0],[300,0]]
columns = ['张三','李四']
indexs = ['语文','数学','英语','理综']
df = DataFrame(data = data,columns = columns,index = indexs)
print(df)
df.to_csv('123.csv',encoding='utf-8')
file = pd.read_csv('123.csv',encoding='utf-8',index_col=0)
print(file)
3.读写sqlite文件
- vscode可以安装sqlite插件
import sqlite3 as sqlite3
# 跟数据库建立连接
connection = sqlite3.connect('./db.sqlite')
# 读取数据库文件
data = pd.read_sql("select* from movie_data",connection)
print(data)
# 写入数据库
print(data.to_sql("score_data",connection,if_exists="replace"))
四、pandas数据处理
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
分组聚合
数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。
数据分类处理:
- 分组:先把数据分为几组
- 用函数处理:为不同组的数据应用不同的函数以转换数据
- 合并:把不同组得到的结果合并起来
数据分类处理的核心:
- groupby()函数
- groups属性查看分组情况
方法 | 作用 |
---|---|
min() | 最小值 |
max() | 最大值 |
std() | 标准差 |
mean() | 平均值 |
median() | 中位数 |
sum() | 总和 |
count() | 数量 |
value_count() | 频数分布 |
grade_df = pd.DataFrame({'班级': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
'性别': ['男', '男', '女', '女', '女', '男', '男', '男', '女', '女'],
'眼镜': ['是', '否', '是', '否', '是', '是', '是', '否', '否', '否'],
'成绩': [95, 90, 96, 92, 94, 85, 87, 80, 81, 86]})
print(grade_df)
# 单层分组聚合
# 对班级进行分组聚合操作
# 分组操作 聚合操作
grade_df1 = grade_df.groupby('班级')['成绩'].mean()
print(grade_df1)
# 多分层分组聚合
grade_df3 = grade_df.groupby(['班级', '性别'])['成绩'].mean()
print(grade_df3)
grade_df4 = grade_df.groupby(['性别', '班级'])['成绩'].mean()
print(grade_df4)
df = DataFrame({'item':['苹果','香蕉','橘子','香蕉','橘子','苹果','苹果'],
'price':[4,3,3,2.5,4,2,2.8],
'color':['red','yellow','yellow','green','green','green','yello'],
'weight':[12,20,50,30,20,44,37]})
print(df)
# 可以通过groups属性查看分组情况,但是不要企图用DataFrame的方式展示数据
print(df.groupby('item').groups)
# 一般是进行聚合操作处理后在查看结果,这里展示查看总和的聚合操作
print(df.groupby('item').sum())
# 对weight求总和
weight_sum = DataFrame(df.groupby('item')['weight'].sum())
print(weight_sum)
# 求价格的平均值
price_mean = DataFrame(df.groupby('item')['price'].mean())
print(price_mean)
# 把总和跟df进行merge合并
# 'left_on'和'right_on'指定了左侧和右侧数据框中用于连接的列
result1 = pd.merge(df,weight_sum,how='outer',left_on='item',right_on='item',suffixes=['','_total'])
print(result1)
# 把平均价格合并到总表里
result2 = pd.merge(result1,price_mean,how='outer',left_on='item',right_index=True,suffixes=['','_mean'])
print(result2)
使用列表进行多列分组,得到的结果是多层级索引
df = DataFrame(df.groupby(['item','color'])['weight'].max())
print(df)
练习:
以属性为列索引,创建一个DataFrame对象df
对df进行聚合操作,求出颜色为绿色的价格总和
对df进行聚合操作,求出萝卜的所有重量(包括白萝卜,胡萝卜,青萝卜)以及平均价格
使用merge合并总重量及平均价格
df1 = DataFrame({'item':['萝卜','白菜','冬瓜','辣椒','冬瓜','白菜','萝卜','辣椒'],
'price':[4,3,3,2.5,4,2,2.8,3.5],
'color':['red','yellow','yellow','green','green','green','red','yellow'],
'weight':[12,20,50,30,20,44,37,25]})
print(df1)
sum = df1.groupby('color')['price'].sum()
print(sum)
weight_sum = df1.groupby('item')['weight'].sum()
price_mean = df1.groupby('item')['price'].mean()
print(weight_sum,price_mean)
# 先跟总重量合并
r1 = pd.merge(df1,DataFrame(weight_sum),how='outer',left_on='item',right_index=True,suffixes=['','_sum'])
# 跟平均价格合并
r2 = pd.merge(r1,DataFrame(price_mean),how='outer',left_on='item',right_index=True,suffixes=['','_mean'])
print(r2)
数据清洗
有两种丢失数据:
- None
None是Python自带的,其类型为python object。因此,None不能参与到任何计算中。 - np.nan(NaN)
np.nan是浮点类型,能参与到计算中。但计算的结果总是NaN。
但可以使用np.nan()函数来计算nan,此时视nan为0。
方法 | 作用 |
---|---|
df.info() | 查看摘要信息 |
df.describe() | 查看描述信息 |
df.isna()/df.notnull() && df.isnull() /df.notnull() | 查找缺失值 |
df.dropna(subset=[‘列名’]) | 如果有缺失值,删除整行(可指定操作的列) |
df.duplicated() | 查找重复值 |
df.drop_duplicates() | 删除重复值 |
df.fillna() | 填充缺失值 |
df.sort_values(by=’列名’) | 对某列数据进行排序 |
df.astype(int/str) | 数据类型转换 |
查看描述信息
# 使用describe()函数查看每一列的描述性统计量
df1.describe()
print(df1.describe().loc['mean','rate'])
数据类型转换
data = pd.DataFrame({
'姓名':['林某某', '许放羊', '王鱼'],
'语文': [87, 82, 67],
'数学':[73, 85, 90],
'英语':['89', '95', '95']
})
# 计算每个人三门科目的总分
data['总分'] = data['语文'] + data['数学'] + data['英语'].astype(int)
print(data)
练习
# 总额 = 单价 x 数量
data = pd.DataFrame({
'商品名':['猪头皮', '醋', '高压锅'],
'单价': [10, 13, 800],
'数量':['5', '2', '1']
})
data['总额'] = data['单价'] * data['数量'].astype(int)
print(data)
数据筛选
data = pd.DataFrame({
'姓名':['林某某', '许放羊', '王鱼'],
'语文': [87, 82, 67],
'数学':[73, 85, 90],
'英语':['89', '95', '95']
})
# 筛选语文大于80的
data = data[(data['语文']>80)]
print(data)
删除重复元素
使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True
- 使用drop_duplicates()函数删除重复的行
- 使用duplicate()函数查看重复的行
data = {'name':['dancer','lucy','mery','dancer','jack','dancer'],'score':[100,98,78,100,87,100]}
score = DataFrame(data)
print(score)
# keep指定保留第一个还是最后一个,first保留第一个,last保留最后一个
# inplace True:修改数据的原始结构,Fasle不修改原始结构,产生新数据
# subset表示要对哪些列进去去重,如果不写默认为第一列
score1 = score.drop_duplicates(keep='last',inplace=False,subset=['name','score'])
print(score1)
过滤掉没用的行
data = {'Name': ['John', 'Alice', 'Bob'],
'Age': [25, 30, 35],
'Email': ['john@123.com', 'alice@example.com', 'bob@example.com']}
df = pd.DataFrame(data)
# 使用正则表达式过滤字符串
pattern = r'example' # 过滤包含"example"的字符串
filtered_data = df[df['Email'].str.contains(pattern)]
print(filtered_data)
过滤掉每一行中没用的字符串
# 创建示例DataFrame
data = {'Name': ['John', 'Alice', 'Bob'],
'Age': [25, 30, 35],
'Email': ['john@example.com', 'alice@example.com', 'bob@example.com']}
df = pd.DataFrame(data)
# 使用正则表达式提取特定部分
pattern = r'(\w+)@' # 提取@符号之前的部分
df['Email'] = df['Email'].str.extract(pattern, expand=False)
print(df)
综合练习
df = DataFrame(data = np.random.randint(5,150,size = 5*5).reshape((5,5)),columns=list('ABCDE'))
df['A'][0] = np.nan
df['E'].loc[1] = np.nan
df['B'] = np.nan
print(df)
# axis=0:index/行,axis=1:columns/列,默认为行
# how='all'表示一行中全为空才过滤,'any'表示有一个为空就过滤整行
df1 = df.dropna(axis=1,how='all')
print(df1)
# 对缺失的数据补0
df2 = df.fillna(0)
print(df2)
# 对指定列补指定的值
df3 = df.fillna({"A":10,"B":20})
print(df3)
# 用前面的值来填充,axis可以控制填充的方向
df4 = df.ffill(axis=1)
print(df4)
# 用后面的值来填充
df5 = df.bfill(axis=1)
print(df5)
替换
replace()函数:替换元素
- 单值替换
- 普通替换
- 字典替换(推荐)
- 多值替换
- 列表替换
- 字典替换(推荐)
单值替换
s1 = Series(['dancer',100,'susan','?',np.nan],index=list('12345'))
print(s1)
s2 = s1.replace(to_replace='dancer',value='DANCER')
print(s2)
替换数字
s1 = Series(['dancer',100,'susan','?',np.nan],index=list('12345'))
print(s1)
s2 = s1.replace(100,500)
print(s2)
替换空值
在Series里面,None值无法进行替换,np.nan是可以被替换和识别的
s1 = Series(['dancer',100,'susan','?',np.nan],index=list('12345'))
print(s1)
s2 = s1.replace(np.nan,'空值')
print(s2)
使用字典替换
s1 = Series(['dancer',100,'susan','?',np.nan],index=list('12345'))
print(s1)
s2 = s1.replace(to_replace={'dancer':'DANCER'})
print(s2)
以后值替换
s2 = Series(data = [100,100,100,98,76],index=list('ABCDE'))
# method:对指定的值使用相邻的值填充,指定填充的方向,ffill是前面的值,bfill是后面的值
# limit 指定填充次数
# 注意:不要在使用value参数 method和limit参数不能在DataFrame中使用
sn = s2.replace(to_replace=100,method='bfill',limit=1)
print(sn)
列表替换
s1 = Series(['dancer',100,'susan','?',np.nan],index=list('12345'))
# 第一个列表是要替换的目标值
# 第二个列表是要替换的新值
# 注意:两个列表长度要匹配
sn = s1.replace(['dancer','susan',np.nan],['DANCER','SUSAN','空值'])
print(sn)
DataFrame替换操作
- 单值替换
- 普通替换
- 按列指定单值替换{列标签:替换值}
- 多值替换
- 列表替换
- 单字典替换(推荐)
data = np.random.randint(0,150,size = (5,5))
columns = ['Python','Java','C#','C++','PHP']
df = DataFrame(data = data, columns=columns)
print(df)
df['Python'] = ['优秀','优秀','不及格','不及格','中等']
df.loc[2] = None
df.loc[1,'PHP'] = '?'
print(df)
# 指定列索引替换
# df.replace(to_replace=np.nan,value=100)
# 第一个参数是一个字典,描述了要替换的值,键表示列名称,值表示要替换的目标值
# 第二个参数要替换的新数据
dn = df.replace({'Java':np.nan},100)
print(dn)
# 普通替换(不改变原数据)
# 搜寻整个表格当中与to_replace匹配的值,使用value进行替换
dn = df.replace(to_replace='?',value='未知数')
dn = df.replace(to_replace='优秀',value='一般')
print(dn)
# 列表替换
# 列表替换同Series的列表替换
df.replace(['优秀',np.nan,'?'],['一般','缺失','未知'])
# 做替换操作时,往往会创建一个范围比较大的字典
# None可以用作字典的键
# 在DataFrame的替换中,None可以匹配None和np.nan
# 在使用的时候要注意None 或np.nan的有效性
map_dic = {'aaa':'AAA','不及格':'有故事',np.nan:'123空值'}
df.replace(map_dic)
注意:DataFrame中,无法使用method和limit参数
练习:
假设张三李四的课表里有满分的情况,老师认为是作弊,把所有满分的情况(包括150,300分)都记0分,如何实现?
data = np.array([[150,139,120],[150,300,143],[300,120,87]])
column = ['语文','数学','物理']
index = ['张三','李四','王老五']
df = DataFrame(data = data, columns=column,index=index)
print(df)
map_dic = {150:0,300:0}
dfn = df.replace(map_dic)
print(dfn)
练习
import pandas as pd
data_7 = pd.DataFrame({'性别':['难', '女', '难', '女', '女'],
'城市':['.', '潮州市', '山头市', '汕尾市', '山头市'],
'年龄':[25, 26, 24, 25, 26],
'爱好':['蓝球', '跑步', '跳舞', '逛街', '读书']})
fix_typo = {'山头市':'汕头市', '蓝球':'篮球'}
# 对全部列的错字进行修改
data_7 = data_7.replace(fix_typo)
print(data_7)
fix_typo = {'山头市':'汕头市', '蓝球':'篮球'}
# 只对【城市】列的错字进行修改
data_7['城市'] = data_7['城市'].replace(fix_typo)
data_7['性别'] = data_7['性别'].replace({'难':'男'})
data_7['城市'] = data_7['城市'].replace({'.':'未知'})
print(data_7)
rename()函数:替换索引
使用rename()函数替换行索引
data = np.random.randint(0,150,size=(5,5))
columns = ['python','c','java','php','c++']
index = ['dancer','lucy','mery','tom','jack']
score = DataFrame(data = data,columns=columns, index=index)
print(score)
# 替换列索引,指定columns参数
name_dic = {'java':'JAVA','python':'PYTHON','c':'C','c++':'C加加','php':'PHP',
'dancer':'DANCER','lucy':'LUCY','mery':'MERY','tom':'TOM','jack':'JACK'}
df = score.rename(columns=name_dic)
print(df)
# 替换行索引,指定index参数
name_dic = {'java':'JAVA','python':'PYTHON','c':'C','c++':'C加加','php':'PHP',
'dancer':'DANCER','lucy':'LUCY','mery':'MERY','tom':'TOM','jack':'JACK'}
df = score.rename(index=name_dic)
print(df)
- level 指定多维索引的维度
# 使用level参数来控制替换的索引层级
mul_df.rename(columns = mul_dic,level = 1)
映射
映射的含义:创建一个映射关系列表,把values元素和一个特定的标签或者字符串绑定
map()函数:新建一列
- map(字典) 字典的键要足以匹配所有的数据,否则出现NaN
- map()可以映射新一列数据
- map()中可以使用lambd表达式
- map()中可以使用方法,可以是自定义的方法
注意 map()中不能使用sum之类的函数,for循环
data = [['dancer',190,200,135],['lucy',136,230,129],['Tom',99,87,135]]
columns = ['name','python','Java','C']
df = DataFrame(data=data,columns=columns)
print(df)
# 键值对一般要保证够用,不然会出现空值
number_list = {'dancer':'01','lucy':'02','tom':'03','Tom':'04'}
df['number'] = df['name'].map(number_list)
print(df)
# 使用字典进行匹配的方式
level_list = {190:'优秀',136:'良好',99:'一般'}
df['level'] = df['python'].map(level_list)
print(df)
data = [['dancer',190,200,135],['lucy',136,230,129],['Tom',99,87,135]]
columns = ['name','python','Java','C']
df = DataFrame(data=data,columns=columns)
print(df)
# 修改一列的值,使用函数
# 注意,不能使用sum这种使用循环实现的函数
def add_score(item):
return item+10
df['python'] = df['python'].map(add_score)
print(df)
# 使用lambda表达式
lambda x : x+10
df['Java'] = df['Java'].map(lambda item : item-10)
print(df)
transform()函数
和map()类似
def transform_func(item):
return item+10
df['python'] = df['python'].transform(transform_func)
练习:
新增两列,分别为张三、李四的成绩状态,如果分数低于90,则为”failed”,如果分数高于120,则为”excellent”,其他则为”pass”
【提示】使用函数作为map的参数
data = [['张三',93],['李四',67],['王五',130]]
score = DataFrame(data = data,columns=['name','python'])
print(score)
def transform_score(item):
if item < 90:
return 'failed'
elif item < 120:
return 'passed'
else:
return 'excellent'
score['成绩'] = score['python'].map(transform_score)
print(score)
agg()函数
import pandas as pd
foods_df = pd.DataFrame({
'食品名': ['肚脐饼', '水晶饺', '擂茶', '肚脐饼', '擂茶'],
'单价': [2, 10, 12, 4, 20],
'数量': [20, '-', 35, 37, '-'],
'城市': ['潮州', '汕尾', '梅州', '深圳', '深圳']
})
# 将【数量】列的“-”统一替换为 0;
def replace_info(data):
if data == '-':
data = 0
return data
foods_df['数量'] = foods_df['数量'].agg(replace_info)
print(foods_df)
# 同时计算【单价】列的最小值和【数量】列的最大值
print(foods_df.groupby('食品名').agg({'单价': 'min', '数量': 'max'}))
排序
take排序
# take()函数接受一个索引列表,用数字表示
# axis指定维度,axis=0是index,axis=1是column,别忘了column也可以通过隐藏索引012
# axis=1的时候,可以列表长度可以少于列数,但是axis=0不行
data = [['dancer',190,200,135],['lucy',136,230,129],['Tom',99,87,135]]
columns = ['name','python','Java','C']
df = DataFrame(data=data,columns=columns)
print(df)
df = df.take([0,2,1])
print(df)
#可以借助np.random.permutation()函数随机排序
df = df.take(np.random.permutation(3))
print(df)
# sort_values排序
# ascending是否按照从小到大
df = df.sort_values(by='python',ascending=False)
sort_values排序
import pandas as pd
humans_df = pd.DataFrame({
'姓名': ['小猿', '小马', '小鱼', '小猫', '小龙'],
'身高': ['165', '170', '160', '172', '178'],
'体重': [56, 45, 60, 40, 70]
})
# sort_values排序
# ascending是否按照从小到大
# 数字字符串也可以进行排序
df = humans_df.sort_values(by='身高',ascending=False)
print(df)
# 只想提取出'身高'列,单独进行排序
df = df['身高'].sort_values(ascending=False)
print(df)
# 重置数据行索引
# drop是否保留原索引,默认False
df = df.reset_index(drop=True)
print(df)
seaborn
import seaborn as sns
import matplotlib.pyplot as plt
from pandas import Series,DataFrame
import pandas as pd
from faker import Faker
import random
f = Faker(locale='zh_CN')
class_list = ['1班','2班','3班']
woman_list = []
for i in range(50):
woman_list.append({
'sex':'woman',
'name':f.name(),
'height': random.randint(150,170),
'weight': random.randint(40,60),
'class': random.choice(class_list)
})
man_list = []
for i in range(50):
man_list.append({
'sex':'man',
'name':f.name(),
'height': random.randint(160,180),
'weight': random.randint(50,70),
'class': random.choice(class_list)
})
student_list = woman_list + man_list
student_df = DataFrame(data=student_list)
print(student_df)
# 设置中文字体
plt.rcParams['font.family'] = 'Microsoft YaHei'
# 散点图
sns.relplot(x='height', y='weight', data=student_df)
# 可选参数hue,该参数通过图中的不同颜色表示不同含义,可以让我们在图中添加一个维度
sns.relplot(x='height', y='weight', data=student_df,hue='sex')
# 可选参数 size,它会根据传入数据的大小在散点图中生成大小不同的点
sns.relplot(x='height', y='weight', data=student_df,hue='sex',size='weight')
# 可选参数是style,它可以在某一维度上,用点的不同形状区分数据
sns.relplot(x='height', y='weight', data=student_df,hue='sex',size='weight',style='class')
# 折线图
sns.relplot(x='height', y='weight', data=student_df,kind='line')
# 直方图 kind默认为hist
sns.displot(x='height', data=student_df)
# 灰色是重合的部分
sns.displot(x='height', data=student_df,hue='sex')
# matplotlib
student_df.plot(x='height', y='weight',kind='scatter')
student_df.plot(x='height', y='weight',kind='line')
plt.show()
matplotlib
折线图
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from matplotlib import pyplot as plt
import matplotlib
# 指定字体为SimHei
matplotlib.rcParams['font.sans-serif'] = 'SimHei'
students_grade = pd.DataFrame({'李健': [80, 85, 89, 91, 88, 95],
'王聪': [95, 92, 90, 85, 75, 80],
'过凡': [90, 91, 92, 91, 90, 91]
}, index=['2月', '3月', '4月', '5月', '6月', '7月'])
# 绘制多条折线图
# df.plot() 默认会将每一列数据用绘制成单条折线图,然后合并到同一张图上
# 如果那一列数据不是数字类型,将无法绘制
# figsize可以设置图标的大小(宽,高)
# rot可以将y轴的刻度逆时针旋转
students_grade.plot(kind='line',figsize=(7, 7),title='月考成绩',rot=90)
print(students_grade)
plt.show()
饼图
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from matplotlib import pyplot as plt
import matplotlib
# 指定字体为SimHei
matplotlib.rcParams['font.sans-serif'] = 'SimHei'
grade_df = pd.DataFrame({'班级': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
'性别': ['男', '男', '女', '女', '男', '男', '男', '男', '女', '女'],
'眼镜': ['是', '否', '是', '否', '是', '是', '是', '否', '否', '否'],
'成绩': [95, 90, 96, 92, 94, 85, 87, 80, 81, 86]})
# print(grade_df)
# 获取频率分布
sex = grade_df['性别'].value_counts()/grade_df['性别'].value_counts().sum()
print(sex)
# 绘制频率分布的饼图
sex.plot(kind='pie',figsize=(7, 7), title='性别分布频数图')
plt.show()
柱状图
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from matplotlib import pyplot as plt
import matplotlib
from faker import Faker
import random
# 指定字体为SimHei
matplotlib.rcParams['font.sans-serif'] = 'SimHei'
f = Faker(locale='zh_CN')
class_list = ['1班','2班','3班']
woman_list = []
for i in range(50):
woman_list.append({
'sex':'woman',
'name':f.name(),
'height': random.randint(150,170),
'weight': random.randint(40,60),
'class': random.choice(class_list)
})
man_list = []
for i in range(50):
man_list.append({
'sex':'man',
'name':f.name(),
'height': random.randint(160,180),
'weight': random.randint(50,70),
'class': random.choice(class_list)
})
student_list = woman_list + man_list
student_df = DataFrame(data=student_list)
weight_mean = student_df.groupby('class')['weight'].mean()
print(weight_mean)
# 降序排列weight_mean
weight_mean = weight_mean.sort_values(ascending=False)
weight_mean.plot(kind='bar')
plt.show()
综合案例
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import matplotlib.pyplot as plt
import matplotlib
from faker import Faker
import random
f = Faker(locale='zh_CN')
class_list = ['1班','2班','3班']
woman_list = []
for i in range(50):
woman_list.append({
'sex':'woman',
'name':f.name(),
'height': random.randint(150,170),
'weight': random.randint(40,60),
'class': random.choice(class_list)
})
man_list = []
for i in range(50):
man_list.append({
'sex':'man',
'name':f.name(),
'height': random.randint(160,180),
'weight': random.randint(50,70),
'class': random.choice(class_list)
})
# 指定字体为SimHei
matplotlib.rcParams['font.sans-serif'] = 'SimHei'
student_list = woman_list + man_list
student_df = DataFrame(data=student_list)
# print(student_df)
# 散点图
student_df.plot(x='height', y='weight',kind='scatter')
# 折线图
# use_index是否要用行索引作为x轴的刻度值
student_df.plot(x='height', y='weight',figsize=(7,7),kind='line',use_index=False)
# 柱状图
student_df.head().plot(x='name', y='weight',kind='barh')
student_df.head().plot(x='name', y='weight',kind='bar')
# 饼图
# 获取班级的频率分布
class_count = student_df['class'].value_counts()/student_df['class'].value_counts().sum()
class_count.plot(kind='pie',title='班级分布',autopct='%.2f%%')
# 绘制岗位的频率分布条形图
class_count.plot(kind='bar', figsize=(13, 6), title='班级频率分布条形图')
plt.show()
sklearn
机器学习可以解决一种简单的问题——分类问题,那些数学的原理太过于高深,我也不懂,我就结合网上资料和AI,给你们弄了一个简单的案例,进行说明,相信你们看完这个案例,至少能够解决机器学习中最简单的分类问题。
机器学习曾经解决过一个经典的问题,对蚊子进行分类
20 世纪 80 年代,生物学家发现了两种蚊子,并把它们分别命名为库蚊和伊蚊,其中伊蚊会传播多种病原体。
他们想,能不能根据这两种蚊子翅长和触角长的数据,对新的未知类别的蚊子进行分类。
这是一个分类问题,目标是根据蚊子的特征(翅长、触角长)对蚊子进行分类。
机器学习其实就是对各种模型的正确使用,那些数学的原理不懂也影响不大,如果理解原理对选择模型肯定会有帮助,我其实还是尝试去学了一下,确实太难了,但是你至少得了解这个模型大概的算法,适不适合解决这类问题,我一开始尝试了很多模型都不对,然后把锅都扔给模型,抱怨这个模型怎么这么垃圾,这样是不对的。
上述问题最好的模型是K Nearest Neighbors(KNN 模型),他是一种近邻分类算法,在蚊子的分类问题中,KNN 算法的计算步骤是这样的:
1)计算未知蚊子与每个已知蚊子特征之间的距离。
2)选取合适的 K 值,找出距离中前 K 个最小值所对应的已知蚊子。
3)根据少数服从多数的原则,对新蚊子的类别进行预测。
未知蚊子与每个已知蚊子的距离在散点图中其实一目了然,大家看看程序预测得准不准吧。
import random
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
# 生成库蚊数据
kuwen_data = []
for i in range(50):
kuwen_data.append({
"翅长": random.uniform(2.2, 2.8),
"触角长": random.uniform(1.0, 1.8),
'类别':'库蚊'
})
# 生成伊蚊数据
yiwen_data = []
for j in range(50):
yiwen_data.append({
"翅长": random.uniform(4.0, 5.0),
"触角长": random.uniform(2.0, 3.0),
"类别": "伊蚊",
})
# 生成未知数据(其实是库蚊)
unknown_data_kuwen = []
for j in range(5):
unknown_data_kuwen.append({
"翅长": random.uniform(2.2, 2.8),
"触角长": random.uniform(1.0, 1.8),
"类别": "未知",
})
# 生成未知数据(其实是伊蚊)
unknown_data_yiwen = []
for j in range(5):
unknown_data_yiwen.append({
"翅长": random.uniform(4.0, 5.0),
"触角长": random.uniform(2.0, 3.0),
"类别": "未知",
})
# 合并数据
wenzi_data = kuwen_data + yiwen_data + unknown_data_kuwen + unknown_data_yiwen
# 创建DataFrame
wenzi_df = pd.DataFrame(wenzi_data)
# print(wenzi_df)
x = wenzi_df[['翅长', '触角长']].values
y = wenzi_df['类别'].values
# Step2 数据预处理
# 最后 10 个样本为未知样本,其余样本为已知样本
train_X = x[:-10]
train_Y = y[:-10]
pred_X = x[-10:]
# Step3 训练模型
# 在 K 近邻分类器中,K 值通过参数 n_neighbors 设置
model = KNeighborsClassifier(n_neighbors=3)
model.fit(train_X, train_Y)
# Step4 应用模型
# 应用训练出的模型预测未知蚊子的类别
pred_Y = model.predict(pred_X)
print(pred_Y)
# 设置中文字体
plt.rcParams['font.family'] = 'Microsoft YaHei'
# 散点图表示
sns.relplot(x='翅长', y='触角长', data=wenzi_df , hue='类别')
plt.show()
faker
from faker import Faker
f = Faker(locale="zh_CN")
print(dir(f))
print(f.address())