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