|
之前我们已经介绍了 pandas的基础使用用法,这一期我们来看看这个包其他有意思的方法
一、排序
1.1 对Series排序
对Series的排序,主要是两个参数,一个是ascending,代表是否升序排列,另一个就是很熟悉的inplace 了
sr = pd.Series([2,3,8,4,5])
sr.sort_values(ascending=False,inplace=True) # 降序排序,同时替换原有DataFrame
print(sr)
输出的结果为,注意排序后index的顺序也会跟着变:
2 8 4 5 3 4 1 3 0 2 dtype: int64
1.2 对DataFrame排序
由于DataFrame是二维的,因此排序时多了一个参数by,表示按照哪一列进行排序,同时ascending也支持布尔数组,实现多条件的排序,如下:
df = pd.DataFrame({"A":["B","A","B","B","A"],
"B":[2,3,8,4,5],
"C":[11,2,7,4,5]})
# 单条件排序
df.sort_values(by="B",ascending=True,inplace=True)
print(df)
单条件的排序结果为:
A B C 0 B 2 11 1 A 3 2 3 B 4 4 4 A 5 5 2 B 8 7
而对于多条件排序,by和ascending一一对应,代表应该是升序还是降序
# 多条件排序
df.sort_values(by=["A","B"],ascending=[False,True],inplace=True)
print(df)
多条件排序输出结果如下,首先按照A列降序排序,然后按照B列升序排序,所以有一个主次的关系:
A B C 0 B 2 11 3 B 4 4 2 B 8 7 1 A 3 2 4 A 5 5
二、字符串和日期处理
对于字符串的处理,我们一般都使用str进行,而对于日期,我们用dt,直接通过底下的代码我们来看
df = pd.DataFrame({"姓名":["张三","李四","王五","赵六","王二"],
"出生日期":["2000-01-01","2001-02-02","2002-03-03","2003-04-04","2004-05-05"],
"分数":["90分","29分","78分","46分","57分"]})
print(df.dtypes)
print("="*30)
df["出生日期"] = pd.to_datetime(df["出生日期"]) # 转换为日期类型
print(df["出生日期"].dtype) # datetime64[ns]
# df["出生日期"] = df["出生日期"].str.replace("1","") # 错误用法,str只能为字符串服务
df["出生日期"] = df["出生日期"].dt.strftime("%Y-%m-%d") # 转换为字符串类型
print(df["出生日期"].dtype) # object
df["分数"] = df["分数"].str.replace("分","").astype(int) # 转换为整数类型
print(df)
输出如下,我们一个一个做分析,首先我们定义了一个DataFrame,可以发现初始都是字符串,因此输出为object,然后我们通过to_datetime将其改成了标准的日期格式,因此输出为datetime64[ns],同样我们也可以通过dt.strftime将其转换为字符串格式,对于字符串格式,我们可以使用str下的若干方法进行处理,上述演示中只是将“分”这个字删除,并转换为整型:
姓名 object 出生日期 object 分数 object dtype: object ============================== datetime64[ns] object 姓名 出生日期 分数 0 张三 2000-01-01 90 1 李四 2001-02-02 29 2 王五 2002-03-03 78 3 赵六 2003-04-04 46 4 王二 2004-05-05 57
同时pandas严格约定str只服务于字符串,如果对其他格式使用,则会报错,对于字符串的处理,还有一个很强大的工具就是正则表达式,我们同样可以使用正则表达式进行处理,但是注意使用regex=True告诉程序这个是正则表达式:
# 常规复杂的三步替换
df["出生日期"] = df["出生日期"].str.replace("年","").str.replace("月","").str.replace("日","")
# 正则表达式替换
df["出生日期"] = df["出生日期"].str.replace("[年月日]","",regex=True)
三、DataFrame的连接
如果需要做DataFrame的连接,我们常常使用concat方法,其重要的三个参数分别是
axis=0 代表按行连接,否则是按列连接ignore_index=True 表示重新生成一个新的索引,否则保留原始索引join="outer" 表示保留所有非重复字段,join="inner"则表示只保留重合字段
df1 = pd.DataFrame({"A":[1,2,3],
"B":[6,7,8]})
df2 = pd.DataFrame({"B":[4,5,6],
"F":[9,10,11]})
print(pd.concat([df1,df2],axis=1))
print(pd.concat([df1,df2],axis=0,ignore_index=True,join="outer"))
输出结果为:
A B B F 0 1 6 4 9 1 2 7 5 10 2 3 8 6 11 A B F 0 1.0 6 NaN 1 2.0 7 NaN 2 3.0 8 NaN 3 NaN 4 9.0 4 NaN 5 10.0 5 NaN 6 11.0
在输出中,如果 ignore_index=False ,左侧就是原始索引 [0,1,2,0,1,2],而如果使用join="inner"则只会保留重合的B列
同时Concat还支持DataFrame 与Series的混合拼接,例如:
sr1 = pd.Series([1,2,3],name="sr1")
sr2 = pd.Series([6,7,8,],name="sr2")
print(pd.concat([sr1,df1,df2,sr2],axis=1)) # 混合拼接
输出结果为:
sr1 A B B F sr2 0 1 1 6 4 9 6 1 2 2 7 5 10 7 2 3 3 8 6 11 8
四、EXCEL表格批量合并和拆分
4.1 批量进行表格合并
之前我们已经学习了那么多的pandas使用技巧,那么接下来我们就看看上面讲到的比如Concat在实际过程中有什么用吧,比如我们先看一下批量的合并,既然要合并,不过就是DataFrame的拼接,在某个文件夹下有若干个xlsx文件,我们需要合并到一张表里,这些子表的表头都是相同的:
那么我们通过下面的程序进行合并,首先获取文件夹下所有的xlsx文件,然后读取DataFrame,紧接着添加一个标识列,代表从哪个数据表中拿到的,最后合并并保存,在这里Concat就起到了将各个DataFrame合并在一起的功能
son_file_path = r"C:\Users\22330\Desktop\进行中\子文件"
file_to_save = r"C:\Users\22330\Desktop\进行中\Data_combine.xlsx"
df_lists = [] # 用于存储每个子文件的DataFrame
for item in os.listdir(son_file_path):
if item.endswith(".xlsx"):
file_path = os.path.join(son_file_path,item)
df = pd.read_excel(file_path)
df["son_id"] = item.split(".")[0] # 提取子文件的id作为新的一列
df_lists.append(df) # 将当前子文件的DataFrame添加到列表中
# 使用Concat合并所有子文件的DataFrame
pd.concat(df_lists,axis=0).to_excel(file_to_save,index=False)
最后输出的文件中,就会多出我们新增的一列son_id,整个的处理非常迅速。
4.2 批量进行表格拆分
既然已经讲了合并,我们顺手也来看看拆分,我们的拆分需求是将表格平均分到若干个表里,在下面的程序中,我通过son_file_num 定义了要拆分的个数,通过考虑了除不尽的情况,然后依次按索引取值,放到每个表中
import pandas as pd
import os
file_path = r"C:\Users\22330\Desktop\进行中\Data.xlsx"
save_path = r"C:\Users\22330\Desktop\进行中\子文件"
if not os.path.exists(save_path): # 如果子文件目录不存在,就创建一个
os.mkdir(save_path)
df = pd.read_excel(file_path)
print(df.head(3)) # 查看前3行数据
print(df.shape) # 查看数据条数和特征数
son_file_num = 4
son_file_size = df.shape[0] // son_file_num # 每个子文件的数据条数
if df.shape[0] % son_file_num != 0: # 如果数据条数不能被子文件数整除,需要额外增加一条数据
son_file_size += 1
for i in range(son_file_num):
start = i * son_file_size
end = start + son_file_size
df_son = df.iloc[start:end] # 这里的end是不包含在切片中的,所以不需要-1
df_son.to_excel(f"{save_path}\{file_path.split('.')[1]}_{i}.xlsx",index=False)
命令行输出了我们的一些调试信息,可想而知,会按152:152:152:150 的比例分配数据,实现拆分
出库日期 产品经理 产品类别 地区 安全等级 销售额(元) 销售数量 客户评分 0 2023-06-01 Jerry 电子产品 西南 C 3789.6 12 5.0 1 2023-06-02 Cary 服装 华东 A 2345.3 14 5.0 2 2023-06-03 Bob-Smith 家居用品 西北 D 567.8 7 3.7 (606, 8)
|