Numpy
导包:import numpy as np
创建数组
- 创建一维数组:data1=np.array([1,2,3,4])
- 创建二维数组:data2=np.array([[1,2,3],[4,5,6]])
- 创建5行3列的二维的全零数组:data3=np.zeros(shape=(5,3))
- 创建5行3列的二维的全一数组:data4=np.ones(shape=(5,3))
- 创建全空数组(数据无限接近0但不是0,方便数学上的一些操作):data5=np.empty(shape=(5,3))
- 创建一个2*2的2维数组,值填充为7:data5=np.full((2,2),7)
- 创建3*3维对角矩阵::data5=np.eye(3,k=2)k>0对角线向右移k行,k<0对角线向左移k行
- 创建【start,end)步长为step的数组:np.arange(start,end,step)
- 创建开始端a,结束端b,分割成n个数据,生成线段:np.linspace(a,b,n)
- 生成a行b列的【0,1)的随机数:np.random.rand(a,b)
- 生成a行b列的【0,1)的具有正态分布的随机数:np.random.randn(a,b)
- 生成a行b列的low(包含)到high(不包含)的随机数:np.random.randint(low=0,high=0,size=(a,b),dtype=np.int)
- 生成5行3列的【0,1)之间的浮点数:
- data9=np.random.random_sample(size=(5,3))
- data9=np.random.random(size=(5,3))
- data9=np.random.ranf(size=(5,3))
- data9=np.random.sample(size=(5,3))
- np.random.choice(a=[],size=(a,b,c),p=[],replace=False)
- a是一个列表,从这个列表中生成随机数据
- size是生成的数组的维度
- p是列表a中的数据生成概率,p的长度要和a一致,且相加等于1
- 当replace为False时,生成的随机数据不能有重复值
np.random.choice(a=['a','b','c','d','e'],size=(5,3),p=[0.2,0.2,0.2,0.2,0.2],replace=False)
属性
- numpy1.reshape((a,b))修改数组尺寸,不修改原数组,返回新数组,新尺寸的数据是要和原数据量一样。
- numpy1.resize((a,b))直接操作原数组,不返回新数组
- numpy1.T数组转置
- numpy1.ndim 数组维度
- numpy1.shape 数组形状
- numpy1.size 数组所有元素个数
- numpy1.dtype 数组的数据类型
- numpy1.nbytes 数组占用空间大小
- numpy1.flat 获取数据任意数据类型的迭代器
for item in numpy1.flat:print(item) - numpy1.astype(type)将numpy1里的数据转换成type类型
- np.argmax(numpy1),np.argmin(numpy1):获取numpy1的最大和最小值的索引。当numpy1是二维数组时,参数axis确定是行/列比较
方法
统计分析
- 计算数据的平均值:numpy1.mean(arr,axis=None,dtype=None):计算数组的平均值,axis表示沿哪个轴进行计算,axis=1求(列之间的计算)每行平均值,axis=0,求(行之间的计算)每列的平均值,dtype表示返回结果的数据类型,默认为float64
- 计算数据的平均值:numpy1.median(arr,axis=None)参数axis和out含义与numpy.mean()相同
- 计算数组的标准差:numpy1.std(arr, axis=None, dtype=None, out=None): 参数axis、dtype和out的含义与numpy.mean()相同。
- 计算数组的方差:numpy1.var(arr, axis=None, dtype=None, out=None): 参数axis、dtype和out的含义与numpy.mean()相同。
- 计算数组的最小值:numpy1.min(arr, axis=None, out=None): 参数axis和out的含义与numpy.mean()相同。
- 计算数组的最大值:numpy1.max(arr, axis=None, out=None): 参数axis和out的含义与numpy.mean()相同。
- 计算数组的极值(最大值-最小值):numpy1.ptp(arr,axis=None,out=None):参数axis和out的含义与numpylmean()相同。
- 计算数组的元素之和:numpy1.sum(arr, axis=None, dtype=None, out=None): 参数axis、dtype和out的含义与numpy.mean()相同。
- 计算数组的元素乘积:numpy1.prod(arr, axis=None, dtype=None, out=None): 参数axis、dtype和out的含义与numpy.mean()相同。
- 计算数组的累积和:numpy1.cumsum(arr, axis=None, dtype=None, out=None): 参数axis、dtype和out的含义与numpy.mean()相同。返回二维数组。
- 计算累积和:np.add.accumulate(numpy1)对numpy1数组进行累积求和,功能上和cumsum类似。
- 计算数组的累积乘:numpy1.cumprod(arr, axis=None, dtype=None, out=None): 参数axis、dtype和out的含义与numpy.mean()相同。返回二维数组。
- 计算数组的加权平均:numpy1.average(a,weights)a:要计算加权平均的数组,weights与a中元素对应的权重数组,长度必须与a相同,
values = np.array([1, 2, 3, 4, 5])
weights = np.array([0.1, 0.2, 0.3, 0.2, 0.2])
np.average(values, weights=weights)
14. 数组裁剪:np.clip(a,a_min,a_max)或者a.clip(a_min,a_max):数组a里比a_min小的替换成a_min,比a_max大的替换成a_max。 15. 计算数组相邻元素之间的差值:numpy.diff(a,n,axis)
numpy.diff(a,n,axis)
a:要计算差值的数组 (后面的-前面的)
n:要计算差值的阶数,默认为1,n=2时计算相邻元素的二阶差值(即相邻差值的差值)
axis:当数组是多维,axis=0时,计算行,下面行的数据减上面行的数据(每一列下面的数减上面的数);
axis=1时,计算列,右边列的数据减左边列的数据(每一行右边的数减左边的数)
16. 沿给定轴返回数组的选定切片:numpy.compress(condition,a,axis)
numpy.compress(condition,a,axis)
condition:bool数组(掩码数组)
a:给定数组
axis:轴
a = np.array([[1, 2], [3, 4], [5, 6]])
a = array([[1, 2],
[3, 4],
[5, 6]])
np.compress([0, 1], a, axis=0) 返回:array([[3, 4]])
axis=0按行切片,第二个是true,所以返回第二行
np.compress([False, True, True], a, axis=0)
返回:array([[3, 4], [5, 6]]) 第二、三行是true,所以返回第二、三行
np.compress([False, True], a, axis=1)
返回:array([[2], [4], [6]]) axis=1按列切片,第二列是true,返回第二列
np.compress([False, True], a) 没有axis参数,第二个是true,所以返回第二个元素
切片
- 单个索引:ndarray[index],多个索引:ndarray[ [index1,index2,...] ]。
- 一维数组切片:ndarray[start:end:step],获取一维数组ndarray的起始索引start和结束索引end,前闭后开,步长为step的数据。
- 多维数组切片
创建一个3维数组,shape=(2,3,5)
[[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]]
[[16 17 18 19 20]
[21 22 23 24 25]
[26 27 28 29 30]]]
data=np.arange(1,31).reshape(2,3,5)
data[第一维的切片,第二维的切片,第三维的切片,...]
行切片,先获取第一维数组:data[0:1],获取三维数组里的第一个元素,是一个二维数组
再获取这个二维数组的前两行,就是[0:2],data[0:1,0:2]就能得到这个三维数组的最前两行
列切片,获取所有行的前两列,[第一维的所有列,第二维的所有列,第三维的前两列]
data[:,:,0:2]
data=np.array([[73,65,34,1,37],
[66,4,30,52,15]])
获取65和1这两列
print(data[:,1:4:2])第一维度获取所有数据,第二维度获取第2列到第4列,步长为2
无规律切片,返回73,65,1,37,4,30
data[ [行索引1,行索引2...], [列索引1,列索引2...] ],获取data[行索引1,列索引1],[行索引2,列索引2]的值
- 堆叠
- 垂直堆叠:np.vstack(numpy1,numpy2),要求两个数组具有相同的列数
- 垂直堆叠:np.hstack(numpy1,numpy2),要求两个数组具有相同的行数
掩码数组
salarys = np.array(
[ ['赵一', '男', 14297],['钱二', '女', 17917],['孙三', '男', 8404],
['李四', '男', 14907],['周五', '男', 18865],['吴六', '女', 11377],
['郑七', '男', 10212],['王八', '男', 15351],['冯九', '女', 19071],
['程十', '女', 18461],['褚天', '女', 10787],['卫地', '女', 13322],
['蒋玄', '女', 16202],['沈黄', '女', 12288],['韩宇', '男', 14422],
['杨宙', '男', 13485]],
dtype=object
)
筛选条件
mask=salarys[:,1]=="女" #掩码数组
salarys[mask] #输出性别等于女的数据
salarys[mask,2].mean()计算性别等于女的第三列的平均数
文件
-
np.savetxt(file="aa.txt",arr1,fmt="%d",delimiter="\t",newline="\n",header='',footer='',comments='')
- file是要保存的文件名
- arr1是要保存的numpy数组
- fmt是要保存的数据类型(%d,%.2f,%18e)
- delimiter是列之间的分隔符
- newline是行之间的分隔符
- header是文件开头的字符串
- footer是文件结尾的字符串
- comments是注释内容
-
np.loadtxt=(file="aa.txt",dtypeobject,delimiter=",",skiprows=1,encoding="utf-8",usecols=(a,b),unpack=False,max_rows=n)
- skipwors=n跳过n行
- usecols(a,b)加载第a列和第b列
- unpack=true/false是否对加载的数据进行解耦操作
- max_rows=n最多读取n行
- converters={n:func}定义函数func,对第n列的所有数据进行func处理
data1,data2,data3=np.loadtxt("stock.csv", delimiter=",", dtype=object, usecols=[1,2,3],#加载第1,2,3列 skiprows=1,#路过第一行 converters={0,date2str}#对第0列的日期数据进行对应的函数处理 unpack=True#解耦操作,返回一个包含三个子数组的二维数组,可以返回多个变量arr1,arr2,arr3 ) print(data1,data2,data3)读取的第1,2,3列分别存储到data1,data2,data3变量中
日期时间函数
导包
from datetime import datetime,timedelta
import time
- 获取当前时间时间戳(单位:秒)
- time.time()
- datetime.now():2024-07-26 13:43:30.599165
- datetime构造时间日期对象
- current=datetime(year,month,day,hour,minute,second)
- current.weekday():周几(周一:0,周日:6)
- 字符串解析成日期类型:datetime.strptime(date_str,format)
datetime1=datetime.strptime("2017-12-13T10:53:49.875Z","%Y-%m-%dT%H:%M:%S.%fZ") - 获取日期的年月日
- 年:datetime1.year
- 月:datetime1.month
- 日:datetime1.day
- 时:datetime1.hour
- 分:datetime1.minute
- 秒:datetime1.second
- 周几:datetime1.weekday()(周一是0,周日是6)
求解线性方程组
np.linalg.solve(A,a)
A:表示方程组的系数矩阵
a:表示等号右侧的常量系数或矩阵
x-2y+z=0
2y-8z=8
-4x+5y+9z=-9
A=np.array([[1,-2,1],[0,2,-8],[-4,5,9]])系数矩阵
a=np.array([0,8,-9])右侧的常量系数
C=np.linalg.solve(A,a) 返回三个解
自定义通用函数
- 自定义一个普通函数
- 使用np.frompyfunc包装器函数,将普通函数封闭为numpy通用函数,np.frompyfunc(func,参数个数,返回值个数)
1.自定义一个普通函数
def func(x):
return x**2
2. 使用np.frompyfunc包装器函数,将普通函数封闭为numpy通用函数,np.frompyfunc(func,参数个数,返回值个数)
np_square=np.frompyfunc(func,1,1)
np_square(n)
Pandas
导包
import pandas as pd
from pandas import Series,DataFrame
Series
创建Series
Series是一维数组
- Series(data,index,name,dtype)
- data:数据
- index:行索引
- name:列索引
- dtype:数据类型
数据是列表,自定义行索引
s1=Series=([1,3,14,521],index=['第一个数','第二个数','第三个数','第四个数'],name='')
数据是字典
s2=Series({'b':3,'a':4,'c':1,'d':2},index=['a','b','c','d'],name='age')
2. 通过字典构建一个Series数组,键是行索引,值是值
dict1={'a':1,'b':2,'c':3,'d':4}
s1=Series(dict1)
Series属性
- s1.index:获取行索引
- s1.size:获取Series的数据数量
- s1.values:直接获取值,不获取索引
- s1.is_unique:判断Series里的所有元素是否都是唯一的(没有重复),返回True/False
Series方法
- s1[行索引],行索引支持单个、多个以及切片,s1[start:end]左闭右开
- s1.sort_index(ascending):按照索引排序
- s1.sort_value(axcending):按照数据排序
- s1.unique():对Series里的数据进行去重
- s1.describe():输出Series的描述性统计
- s1.isin([集合]):遍历s1中的所有元素,判断每个元素是否在集合中,返回bool类型的Series
- s1.notnull():检察s1中,非空值返回True,空值(None,NaN)返回False
DataFrame
创建DataFrame
DataFrame是二维数数组
- DataFrame(data,columns=[],index=[])使用字典创建df(data是数据,columns是列索引,index是行索引)
data1={'name'['apple','egg','watermelon'],'color'['red','yellow','green'],'num':[30,40,50]}
#直接创建columns是列标题,index是行标题,列名数超过原数据则创建空列,行索引不能超过行数
df1=pd.DataFrame(data1,columns['name','num','color'],index['No.1','No.2','No.3')
2. DataFrame(data,columns=[],index=[])使用numpy生成的二维数据创建(data是numpy生成的2行4列的二维数组,行索引['b','a'],列索引是['age','name','gender','addr'])
pd1=DataFrame(np.arange(8).reshape(2,4),index['b','a'],columns['age','name','gender',addr'])
属性
- pd1:获取原数据
- pd1.values:获取值
- df1.index:获取行索引
- df1.columns:获取列索引
- df1.axes:获取行及列索引
- df1.shape:获取数据维度
- df1.T:数据转置
- df1.col_name/pd1[col1,col2...]:获取某一列或几列的数据
- df1.describe():获取统计变量(个数、中位数、标准差、方差、最小最大值)
- df1.rename(columns={old1:new1,old2:new2},index={old1:new1},inplace=True/False)
- df1.describe():描述性统计
- df1.sum(axis=0/1);df1.mean();df1.median()按行或列求和,平均值,中位数
- df1.nunique(drop=True/False):计算DataFrame或Series中唯一值的数量,适用统计某一列不同值的个数,drop=True:忽略NaN,drop=False:NaN会被统计为一个值
- df1[列名].unique():列出df1中某一列的去重后的值
方法
一、 排序
-
df1.sort_index(axis=0,ascending=false,inplace=true/false):根据索引进行排序- axis=0:根据行索引,axis=1:根据列索引
- ascending=true/false:是否升序
- inplace=true是直接在原数据排序,false返回新的数据
-
df1.sort_values(by=,axis=,ascending,inplace=)- by:指定列名或行名(根据某一列/行的数据进行排序),可以指定多列
- axis=0,行依据,行排序,这时by只能指定列名;axis=1,列依据,列排序,这时by只能指定行名
- ascending:true/false是否升序
- inplace=true/false;true是直接在原数据排序,false返回新的数据
- na_position:指定缺失值(NaN)的位置,'first' 表示将缺失值放在前面(默认),'last' 表示将缺失值放在后面。
df = pd.DataFrame({'A': [3, 1, 2], 'B': [1, 3, 2]})
# 按照 A 列升序排序
sorted_df = df.sort_values(by='A')
# 按照 A 列降序排序
sorted_df_desc = df.sort_values(by='A', ascending=False)
# 按照 A 列升序、B 列降序排序
sorted_df_multiple = df.sort_values(by=['A', 'B'], ascending=[True, False])
# axis=1:列排序,by=只能指定行名,以行索引为1的数据进行降序排序
df1.sort_values(by=1,axis=1,ascending=False)
-
日期时间函数
pd.date_range(start:起始日期,end:结束日期,periods:生成的日期数量,freq:指定日期序列的频率)- freq:日期频率,'D'(天),'W'(周),'Q'(季),'Y'(年),'5D'(每5天),'2M'(每2个月)
pd.date_range(start='20210101',periods=6,freq='D')
- freq:日期频率,'D'(天),'W'(周),'Q'(季),'Y'(年),'5D'(每5天),'2M'(每2个月)
-
获取列,将DataFrame的一个列或行获取为一个Series数据
- df1[列名],df1[[列名1,列名2,...]]获取多列数据
- df1[start,end,step]获取行数据,起始索引和结束索引,step为步长
-
通过标签获取数据,使用loc
使用布尔进行筛选
#单列做索引
df1[df1['a']>10],a列大于10的数据
df1[df1['a'].isin([])]筛选包含特定值的数据
df1[df1['a'].str.contains(r'正则表达式')]
df1[df1['a'].between(x,y)]筛选a列x,y之间的数据,闭区间
#多列做索引
使用 & | ~ 逻辑与或非
df1[(df1['a']>10) & (df1['b']<10)]筛选两个条件都为true的数据
df1[(条件1) | (条件2) ]筛选条件1或条件2为true的数据
df[ ~(条件1) ]筛选条件1不成立的数据
#使用query方法筛选数据
筛选visits大于150且category等于A的
df.query('visits > 150 and category == "A"')
df1.loc[[行标签],[列标签]]
df1=DataFrame({'A'[3,3,2],'B'[3,4,2],'C'[9,1,8]},index['No1','No2','No3'])
df1[df.'A'>2]=0#找到A列,所有大于2的数据赋值为0
df1.loc[['No1','No1']]#行标签
df1.loc['No1',['A','C']]#行列标签混合
df1.loc[:,['A','C']]#全选行但不全选列
df1.loc[['No1','No2'],:]#全选列但不全选行
- 通过位置获取数据,使用iloc
df1.iloc[ 行start:end,step,列start:end:step]
df1.iloc[[行索引],[列索引]]
df1.iloc[3]#第四行
df1.iloc[1:3,2:4]#第二到三行,三到四列
df1.iloc[[1,2,3],[2,3]]#第2,3,4行,3,4列
-
删除df的行/列数据
df.drop([行或列名],axis=0/1,inplace=True/False)- axis=0:删除行[]里只能是行名,axis=1:删除列[]里只能是列名
- inplace:表示是否直接操作原始数据
-
频数统计
针对Series里每个元素的值返回每个元素的值以及出现的次数
df1[列名].value_counts(sort,ascending,dropna,normalize=True) df1.column.value_count() df1.apply(pd.Series.value_counts,axis) sort:True/False是否对频率进行排序 ascending:True升序排序 dropna:True/False是否对NaN的次数进行统计 normalize=True/False是否返回每个值占总量的比例 fruits = { "A": ["apple", "banana", "apple", "orange", "banana"], "B": ["banana", "apple", "apple", "banana", "orange"], } df_fruits = pd.DataFrame(fruits) print(df_fruits) print(df_fruits.apply(pd.Series.value_counts, axis=1).fillna(0)) print(df_fruits.apply(pd.Series.value_counts, axis=0).fillna(0)) #normalize=True返回每个值占问题的比例 pd['col1'].value_counts(normalize=True).apply(lambda x:format(x,'.2f')) A B 0 apple banana 1 banana apple 2 apple apple 3 orange banana 4 banana orange apple banana orange 0 1.0 1.0 0.0 1 1.0 1.0 0.0 2 2.0 0.0 0.0 3 0.0 1.0 1.0 4 0.0 1.0 1.0 A B apple 2 2 banana 2 2 orange 1 1 -
缺失值统计
删除空值 函数形式:dropna(axis=0, how='any', thresh=None, subset=None, inplace=False) 参数: axis:轴。0或'index',表示按行删除;1或'columns',表示按列删除。 how:筛选方式。‘any’,表示该行/列只要有一个以上的空值,就删除该行/列;‘all’, 表示该行/列全部都为空值,就删除该行/列。 thresh:非空元素最低数量。int型,默认为None。如果该行/列中, 非空元素数量小于这个值,就删除该行/列。 subset:子集。列表,元素为行或者列的索引。如果axis=0或者‘index’,subset中元 素为列的索引;如果axis=1或者‘column’,subset中元素为行的索引。由subset 限制的子区域,是判断是否删除该行/列的条件判断区域。 inplace:是否原地替换。布尔值,默认为False。如果为True,则在原DataFrame上进 行操作,返回值为None。 填充空值 DataFrame.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None) 参数说明: value: 标量、字典、序列或 DataFrame。用于填充缺失值的值。 method: {‘backfill’, ‘bfill’后向填充, ‘pad’, ‘ffill’前向填充, None}。填充方法。 axis: {0 or ‘index’, 1 or ‘columns’}。沿着哪个轴填充。为1,填充前/后一列的数据 inplace: bool,默认为 False。如果为 True,则在原地修改数据。 limit: int,默认为 None。如果方法是 pad 或 ffill,则这是连续的填充的最大数 量;如果方法是 backfill 或 bfill,则这是连续的填充的最大数量。 downcast: dict,默认为 None。一个字典,其键是列名,其值是 [numpy]数据类型。 如果可能,将尝试将列转换为这些类型。 indices=series1.isnull(),判断缺失值,返回bool类型的Series掩码值 s[indices]获取缺失值 s[~indices]获取有效值 Series.isnull().sum()统计缺失值数量 Series.dropna(axis=表示要删除缺失值的行列依据{0:行,1:列} how="any/all" {any:有缺失值就删除,all:所有值都是缺失值才删除},默认any inplace=True/False)删除缺失值 Series.fillna(value) 用value填充缺失值 Series.mean(skipna=True)聚合统计时跳过缺失值 基于统计分析的结果,对缺失值进行合理的处理 avg=s.mean(skipna=True) s.fillna(avg) median=s.median(skipna=True) s.fillna(median) Series.ffill() 使用前一个非NaN数据填充 Series.bfill() 使用后一个非NaN数据填充 any(iterator)给定的可迭代对象中有任意一元素转化为bool为True,返回结果即为True all(iterator)给定的可迭代对象中所有元素转化为bool为True,返回结果才为True -
数据行列转换
df1.stack(dropna=True/False):列索引追加到行索引,二维转向一维。stack默认删除nan的值,dropna=False保留空值
df1.unstack():行索引转向列索引,一维转向二维。 二者默认操作的是最内层
- 单层列索引数据旋转到行:df1.stack()列索引变成行索引,行索引变成了多层索引。二维表向一维表转换,类似透视和逆透视。
scores = DataFrame( np.random.randint(60, 100, (4, 3)), index="张三-李四-王舞-赵柳".split("-"), columns=["语文", "数学", "音乐"], ) scores scores.stack().index- 多层列索引旋转到行:df1.stack(level=[0,1],future_stack=True)
index = pd.MultiIndex.from_product( [['第一季度', '第二季度', '第三季度', '第四季度'], ['销售', '研发', '市场']], names=['季度', '部门'] ) # 创建多层级索引的列索引 columns = pd.MultiIndex.from_product( [['收入', '支出'], ['实际', '预算']], names=['类型', '类别'] ) # 创建 DataFrame data = np.random.randint(1000, 5000, size=(12, 4)) df = pd.DataFrame(data, index=index, columns=columns) df #将列索引的层级为0和1转换成行索引,future_stack=True,不加会有警告 df.stack(level=[0,1],future_stack=True)
-
转换成行索引的逆序:df1.unstack()
df1.stack(level=[0,1].unstack(level=[2,3])) df1原本有各有两层行索引和列索引,将df1的第一、第二层列索引转换成行索引后, 变成第三、第四层行索引,再使用unstack()将那两层行索引逆序成列索引。
- 重新构建索引:DataFrame.reindex(),和索引重命名的区别是,重构是重构索引,重命名索引是对于索引标签进行重命名。
obj.reindex(
index=None,
*,
axis: 'Axis | None' = None,
method: 'ReindexMethod | None' = None,
copy: 'bool | None' = None,
level: 'Level | None' = None,
fill_value: 'Scalar | None' = None,
limit: 'int | None' = None,
tolerance=None,
)
主要参数
index:新索引标签数组或 Index 对象。method:填充方法,可选。可以是'backfill'/'bfill'、'pad'/'ffill'、'nearest'。copy:默认为True,如果为False,则尽量避免复制底层数据。level:对 MultiIndex 有效。级别(或级别名),用作重索引的索引。fill_value:在重新索引期间引入的缺失值的填充值。limit:向前或向后填充值时的最大数量。tolerance:容差范围内的最大距离。如果索引变化超过这个范围,则不进行填充。 对于Series
索引的重新赋值,不会和原索引匹配也不会改变原数据。
s = Series(np.random.randint(0, 100, size=(5,)), index=list("abcde"))
name_idx = ["张三", "李四", "王舞", "赵柳", "孙七"]
s.index = name_idx#行索引重新赋值
使用reindex()重构索引,会和原索引匹配,和原索引不一致的值会变成nan。
重新(重构)索引
s = Series(np.random.randint(0, 100, size=(5,)), index=list("abcde"))
name_idx = ["张三", "李四", "王舞", "赵柳", "孙七"]
s.reindex(name_idx)
五个值都是nan,对于nan,可以用fill_value填充。
11. 行列索引重命名
DataFrame.rename() 函数用于对 DataFrame 的行索引和列标签进行重命名。它可以通过提供字典或函数的方式来修改索引或列标签。这个函数特别有用,当你需要清理数据或使列名和索引更具可读性时。
DataFrame.rename(
mapper: 'Renamer | None' = None,
*,
index: 'Renamer | None' = None,
columns: 'Renamer | None' = None,
axis: 'Axis | None' = None,
copy: 'bool | None' = None,
inplace: 'bool' = False,
level: 'Level | None' = None,
errors: 'IgnoreRaise' = 'ignore',
)
关键参数说明:
mapper:函数或字典,用于重命名行索引或列标签。index:函数或字典,用于重命名行索引。columns:函数或字典,用于重命名列标签。axis:用于指定应用重命名的轴。0或'index'表示行索引,1或'columns'表示列标签。
df = pd.DataFrame({
'old_name1': [1, 2, 3],
'old_name2': [4, 5, 6]
})
#1使用字典对列重命名{"原列名":"新列名","":"",}
df.rename(columns={"old_name1":"col1","old_name2":"col2"})
#2使用mapper函数更新列名
df.rename(columns=str.upper)#将英文字符转换成大写
使用函数对行索引重命名
df.rename(index = lambda x : "row_" + str(x) )
# 5、mapper + axis 组合实现行、列索引更新
df.rename(mapper=str.upper, axis=0) # axis=0, 默认值,表示使用 mapper 函数对行索引重命名
df.rename(mapper=str.upper, axis=1)
12. 更改索引层级顺序:obj.reorder_level(order=[1,0],axis=0/1)
- order=[],多层索引level从最多层向里的从0开始的递增序列,order可以改变层级顺序
- axis=0调整行索引顺序,axis=1调整列索引顺序
# 创建多层级索引的行索引
index = pd.MultiIndex.from_product(
[["第一季度", "第二季度", "第三季度", "第四季度"], ["销售", "研发", "市场"]],
names=["季度", "部门"],
)
# 创建多层级索引的列索引
columns = pd.MultiIndex.from_product(
[["收入", "支出"], ["实际", "预算"]], names=["类型", "类别"]
)
# 创建 DataFrame
data = np.random.randint(1000, 5000, size=(12, 4))
df_data = pd.DataFrame(data, index=index, columns=columns)
df_data
- 删除重复值
DataFrame.drop_duplicates(subset=None, keep='first', inplace=False, ignore_index=False, keep_original_index=False)
参数:
-
subset (列标签列表, 可选):
- 描述:要用来判断重复值的列的标签列表。默认情况下,会考虑所有列。
- 示例:
df.drop_duplicates(subset=['col1', 'col2'])将仅根据col1和col2列中的值来判断重复项。
-
keep (字符串, 默认 'first'):
-
选项:{'first', 'last', False}
-
描述:确定保留哪些重复项(如果有)。
- 'first':保留每组重复项中的第一个出现。
- 'last':保留每组重复项中的最后一个出现。
- False:删除所有重复项。
-
示例:
df.drop_duplicates(keep='last')将保留每组重复项中的最后一个出现。
-
-
inplace (布尔值, 默认 False):
- 描述:是否直接在原 DataFrame 上进行修改。
- 示例:
df.drop_duplicates(inplace=True)将直接修改原始 DataFramedf。
-
ignore_index (布尔值, 默认 False):
- 新版本:1.1.0 版本新增
- 描述:如果为 True,则结果索引将被重置为 0, 1, ..., n-1。
- 示例:
df.drop_duplicates(ignore_index=True)将重置 DataFrame 的索引。
-
keep_original_index (布尔值, 默认 False):
- 新版本:1.3.0 版本新增
- 描述:如果为 True 并且
ignore_index=False,则保留原始索引。 - 示例:
df.drop_duplicates(keep_original_index=True)在删除重复项时保留原始索引。
返回值:
- 如果
inplace=False(默认),返回一个没有重复行的新 DataFrame。 - 如果
inplace=True,直接修改原 DataFrame。
- 长宽格式的转换
宽格式是指:一列或多列作为标识变量(id_vars),其他变量作为度量变量(value_vars),直观上看,这种格式的数据比较宽,举个列子,列名是:id1、id2、var1、var2、var3,一行可以表示多个度量变量的值。
而长格式是指在一行中,除了标识变量(id_vars),其他列是variable和name,从宽格式转换为长格式,会使得数据行数增加,直观上看,这种格式的数据比较长,举个例子,列名是:id1、id2、variable、value,一行只表示一个度量变量的值。
在宽格式转换为长格式的过程中,宽格式中的多个度量变量进行了分裂,使得长格式中的每一行,实际上,只表示一个度量变量的值。
-
整合数据,逆透视表(unpivot),把数据从宽格式转换为长格式
DataFrame.melt(self,id_vars=None,value_vars=None,var_name=None,value_name='value',col_level=None)参数注释:
- id_vars:作为标识变量的列
- value_vars:作为值的列
- var_name:默认值是variable,对长格式中度量变量的列名所在的列进行命名
- value_name:默认值是value,对长格式中度量变量的列值所在的列进行命名
- col_level:如果列是multiindex,使用这个level的索引进行melt
df=pd.DataFrame({'idA':{0:'a',1:'b',2:'c'},
'varB':{0:1,1:3,2:5},
'varC':{0:2,1:4,2:6}})
idA varB varC
0 a 1 2
1 b 3 4
2 c 5 6
id列是idA,度量变量是varB和varC,得到如下长数据
df.melt(id_vars='idA',value_vars=['varB','varC'])
idA variable value
0 a varB 1
1 b varB 3
2 c varB 5
3 a varC 2
4 b varC 4
5 c varC 6
-
数据透视 把数据从长格式转换为宽格式,返回按照特定的index或column重塑的DataFrame,不带聚合函数,可以处理文本数据:
DataFrame.pivot(self,index=None,columns=None,values=None)参数注释:
- index:用户创建新DataFrame的索引,相当于分组列,相同索引的行称为一个小分组。
- columns:根据columns指定的列值来创建新DataFrame的列名,使用该参数指定的列来创建结果的列名。
- values:和columns对应,表示相应列的列值,用于填充结果列的列值。
重塑数据的流程:
- 根据index的唯一值进行分组
- 把columns指定的列的唯一值作为结果的列名,即列的值作为结果的列名
- 把values对应的列值作为新列名的值,即把列的值作为结果中对应列的值
idA variable value
0 a varB 1
1 b varB 3
2 c varB 5
3 a varC 2
4 b varC 4
5 c varC 6
使用pivot把长格式转换为宽格式,按照idA列进行分组,
把variable的列值作为结果的列名,把values的列值作为结果列的值:
df.pivot(values='value',columns='variable',index='idA')
variable varB varC
idA
a 1 2
b 3 4
c 5 6
重塑的数据包含行索引idA,列标签varB和varC,其中variable是列标签的name。
Pandas时间日期处理
-
pd.to_datetime(date_str):时间日期字符串转换成时间日期(当参数是列表时,返回列表)
timestr_list=["2024-7-26 13:44:59","2024-7-26 14:55:20"] -
data.date.dt.month:data是一个dataframe,date是这个df是日期列,dt:这是Pandas中用于访问datetime类属性的方法。它允许我们从日期时间类型的序列中提取部分,如年、月、日、小时、分钟等;month:这是通过
dt访问器获取具体日期时间组成部分的一个属性,这里是指月份。它会返回一个整数序列。 -
在Pandas库中,
strftime是一个方法,用于将日期时间对象格式化为字符串。这个方法通常用在datetime类型的 Series 或者 DataFrame 的某一列上,它可以按照指定的格式将日期时间转换成字符串形式。strftime方法是dt属性的一部分,它允许你定义一个格式字符串来控制日期时间的输出格式。这个功能基于 Python 标准库中的datetime.strftime方法。import pandas as pd # 创建一个包含日期时间的DataFrame data = {'date': ['2024-01-01', '2024-02-15', '2024-03-10']} df = pd.DataFrame(data) df['date'] = pd.to_datetime(df['date']) # 将字符串转换为日期时间类型 # 使用strftime方法格式化日期 df['formatted_date'] = df['date'].dt.strftime('%Y-%m-%d') print(df)
strftime 支持多种格式化选项,例如:
%Y:完整的四位数年份,如 2024。%y:两位数的年份,如 24。%m:月份,如 01。%d:日期,如 01。%H:小时,如 14。%M:分钟,如 30。%S:秒,如 59。%w: 数字化的星期,周日为0,周一为1。%a:本地简化星期名称,如 Wed。%A:本地完整星期名称,如 Wednesday。%b:本地简化月份名称,如 Jan。%B:本地完整月份名称,如 January。%x:本地日期表示方式。%X:本地时间表示方式。%%:百分号 %。
- pd.date_range():批量创建时间日期数据
pd.date_range(start=None, end=None, periods=None, freq=None, normalize=False, name=None, inclusive=None, tz=None, **kwargs) start=None: 开始时间 '2021-1-1' ,'2021/1/2' , '2021-5' ,'2021' end=None: 结束时间 periods=None: 时间间隔和单独的 start 或 end 配合。 freq=None : 生成日期范围的频率,默认按天取 。 Y/y 年 m/M 月 D 日 H 小时 D: Calendar Day (日频率),按天 B:Business Day (工作日频率),不包含周末和节假日 W:Weekly (周频率),生成每周的日期范围,默认为每周日。 M/ME:Month End (月末频率),生成每月最后一天的日期范围。 MS: Month Start (月初频率),生成每月第一天的日期范围。 A/YE: Year End (年末频率),生成每年最后一天的日期范围。 AS/YS: Year Start (年初频率),生成每年第一天的日期范围。 H/h: Hourly (小时频率),生成每小时的日期范围。 T/min: Minutely (分钟频率),生成每分钟的日期范围。 S/s: Secondly (秒频率),生成每秒的日期范围。 normalize=False:是否将时间戳标准化到午夜(即当天的00:00:00)。 normalize=False不会将生成的日期范围中的每个时间戳标准化为该天的午夜时间。 normalize=True会将生成的日期范围中的每个时间戳标准化为该天的午夜时间。 name:日期对象的名称 inclusive:取值有 {"both", "neither", "left", "right"} 代表开始和结束时间边界值是否能取到, 或者只取一边 both:start 和 end 两个时间边界值都包含 neither:start 和 end 两个时间边界值都能不包含 left:包含 start 开始时间,不包含 end 结束时间 right:不包含 start 开始时间,包含 end 结束时间 #批量创建时间日期数据 print(f'批量日期{pd.date_range(start="20240501",end="20240715",freq="D",inclusive="left")}') #开始时间向后取10个日期 print(pd.date_range(start="2024-07-01", periods=10)) #结束日期向前取10个日期 print(pd.date_range(end="2024-07-01", periods=10)) print(pd.date_range("2020-01-01", "2024-07-25", freq="YS")) print(f'获取 `2020-01-01~2024-07-25` 之间所有7月末的日期数据{pd.date_range( start="2020-01-01",end= "2024-07-25",freq="YE-JUL")}') print(f"""获取 `2020-01-01~2024-07-25` 之间所有7月末8月初的日期数据{pd.date_range( start="2020-01-01",end= "2024-07-25",freq="YS-AUG").union( pd.date_range(start="2020-01-01",end= "2024-07-25",freq="YE-JUL") )}""") print(f'获取 `2024-01-01~2024-07-25` 之间,每隔3个月为频率 所有月末的日期数据 {pd.date_range(start="2023-01-01", end="2024-07-25", freq="3ME")}') print(f'获取 `2024-07-01~2024-07-25` 之间所有周六的日期数据{pd.date_range( start="2024-07-01",end="2024-07-25",freq="W-SAT")}')
文件
Pandas读取csv文件
函数用于从 CSV 文件中读取数据并创建一个 DataFrame
pd.read_csv(file,delimiter,header,names,index_col,usecols,skiprows,nrows,encoding,dtype)
file:要读取的文件路径(字符串)、URL 或文件型对象。这是必填参数。
delimiter:指定分隔符,默认为 ',' 。
header:指定用作列名的行号,默认为 0(即第一行)。如果没有列名,可以设置为 `None` 。
names:如果 header=None,可以通过此参数提供列名列表。
index_col:用作索引的列号或列名。
usecols指定要读取的列,可以是列号、列名或它们的列表。
skiprows:要跳过的行数(从文件开头开始计数)。
skipfooter:要跳过的行数(从文件末尾开始计数)。
nrows:要读取的行数。
encoding:指定文件的编码格式,例如 'utf-8'。
dtype:指定列的数据类型,可以是字典形式,为每列指定类型。
date=pd.read_csv("stock.csv",index_col="date",parse_dates=True)
- 读取csv文件,以date列为行索引列,parse_dates=True表示会尝试将索引列中的值(date列)解析为日期类型索引,以便进行日期相关操作。
xxx.loc['年'] , xxx.loc['年月'] , xxx.loc['年月日'] ,
xxx.loc['年月日 时'] 年 月 日 时 分 秒等等
xxx.loc[start:end] 使用切片,获取日期介于 start 与 end 之间的数据
#获取2024年数据
#print(data.loc["2024"])
#获取2024年7月数据
#print(data.loc["2024-07"])
#获取start-end之间的数据
#print(data.loc["2024-06":"2024-07"])
Pandas读取excel文件
io: 字符串、文件路径或文件类对象,用于指定要读取的 Excel 文件的位置。可以是一个本地文件路径或者是一个支持 read() 方法的对象。sheet_name: 可以是整数(表示工作表索引),字符串(表示工作表名称),列表(包含多个工作表名或索引)或者 None(默认为 0,即第一个工作表)。如果设置为 None,则会读取所有的表格,并返回一个字典形式的结果。header: 指定作为列名的行号,默认是 0,即第一行作为列名。如果文件没有列名行,可以设置为 None。names: 列名列表。如果指定了此参数,那么 header 参数将被忽略。index_col: 用作行索引的列编号或列名。如果是 None(默认值),则自动产生一个默认的整数索引。usecols: 要解析的列。可以是列名的列表,例如 ['A', 'B'] 或者列号的列表 [0, 1,2],也可以是一个函数,该函数接收列名/列号并返回布尔值来决定是否读取该列。dtype: 指定每一列的数据类型。可以是类型名的字典,比如 {'a': np.float64, 'b': np.int32}。skiprows: 需要跳过的行数(从文件开头开始计数),或者是一个包含要跳过的特定行号的列表。nrows: 需要读取的行数(从文件顶部开始计算)。na_values: 指定一组额外的字符串应该被视为缺失值。这可以是一个字典,键是列名,值是应该被视为缺失值的字符串集合。parse_dates: 是否尝试将数据解析为日期时间。可以是列表 [1, 2] 表示尝试将第 1 和第 2 列解析为日期;True 表示尝试将所有看起来像日期的列都解析为日期;或者是一个字典,指定如何组合多列创建一个新的日期列。date_parser: 用来解析日期的函数。如果 parse_dates 设置了,这个函数会被用来转换日期字符串到 datetime 对象。thousands: 用来分隔千位的字符,通常用于处理数字中的逗号或其他分隔符。comment: 如果设置了这个选项,那么该字符之后的内容会被视为注释并忽略。encoding: 用于解码文件内容的编码方式。默认情况下,Pandas 将使用 UTF-8 编码。engine: 使用哪个引擎来读取 Excel 文件。可选值有 'xlrd' 和 'openpyxl'。对于 .xls 文件通常使用 'xlrd',而 .xlsx 文件则推荐使用 'openpyxl'。converters参数是pandas.read_excel()函数中的一个选项,它允许你为 Excel 文件中特定的列指定自定义转换函数。这个参数接受一个字典,其中键是列名(或者列索引),值是一个函数,该函数将应用于该列的每一个元素。
Python连接MySQL数据表
- 安装sqlalchemy和pymysql模块
pip install sqlalchemy pymysql -i https://mirrors.cloud.tencent.com/pypi/simple导入模块:from sqlalchemy import create_engine, text- create_engine:创建新的SQLAlchemy Engine实例。连接数据库的起点,负责管理数据库连接与数据库的交互。
- text:用于创建一个SQL语句文本对象。与SQLAlchemy的执行引擎结合使用,以执行原生SQL语句。
- engine=create_engine("mysql+pymysql://{username}:password@ip:port/databasename?charset=utf8")
- result=con.execute(text(sql),{'var1':v1})用v1代替sql语句里的var1
- result.keys()获取所有列名
from sqlalchemy import create_engine, text
#create_engine("mysql+pymysql://{username}:password@ip:port/databasename?charset=utf8")
engine = create_engine("mysql+pymysql://root:123456@localhost:3306/book?charset=utf8")
#使用SQLAlchemy Engine 创建数据库连接
with engine.connect() as con:
#定义sql语句,使用':'来定义变量,以便填充
sql="select * from book where id=:user_id"
#通过text对象处理sql语句并执行
result=con.execute(text(sql),{"user_id":9})#字典类型填充变量
#获取所有列名
result.keys()
#解析执行结果
for row in result.all():
print(row)
Pandas读取MySQL数据库
pandas提供 pd.read_sql(sql.connection) 函数用于连接并加载mysql数据,它直接返回DataFrame
- sql:要执行的sql语句
- connection: mysql数据库连接对象
-
导包:
from sqlalchemy import create_engine -
连接对象变量名=create_engine("mysql+pymysql://{username}:password@ip:port/databasename?charset=utf8")
-
pd.read_sql(sql,con,index_col=None,coerce_float=True,parse_dates=None,columns=None)
- sql:sql语句
- con:mysql连接的对象
- index_col:加载mysql数据表中的哪一列作为DataFrame索引
- coerce_float:数据类型自动为float
pd.read_sql(sql,con,index_col='列名')
-
pd.read_sql_table('表名称',连接对象,columns=[0,2]),默认读取一张表所有内容
Pandas存储到mysql
使用pd.to_sql(name,con,if_exists,index=True,index_label=None,chunksize=None,dtype=None,method=None)
- name :表名称
- con:SQLAlchemy创建的连接对象
- if_exists:如果数据表存在采取何种策略,取值有,
{'fail', 'replace', 'append'} - index:将索引写为一列 ,使用 index_label的值为列名称,=False时不保存行索引
- dtype:标量或字典,指定DataFrame保存到MySQL数据库时各个列的采用哪种数据类型
如果需要存储自定义索引,先df.reset_index().to_sql()
索引是数字对象或日期对象,可以直接用index=True存储 df1.to_sql("df1",con,index=True,if_exists="replace")
注意:将pandas数据存储到mysql要注意数据类型
mysql没有list[],dict{}等数据类型,mysql不认识list,dict,就会报错
所以一般要将list,dict转换成str,再存储
用 .dtypes属性查不具体,因为str,list,dict等都是object
df1.iloc[0].apply(type)所以使用apply查询第一行的数据类型
转换数据类型
xx.astype(具体的类型)
dict{'列名称':数据类型}
df1.astype(str)全部转为str
df2=df1.astype({"要转换的列名":str})
元素级运算函数
- map(func,*iterables,na_action):将func函数应用到可迭代对象iterables的每个元素上,传入Series或DataFrame返回Series/DataFrame,第一个函数参数可以是字典,传入Series返回键对应的值。
- na_action:取值'ignore',忽略NaN值。
- apply(func,axis,raw,result_type):函数主要作用于DataFrame的行或列数据
- func作用于df的行数据或列数据的具体函数
- axis:决定函数作用于行或列(axis=0:行之间运算;axis=1:列之间运算)
- raw:bool,决定是否将行/列数据以ndarray形式传递给func
- applymap(func):将一个函数作用于Series和DataFrame的每个元素上,不区分行或列,返回DataFrame,pandas版本大于2.1.0不推荐,使用df.map平替。
分组函数
DataFrame.groupby(by=None,axis=0,level=None,as_index=True,sort=True,group_keys=True,squeeze=False,observed=False,dropna=True)
DataFrame的groupby函数,返回类型是DataFrameGroupby,而Series的groupby函数,返回类型是SeriesGroupBy。
by:用于分组的列名或函数 。可以是一个列名、一个函数、一个列表或一个字典
axis:分组轴。如果 axis=0(默认值),则沿着行方向分组;如果 axis=1,则沿着列方向分组。
level:在多层索引的情况下,用于指定分组的级别。
as_index:是否将分组键作为索引返回。如果 as_index=True(默认值),则返回一个带有分组键作为索引的对
象;否则返回一个不带索引的对象。
sort:是否对分组键进行排序。如果 sort=True(默认值),则对分组键进行排序;否则不排序。
group_keys:是否在结果中包含分组键。如果group_keys=True(默认值),则在结果中包含分组键;否则不含。
squeeze:是否压缩返回结果。如果 squeeze=True,则尝试压缩返回结果;否则不压缩。(已废弃)
observed:是否仅使用观察到的类别进行分组。仅适用于类别类型数据。
dropna:是否删除包含缺失值的行。如果 dropna=True(默认值),则删除包含缺失值的行;否则保留。
data={'A':[1,2,3,4],'B':[5,6,7,8],'C':['X','X','Y','Y']}]
df=pd.DataFrame(data)
groupby简单用法:df.groupby(分组依据1,2...)[列1,列2...].聚合函数()
df.groupby('C')['A'].mean()计算每个类别中A列的平均值。分组依据会变成行索引。
在pandas中,groupby结合agg函数可以对分组后的数据进行聚合计算。
agg函数允许您对每个分组应用一个或多个聚合函数。
(sum:求和,mean:平均值,median:中位数,min:最小值,max:最大值,std:标准差,var:方差,count:非空值计数
data = {'Group': ['A', 'A', 'B', 'B', 'A', 'B'],
'Value': [10, 20, 30, 40, 50, 60]}
df = pd.DataFrame(data)
result = df.groupby('Group').agg({'Value': ['sum', 'mean', 'max', 'min']})
#自定义聚合函数
def custom_agg(x):return x.max() - x.min()
df.groupby('group')['column'].agg(custom_agg)
#groupby和filter结合使用,先对数据进行分组,然后对分组后的结果筛选
#按category分组,然后筛选平均visits大于150的组
grouped = df.groupby('category').filter(lambda x: x['visits'].mean() > 150)
#transform方法可以帮助我们在保持原始DataFrame结构的同时进行分组计算。类似窗口函数
# 使用transform计算每个category的平均visits,并筛选大于平均值的行
df['mean_visits'] = df.groupby('category')['visits'].transform('mean')
filtered_df = df[df['visits'] > df['mean_visits']]
#groupby('Group')按照 'Group'列进行分组。
#agg({'Value': ['sum', 'mean', 'max', 'min']})对 'Value'列应用 'sum'(求和)、
#'mean'(平均值)、 'max'(最大值)和 'min'(最小值)这四个聚合函数。
data = {'Group': ['A', 'A', 'B', 'B', 'A', 'B'],
'Value1': [10, 20, 30, 40, 50, 60],
'Value2': [15, 25, 35, 45, 55, 65]}
df = pd.DataFrame(data)
# 对 'Value1' 列计算求和与平均值,对 'Value2' 列计算最大值和最小值
result = df.groupby('Group').agg({
'Value1': ['sum', 'mean'],
'Value2': ['max', 'min']
})
print(result)
按照 'Group' 列进行分组,然后对 'Value1' 列分别应用求和和平均值的聚合函数,
对 'Value2' 列分别应用最大值和最小值的聚合函数。
#对A列进行分组,并将每组中C列的值用分号隔开。
result=df.groupby('A').agg({'C':lambda x:';'.join(x)})
#直接重命名 agg(新列名=(列名,统计方式))
agg(合计=('用户名','sum'))
分组聚合后有多重索引,重置索引 reset_index(),然后赋值新列名 df1.columns=[]
Pandas拼接合并
1. pd.merge()
功能类似于 SQL 中的连表查询,支持 inner、left、right、outer 等各种连表查询,合并时默认匹配相同的列名。
pd.merge(
left: 'DataFrame | Series',
right: 'DataFrame | Series',
how: 'MergeHow' = 'inner',
on: 'IndexLabel | AnyArrayLike | None' = None,
left_on: 'IndexLabel | AnyArrayLike | None' = None,
right_on: 'IndexLabel | AnyArrayLike | None' = None,
left_index: 'bool' = False,
right_index: 'bool' = False,
sort: 'bool' = False,
suffixes: 'Suffixes' = ('_x', '_y'),
copy: 'bool | None' = None,
indicator: 'str | bool' = False,
validate: 'str | None' = None,
)
- left:要合并的左侧DataFrame或Series。
- right:要合并的右侧DataFrame或Series。
- how:合并的方式,默认为'inner'。其他选项包括:
- 'left':左连接,保留左侧DataFrame中的所有行。
- 'right':右连接,保留右侧DataFrame中的所有行。
- 'outer':外连接,保留两个DataFrame中的所有行。
- 'corss':笛卡尔积,左右两表进行笛卡尔积操作结果。
- on:用于合并的列名或索引级别。如果没有指定且left和right都是DataFrame,将会使用列名的交集。
- left_on:左侧DataFrame中用于合并连接时匹配的列名。如果left是Series,将会忽略该参数。
- right_on:右侧DataFrame中用于合并连接时匹配的列名。如果right是Series,将会忽略该参数。
- left_index:是否使用左侧DataFrame的索引进行合并,默认为False。
- right_index:是否使用右侧DataFrame的索引进行合并,默认为False。
- sort:是否对合并后的数据进行排序,默认为False。
- suffixes:合并后列名冲突时的后缀,默认为('_x', '_y')。
- indicator:用于在合并结果表中显示数据来源(both/left_only),bool类型
- validate:参数对需要合并的两张表的关联字段所对应的合并规则进行验证,如果验证不对则代码报错,字符串类型。
- one_to_one|1:1:检查合并键在左右数据是否是一对一
- one_to_many|1:m:检查合并键在左右数据是否是一对多
- many_to_one|m:1:检查合并键在左右数据是否是多对一
- many_to_many|m:m:检查合并键在左右数据是否是多对多
- left_index/right_index:bool类型,左右两表连接时,是否使用相同的行索引进行合并,通常两个都是
true,使用left_index就不能使用left/right_on
pd.merge(df3,df4,left_index=True,right_index=True,indicator=True)
df1 = DataFrame({"key": list("aabbabc"), "data1": np.arange(7) * 10})
df2 = DataFrame({"key": list("abd"), "data2": np.arange(1, 4) * 100})
#inner使用相同列名
pd.merge(df1,df2,how='inner')
pd.merge(df1,df2,how='left')
pd.merge(df1,df2,how='right')
pd.merge(df1,df2,how='outer')#outer,左右两张表的并集
pd.merge(df1,df2,how='cross')
#suffixes=('a','b')相同列名加的后缀
pd.merge(df1,df2,how='cross',suffixes=("aa","bb"))
df3 = DataFrame({"key1": list("aabbabc"), "data1": np.arange(7) * 10})
df4 = DataFrame({"key2": list("abd"), "data2": np.arange(1, 4) * 100})
#left_on:指定左表连接匹配的字段 str/list
#right_on:指定右表连接匹配的字段 str/list
pd.merge(df3,df4,left_on='key1',right_on='key2',how='inner')
# 2、使用多列进行表合并
df_left = DataFrame(
{
"key1": ["foo", "foo", "foo", "bar", "bar"],
"key2": ["one", "two", "one", "one", "two"],
"Lvalue": [10, 20, 30, 40, 50],
}
)
df_right = DataFrame(
{"key3": ["bar", "foo", "foo"], "key4": ["one", "two", "one"], "Rvalue": [6, 7, 8]}
)
df_left
df_right
pd.merge(df_left,df_right,left_on=["key1","key2"],right_on=["key3","key4"],how="inner")
2.pd.concat()
用于将多个 Series 或 DataFrame 沿指定轴方向连接起来,可以理解为数据在列/行方向的拼接,函数参数如下:
pd.concat(
objs: 'Iterable[Series | DataFrame] | Mapping[HashableT, Series | DataFrame]',
*,
axis: 'Axis' = 0,
join: 'str' = 'outer',
ignore_index: 'bool' = False,
keys: 'Iterable[Hashable] | None' = None,
levels=None,
names: 'list[HashableT] | None' = None,
verify_integrity: 'bool' = False,
sort: 'bool' = False,
copy: 'bool | None' = None,
)
核心参数解释:
- objs:需要连接的Series或DataFrame的迭代器(例如列表或字典)。
- axis:沿着哪个轴进行连接,默认为0(行)。可选值有1(列)。
- join:连接的方式,默认为'outer'(外连接)。其他选项包括'inner'(内连接)。
- ignore_index:是否忽略原有的索引,默认为False。如果设置为True,则生成新的整数索引。
- keys:用于创建层次化索引的键序列,默认为None。如果传递,将使用这些键作为最外层索引。
- levels:用于创建层次化索引的特定级别,默认为None。
- names:新层次化索引的名称列表,默认为None。
- verify_integrity:检查新连接的对象是否有重复索引,默认为False。如果设置为True,则在连接前会进行检查。
- sort:是否在连接时对数据进行排序,默认为False。此参数仅在连接类型为'inner'时生效。
- copy:默认为None,是否在内存中复制数据。
三个Series
keys参数作为最外层索引
df11=pd.DataFrame(np.arange(12).reshape(3,4),columns=['a','b','c','d'])
df12=pd.DataFrame(np.arange(12,24).reshape(3,4),columns=['a','b','c','d'])
df13=pd.DataFrame(np.arange(24,36).reshape(3,4),columns=['a','b','c','d'])
#纵向合并,ignore_index=True是不考虑表原来的idnex
df14=pd.concat([df11,df12,df13],axis=0,ignore_index=True)
df15=pd.concat([df11,df12,df13],axis=1,join='outer')#横向合并
print('纵向合并结果')
print(df14)
print('横向合并结果')
print(df15)
3. left.combine_first(right)
实现两个数据集的补充合并功能,使用right(右边)数据对left(左边)数据补充的一种合并方式。
- left,right是Series或DataFrame
- 以左边 非nan 为主,可理解为连表查询中的主表,不需要补充
- 如果 左边数据为nan ,右边不是,用右边的数据对左边数据进行补充
- 如果 左边没有而右边有的数据,则直接用右边数据对左边数据进行补充
用right里的数据补充left里行索引一样的数据,如果left里没有数据或为nan则补充,没有则不补充。
- 数据比较
obj1.compare(obj2):实现两个数据集的比较功能
obj1、obj2 可以是 pandas 中的 Series 或者 DataFrame
obj.compare(
other: 'DataFrame' | 'Series',
align_axis: 'Axis' = 1,
keep_shape: 'bool' = False,
keep_equal: 'bool' = False,
result_names: 'Suffixes' = ('self', 'other'),
)
关注非NaN的值,如果是非NaN值,表示同一位置数据发生了变化
关键参数解释:
- other:另一个用于比较的DataFrame或Series。
- align_axis:指定对齐的轴,默认为1(列对齐)。如果设置为0,则按行对齐。
- keep_shape:是否保持输出结果的原始形状,默认为False。如果设置为True,则结果会保留原始对象的形状。
- keep_equal:是否在输出结果中保留相等的元素,默认为False。如果设置为True,则结果中相等的元素也会显示出来。
Pandas中的多层索引
Pandas中 Series 和 DataFrame 的索引主要有以下两类
- index:行索引
- columns:列索引
针对以上行索引和列索引,又可以细分为 单层索引和多层索引,以下为Padnas中常用的创建索引的方法:
- pd.Index()
- pd.date_range()
- pd.MultiIndex.from_arrays() 从数组创建多层索引对象
- pd.MultiIndex.from_tuples() 从元组创建多层索引对象
- pd.MultiIndex.from_frame() 从 DataFrame 创建多层索引对象
- pd.MultiIndex.from_product() 从笛卡尔积创建多层索引对象
#从元组
pd.MultiIndex.from_tuples(
[('a','one'),('a','two'),('a','three'),('b','one'),('b','two'),('b','three')]
)
#从数组
pd.MultiIndex.from_arrays(
[
['a' ,'a' ,'a' ,'b' ,'b' ,'b' ],
['one','two','three','one','two','three']
]
)
#从DataFrame
frame = DataFrame(
[
('a','one'),
('a','two'),
('a','three'),
('b','one'),
('b','two'),
('b','three')
],
columns=["编号","区域"],
)
#从笛卡尔积 2*3
pd.MultiIndex.from_product(
[
["a","b"],
["one","two","three"]
]
)
Series重置索引
pandas 针对 Series 数据结构提供 Series.reset_index() 函数用于重置Series的索引,将索引转换为列数据。函数参数如下
Series.reset_index(
level: 'IndexLabel | None' = None,
*,
drop: 'bool' = False,
name: 'Level' = <no_default>,
inplace: 'bool' = False,
allow_duplicates: 'bool' = False,
)
核心参数说明:
- level:可选参数,默认为None。指定要转换成列数据的索引是哪一层。指定要重置的索引级别。如果Series是多级索引(MultiIndex),可以通过此参数选择特定级别进行重置。可以是单个级别、多个级别或级别名称。如果未指定,则重置所有级别。
- drop:布尔值,默认为False。如果为True,则不会将索引作为列插入到Series中。索引将被删除,数据将以默认整数索引进行索引。
- name:可选参数,指定新列的名称。如果没有提供,将使用原索引的名称。
- inplace:布尔值,默认为False。如果为True,则在原地修改Series,而不是返回修改后的副本。
- allow_duplicates:布尔值,默认为False。如果为True,允许新列的名称与现有列名称重复。
Series重置单层索引
- name参数指定新列名
- drop参数删除成为新列的索引列
创建多层索引
# 创建多层索引
multi_index = pd.MultiIndex.from_arrays(
[
["一班"] * 5 + ["二班"] * 5,#第一层索引
range(1000, 1010),#第二层索引
],
names=["班级", "学号"],#两层索引对应的名字
)
# 创建随机数据 30~100 整数模拟学生成绩
data = np.random.randint(30, 100, size=(10,))
# 基于多层索引及随机数据创建 Series
mul_level = Series(data, index=multi_index,name="分数")
mul_level
多层索引重置时,默认多层索引全部转换为列数据,新增的数据列变成从0开始递增的整数
mul_level.reset_index(level=0,name="分数")
将level对应的那一层索引转换成数据列
drop=True将转换后的数据列删除。
mul_level.droplevel(level=0):将level对应的那一层索引删除
DataFrame重置索引
pandas 针对 DataFrame 数据结构提供 DataFrame.reset_index() 函数用于重置 DataFrame 的索引,将索引转换为列数据。函数参数如下
DataFrame.reset_index(
level: 'IndexLabel | None' = None,
*,
drop: 'bool' = False,
inplace: 'bool' = False,
col_level: 'Hashable' = 0,
col_fill: 'Hashable' = '',
allow_duplicates: 'bool | lib.NoDefault' = <no_default>,
names: 'Hashable | Sequence[Hashable] | None' = None,
)
- level:指定要重置的索引级别。可以是单个级别、多个级别或级别名称。如果 DataFrame 是多级索引(MultiIndex),可以通过此参数选择特定级别进行重置。默认为 None,表示重置所有级别。
- drop:布尔值,表示重置索引后是否将索引丢弃。
- True:表示丢弃索引数据。
- False:默认值,表示重置索引后,索引将作为列/行数据添加到DataFrame。
- inplace:布尔值,表示是否直接修改原 DataFrame,而不是返回修改后的副本。
- col_level:默认值为 0,用于指定在多级索引(MultiIndex)中索引列插入到哪个级别,默认为0,表示是最外层。
- col_fill:默认值为空字符串,用于指定在多级索引(MultiIndex),新索引列名称的填充方式。
- allow_duplicates:布尔值,是否允许新列的名称与现有列名称重复,True表示允许。
- names:指定重置索引后的新列名称。可以是单个名称或名称列表。如果为 None,则使用原索引名称。
设置索引
pandas提供 DataFrame.set_index() 函数用于将一列或者多列设置为 DataFrame 的行索引。参数如下
DataFrame.set_index(
keys,
*,
drop: 'bool' = True,
append: 'bool' = False,
inplace: 'bool' = False,
verify_integrity: 'bool' = False,
)
参数解释
keys:- 说明:指定将要设置为索引的列或列的列表。
- 类型:
labelorlist of labels - 示例:
keys='column_name'或keys=['column1', 'column2']
drop:- 说明:是否从 DataFrame 中删除已设置为索引的列。默认为
True,表示删除这些列。如果为False,则保留这些列在 DataFrame 中。 - 类型:
bool - 默认值:
True - 示例:
drop=False
- 说明:是否从 DataFrame 中删除已设置为索引的列。默认为
append:- 说明:是否将新设置的索引追加到现有索引中。如果为
True,则保留现有索引,并将新索引追加到现有索引后面。默认为False,表示替换现有索引。 - 类型:
bool - 默认值:
False
- 说明:是否将新设置的索引追加到现有索引中。如果为
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [28, 34, 29, 40],
'部门': ['销售', '研发', '市场', '销售']
}
employee = pd.DataFrame(data)
employee.set_index("姓名")
employee.set_index(keys=["部门","姓名"])
数据分箱
数据分箱,也经常被称为 数据离散化、数据分桶、数据分段 ,是可以将连续数据转换为离散类别的一种数据处理技术。通过将连续数据划分为几个区间或“箱”(bin),每个区间内的数据点都会被分配到相应的“箱”中,这样可以将连续数据转换为分类数据。
常见的数据分箱方式主要有以下三种
- 自定义分箱:数据分段/分组区间由用户自行定义
- 等宽度分箱:数据分段/分组时,保证每组数据的跨度或宽度一致
- 等深/等频分箱:数据分段/分组时,保证每组数据样本量一致,或按指定的比例分布
pandas 针对以上三种不同的数据分箱方式,提供了以下两个函数进行实现
- pd.cut()
- pd.qcut()
自定义分箱
age=np.random.randint(0,100,size=10)10个0-100之间的随机数
#自定义分箱
pd1=pd.Series(age,name='age')
#自定义分箱的边界
bins=[0,18,34,59,100]#(0-18]一个区间,(18-34]一个区间
#对age进行自定义分箱
age_cut=pd.cut(pd1,bins=bins)
#添加分组标签label=[]
age_cut=pd.cut(age,bins=bins,labels=["少年", "青年", "中年", "老年"])
age_cut
#对分箱后的数据进行频数统计
age_cnt=age_cut.value_counts()
#频数统计后排序
age_cnt.sort_values(ascending=False)
age_cnt.sort_index(ascending=False)
等宽分箱
width_cut=pd.cut(age,bins=4)#bins=n给定分组数量,n组
width_cut.value_counts().sort_index()
等深/等频分箱
#age样本分成5组
qcut=pd.qcut(age,q=5)
qcut.value_counts()
#按指定比例分组 第一组:0-40%,第二组:40%-80%,第三组:80%-100%
qcut=pd.qcut(age,q=[0,0.4,0.8,1.0])
qcut.value_counts()
数据分箱的意义
-
数据处理、清洗、分析及可视化
-
查看数据分布情况:非常直观的将连续性数据进离散化处理,便于观察数据在各个区间的分布情况和占比情况
-
异常值检测:连续数据离散化处理后,可根据离散化后的结果进行异常值检测
# 故意在数据中添加一些异常值
age[0] = 130
age[1] = 150
# 数据自定义分箱 ---> 频数统计 ---> 结果排序
pd.cut(age, bins=[0, 18, 34, 59, 100, np.inf]).value_counts()