📊 第4章 Pandas 进阶
📄 一句话概括

to_excel 一次只能写一张表,要写多张必须走 ExcelWriter。 index=False 几乎每次都要加,否则表里多出一列没有名字的序号。 日期必须是 datetime 类型,是字符串就排不了序、算不了间隔、画不了时间轴。

📝 本章和前面几章的关系

算完的东西得交出去。这一篇讲两件事:怎么导出、日期怎么处理。 日期单列一篇是有原因的:它是数据分析里最容易出错、也最容易被忽略的一块。

一、导出到一张表

df.to_excel('导出.xlsx', index=False, sheet_name='成绩'),一行写完。 这次写出去 5807 字节,读回来形状还是 (10, 6),一个字节都没丢。 index=False 几乎每次都要加。忘了他,Excel 里会多出一列没名字的序号。

那一列在别人手里就是个麻烦:删了怕有问题,不删又多一列。 sheet_name 不给就是 Sheet1。给人看的文件,表名取清楚点。

二、一个文件多张表:ExcelWriter

with pd.ExcelWriter(路径) as w: 然后在里面连续 to_excel(w, sheet_name=...)。 这次写出 3 张表:成绩、班主任、班级均值。读回来 sheet_name=None 拿到 3 个键。 to_excel 一次只能写一张表。要写多张必须走 ExcelWriter。

老办法是先写一张再 mode='a' 追加,麻烦还容易覆盖。用 with 最省心。 上下文管理器退出时自动保存并关闭。不 close 的文件是 0 字节——这条老账要记住。

三、转成日期:to_datetime

pd.to_datetime(['2026-01-05', '2026/1/6', '20260107'], format='mixed')。 三种写法都能认,得到 2026-01-05、01-06、01-07,类型是 datetime64[us]。 pandas 3 要显式写 format='mixed' 才能混着猜,不写会报错。

中文日期它不认:「2026年1月8日」直接 DateParseError,得自己换成 2026-1-8。 这一步很常见:从网页或 Word 里拷出来的日期,十有八九带「年月日」。

四、取出年月日与间隔

日期 年 月 星期
2026-01-05 2026 1 0
2026-01-06 2026 1 1
2026-01-07 2026 1 2

.dt 是日期专用的入口,year、month、day、hour 都挂在它下面。 星期用 day_of_week,周一是 0。老写法 dayofweek 还能用,但会报废弃警告。 两个日期一减得到 Timedelta:2 days 00:00:00。

日期减日期给的是「时间差」,不是数字。要天数写 .days,要秒写 .total_seconds()。

五、动手 Demo:数据导出与日期处理

先导一张表、再导三张表到一个文件,然后处理三种格式的日期。 最后取出年月日,算两个日期差。

import os
import pandas as pd

D = pd.DataFrame({"姓名": ["张伟", "王芳"], "语文": [88, 92]})
D.to_excel("导出.xlsx", index=False, sheet_name="成绩")
print("字节 %d,读回 %s" % (os.path.getsize("导出.xlsx"),
                             pd.read_excel("导出.xlsx").shape))

with pd.ExcelWriter("多表.xlsx") as w:
    D.to_excel(w, sheet_name="成绩", index=False)
    D.to_excel(w, sheet_name="备份", index=False)
print("多表:%s" % list(pd.read_excel("多表.xlsx", sheet_name=None).keys()))

DT = pd.to_datetime(["2026-01-05", "2026/1/6", "20260107"], format="mixed")
print("日期 %s" % [str(v)[:10] for v in DT])
print("类型 %s" % DT.dtype)

T = pd.DataFrame({"日期": DT})
T["年"] = T["日期"].dt.year
T["星期"] = T["日期"].dt.day_of_week
print(T.to_string(index=False))
print("间隔 %s,共 %d 天" % (DT[2] - DT[0], (DT[2] - DT[0]).days))

实跑输出:

--------------------------------------------------------------------
数据导出与日期处理
--------------------------------------------------------------------

  ① 导出到一张表
  --------------------------------------------------------------------
  写出去 5807 字节,读回来 (10, 6)。
  index=False 是不写行号。不写这一条,Excel 里会多出一列没有名字的序号。
  ! index=False 几乎每次都要加。忘了它,别人打开就看到一列莫名其妙的 0、1、2。

  ② 一个文件多张表:ExcelWriter
  --------------------------------------------------------------------
  一个文件里 3 张表:成绩、班主任、班级均值。
  用 ExcelWriter 上下文管理器,写多张表只需要一个文件句柄。
  ! to_excel 一次只能写一张表。要写多张,必须走 ExcelWriter。

  ③ 转成日期:to_datetime
  --------------------------------------------------------------------
  三种写法都能认:2026-01-05、2026-01-06、2026-01-07。
  pandas 3 要显式写 format='mixed' 才能混着猜,不然会报错。
  类型是 datetime64[us],不是字符串。
  中文日期它不认:「2026年1月8日」直接报 DateParseError。
  先换成 2026-1-8 这样的写法,再读就好了:2026-01-08。
  ! 日期读进来必须是 datetime 类型。是字符串就排不了序、算不了间隔、画不了时间轴。

  ④ 取出年月日与间隔
  --------------------------------------------------------------------

| 行 | 日期 | 年 | 月 | 星期 |
|---|---:|---:|---:|---:|
| 0 | 2026-01-05 00:00:00 | 2026 | 1 | 0 |
| 1 | 2026-01-06 00:00:00 | 2026 | 1 | 1 |
| 2 | 2026-01-07 00:00:00 | 2026 | 1 | 2 |

  .dt 是「日期专用」的入口,year/month/day/hour 都挂在它下面。
  星期用的是 day_of_week,周一是 0。老写法 dayofweek 还能用,但会报 DeprecationWarning。
  两个日期一减得到 Timedelta:2 days 00:00:00。
  要天数就 .days,要秒数就 .total_seconds()。
  ! 日期减日期给的是「时间差」,不是数字。直接拿去算会报类型错。

字节数每次可能差几个字节(Excel 里存时间戳),形状 (2, 2) 才是要核的东西。 (DT[2] - DT[0]).days 给整数,直接拿 Timedelta 去算是会报错的。

30 秒实验

  1. 把 to_excel 的 index=False 去掉,再读回来看看多没多一列。
  2. 把 format='mixed' 去掉,看报什么错。
  3. 想一想:把日期当字符串存进 Excel,别人再读回来会是什么类型?

常见误区

  1. 忘了 index=False:文件里多一列没名字的序号。
  2. 一张一张 to_excel 想写进同一文件:后一次把前一次覆盖了。
  3. to_datetime 不写 format='mixed':格式一混就报错。
  4. 中文日期直接喂进去:DateParseError,得先清洗。
自测三问(点开对答案) 1. 为什么要用 ExcelWriter? —— to_excel 一次只能写一张表。要一个文件装多张,必须靠 ExcelWriter 统一管理。 2. 日期读进来是字符串会有什么后果? —— 排不了序(按字典序排)、算不了间隔、画不了时间轴、resample 直接报错。 3. Timedelta 怎么取出天数? —— 加 .days 取整天数,.total_seconds() 取秒数。直接拿去算会报类型错。

最后一篇:把日期当索引,按周按月汇总,这就是时间序列。

相关笔记