📈 第13章 整理数据
📄 一句话概括

拆列就是找一个字符,按它下刀。Excel 里叫「分列」,代码里就是 split。 拆完才有「列」这个概念,才能算「某个城市的平均等级」「按电话去重」。 一行一个字符串的时候你只能靠眼睛找;拆成列之后,程序才能替你找。

📝 本章和前面几章的关系

上一篇把形状统一了。这一篇做那件最机械、也最关键的事:切。 这一步是整章的地基。地基不牢,后面所有清洗都是在歪墙上刷漆。

一、拆列就是按一个字符下刀

「张三#13901234567#北京 朝阳#2023-05-01#VIP」按井号一拆,就是五个值。 书里在 Excel 里叫「分列」:选分隔符、点完成。代码里就是 split。 动作完全一样:找一个字符,按它下刀。

所以工具不是重点。重点是那个字符必须真的只用来分隔字段。

二、为什么要拆成列

分析都是按列做的:算某个城市的平均等级、按日期排序、按电话去重。 一行一个字符串的时候,字段的位置不固定,切不开就没法按列操作。 你能做的只有「用眼睛找」,而眼睛找不了六万行。

结构化不是为了好看,是为了让「按某一列做运算」这件事成为可能。 这一步之后,「数据」才从一堆文本变成一张表。

三、拆完立刻做三件事

第一件:数行数。拆列不该改变行数,变了就说明有行被吞掉或撑开。 第二件:数每行的段数。有行不是五段,说明前面准备工作没做完。 第三件:抽前五行看一眼。看字段有没有错位——电话列里出现城市,就是错位。

三件事都是十秒钟的活,但能挡住后面几小时的返工。 拆列是「一次成型」的动作,拆错了整张表都得重来。

四、错位长什么样

如果某行只有四段而你没补,按五列解包时会有两种结果。 严格的工具直接报错,说这一行长度不对。这算好的,至少你知道出事了。 宽松的工具会把日期放进城市列、把等级放进日期列,最后等级列空着。

后一种最坏:它不报错,只是从此你的「城市」里混进了日期。

五、拆完的列还是脏的

列拆开了,但内容还没洗:姓名里有 ^ 和空格,电话有 +86 和横杠。 这些不影响「拆列」,只影响「按这一列匹配」。 所以下一篇开始洗内容。顺序还是那个:先形状,后内容。

六、动手 Demo:按分隔符拆成多列

拿六行样例:统一分隔符,切分,按五列摆成表。 再故意留一行四段的,看它拆出来错位成什么样子。

ROWS = [
    "王^小明#+861300001000# 北京 朝阳 #2023-01-01#VIP",
    "李娜#139-0000-3271#上海 浦东#2023-02-02#A",
    "张静/13800005626/广州 天河/2023-03-03/B",
    "刘艳,13800005939,深圳 南山,2023-04-04,C",
    "陈芳#13800006252#杭州 西湖#2023-05-05#VIP",
    "杨强#13800006565#2023-06-06#A",
]

# 第一步:统一分隔符
fixed = [s.replace("/", "#").replace(",", "#") for s in ROWS]

# 第二步:切
seg = [s.split("#") for s in fixed]
for i, x in enumerate(seg):
    print("第 %d 行:%d 段" % (i + 1, len(x)))

# 第三步:按五列摆开(四段的行会错位)
print()
for x in seg:
    x = (x + [""] * 5)[:5]
    print("%-8s %-15s %-12s %-12s %s" % tuple(x))

实跑输出:

--------------------------------------------------------------------
按分隔符拆成多列
--------------------------------------------------------------------

  ① 拆列就是把一行的字符串切成几段
  --------------------------------------------------------------------
  「张三#13901234567#北京 朝阳#2023-05-01#VIP」按 # 一拆,就是五个值。
  书里在 Excel 里叫「分列」,选分隔符、点完成。这里就是 split。
  动作完全一样:找一个字符,按它下刀。

  ② 拆完的样子
  --------------------------------------------------------------------

| 姓名 | 电话 | 城市 | 日期 | 等级 |
|---|---|---|---|---|
| 王^小明 | +8613000001000 |  北京 朝阳  | 2023-01-01 | VIP |
| 李娜 | 139-0000-3271 | 上海 浦东 | 2023-02-02 | A |
| 张静 | 13800005626 | 广州 天河 | 2023-03-03 | B |
| 刘艳 | 13800005939 | 深圳 南山 | 2023-04-04 | C |
| 陈芳 | 13800006252 | 杭州 西湖 | 2023-05-05 | VIP |

  五列都在,位置也对。这一步看着平淡,但它是整章的地基。

  ③ 为什么一定要用「列」而不是「行」
  --------------------------------------------------------------------
  分析是按列做的:算某个城市的平均等级、按日期排序、按电话去重。
  字符串里一个字段的位置是不固定的,切不开就没法按列操作。
  结构化不是好看,是让「按某一列做运算」这件事成为可能。
  一行一个字符串的时候,你只能靠眼睛找;拆成列之后,程序才能替你找。

  ④ 段数不齐的行会怎样
  --------------------------------------------------------------------
  如果不先补段数直接拆:第 6 行会错位。
  它只有四段,拆出来「城市」这一列装的是日期,「等级」这一列是空的。
  错位不会报错,只会让后面的统计全歪。这是清洗里最难发现的一类错。

  ⑤ 拆完之后立刻看第一列
  --------------------------------------------------------------------
  列拆开了,但内容还没洗:姓名里有 ^ 和空格,电话有 +86 和横杠。
  这些留着不影响「拆列」这件事,只影响「按这一列匹配」这件事。
  下一篇开始洗内容。顺序还是那个:先形状,后内容。

最后一行是四段的,摆出来之后「城市」那一列装的是日期,「日期」那一列装的是等级。 错位不会报错,只会错得很安静。 注意打印时用的是定宽格式(%-8s):窄了会挤在一起,看上去像错位, 其实是显示问题——排错前先确认自己看的是不是真的。

30 秒实验

  1. 如果某一行的城市名里本来就有井号(比如「北京#朝阳」),拆列会出什么问题?
  2. 除了井号,还有什么字符不适合当分隔符?为什么?
  3. 想一想:为什么「拆完数一下每行几段」这么简单的检查,能省下大量返工?

常见误区

  1. 不检查段数就拆:四段的行会错位,而且不报错。
  2. 用会出现在内容里的字符当分隔符:城市名、备注里都可能有,一拆就多列。
  3. 拆完不抽看前几行:错位往往前几行就能看出来。
  4. 以为拆完就干净了:拆列只解决形状,内容还是脏的。
自测三问(点开对答案) 1. 拆列的本质动作是什么? —— 按一个指定的字符把字符串切成几段。Excel 叫分列,代码叫 split,本质一样。 2. 为什么拆完要立刻数段数? —— 段数不齐说明有行缺字段,直接按固定列数解包会错位,而错位通常不报错。 3. 拆列之后数据算「能用」了吗? —— 还不算。字段位置对了,但内容还有 +86、^、空格这些问题,匹配和统计仍会出错。

列有了,内容还脏。下一篇开始洗内容:把 ^、+86、横杠、多余空格一个个拿掉。

相关笔记