返回首页

Roadmap
更新于 2026年10月27日 全文 2342 字未阅读

第 1.1 节 核心知识点#

预计学习时长: 30 分钟

本节目标:

  • 会用字典创建一个 DataFrame;
  • 知道怎么看一张表有几行几列;
  • 会取出一列或多列,并说清楚它们返回的是什么东西;
  • 看懂 dtypes 输出的 int64 / float64 / object 是什么意思;
  • 会用 head() 和 tail() 预览数据。

本课程使用的 Pandas 版本是 '3.1.0'

DataFrame 是什么#

在动手写代码之前,先建立一个直觉,不然每个方法都会显得很突兀。

在 Pandas 中,DataFrame 其实就是一张二维表格,它和 Excel 里的工作表几乎一样:

  • 有行,有列;

  • 每行是一条记录,每列是一个字段;

  • 行列交汇的格子(称之为 Cell)里存一个值。

但和 Excel 不同的是,DataFrame 是一张有户口本的表,它的每一行都有编号(叫索引 index),每一列都有名字(叫列名 columns)。这两样东西你随时可以换、可以查、可以重设,这也是第 2 章将要重点讲的东西。

在 Pandas 里,有两种基本的数据结构:

结构是什么长什么样
Series一列一维的「带标签的数组」,比如下面订单表里的「城市」这一列
DataFrame整张表二维的「带行标签和列标签的表格」,由多个 Series 拼起来

一句话记住:Series 是一列,DataFrame 是很多列拼起来的表。

现在我们开始把这张表造出来。

本小节示例代码文件: 。

知识点 1:用字典创建 DataFrame#

推荐做法#

Pandas 提供了 pd.DataFrame() 函数。把一个字典传进去,它就变成一张表。

import pandas as pd

data = {
    "订单号":   [1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008],
    "下单日期": ["2024-01-05", "2024-01-08", "2024-01-12", "2024-02-03",
                 "2024-02-15", "2024-03-02", "2024-03-20", "2024-04-08"],
    "城市":     ["北京", "上海", "北京", "广州", "上海", "北京", "深圳", "广州"],
    "商品":     ["手机", "电脑", "耳机", "手机", "键盘", "显示器", "耳机", "手机"],
    "销量":     [2, 1, 3, 2, 5, 1, 4, 2],
    "单价":     [3999.0, 7999.0, 599.0, 3999.0, 299.0, 1299.0, 599.0, 3999.0],
    "金额":     [7998.0, 7999.0, 1797.0, 7998.0, 1495.0, 1299.0, 2396.0, 7998.0],
    "客户评分": [4.5, 4.0, 4.8, 3.9, 4.2, 4.6, 4.1, 4.9],
}

df = pd.DataFrame(data)
df

输出:

     订单号    下单日期  城市  商品  销量  单价      金额  客户评分
0    1001  2024-01-05  北京  手机   2  3999.0   7998.0   4.5
1    1002  2024-01-08  上海  电脑   1  7999.0   7999.0   4.0
2    1003  2024-01-12  北京  耳机   3   599.0   1797.0   4.8
3    1004  2024-02-03  广州  手机   2  3999.0   7998.0   3.9
4    1005  2024-02-15  上海  键盘   5   299.0   1495.0   4.2
5    1006  2024-03-02  北京  显示器  1  1299.0   1299.0   4.6
6    1007  2024-03-20  深圳  耳机   4   599.0   2396.0   4.1
7    1008  2024-04-08  广州  手机   2   3999.0   7998.0   4.9

创建 DataFrame 的 3 要素#

  • 第一,字典的每个键就是列名。 上面的 "订单号"、"城市"…… 一共 8 个键,所以表有 8 列,顺序就是你在字典里写的顺序,列也是按这个顺序排的。

  • 第二,字典的每个值就是这一列的全部数据,而且必须是一个列表(list)。长度为 8,所以表有 8 行。

  • 第三,所有列的长度必须一样。 这是最容易踩的坑:

# 这行会报错
pd.DataFrame({"城市": ["北京", "上海"], "销量": [1, 2, 3]})

报错信息大概长这样:

ValueError: All arrays must be of the same length

翻译过来就是「所有数组长度必须一致」。Pandas 不会帮你猜哪列少一个值,它只会直接罢工。

因此,如果你的数据来自 Excel 或 JSON,构造字典这一步最容易出错,务必先数一下每列有几个值。

从列表创建#

有时候数据本来就是由「一堆行」,每行是个列表或字典。此时,用 pd.DataFrame() 直接传列表也行:

# 传列表:每一行是一个列表
df_rows = pd.DataFrame([
    [1001, "北京", 2],
    [1002, "上海", 1],
], columns=["订单号", "城市", "销量"])

传字典的列表也是常见做法,而且可读性更好:

df_rows = pd.DataFrame([
    {"订单号": 1001, "城市": "北京", "销量": 2},
    {"订单号": 1002, "城市": "上海", "销量": 1},
])

注意这两种写法的区别:传字典时列名来自字典的键;传字典的列表时列名来自每个字典的键的并集,某个字典缺哪个键,那个位置就是空值。

实际工作里怎么选? 如果你的数据是「一列一列」整理好的(比如从 Excel 复制来的几列),用字典;如果你的数据是「一行一行」记下来的(比如接口返回的一堆 JSON 对象),用字典的列表。

从 NumPy 数组创建#

如果你已经有一个二维 NumPy 数组,也可以直接转:

import numpy as np

arr = np.array([[1, 2, 3], [4, 5, 6]])
df_arr = pd.DataFrame(arr, columns=["a", "b", "c"])

如果不通过 columns 指定列名的话,Pandas 会自动用整数 0, 1, 2 当列名。所以实践上一定要传 columns=。

从现有文件读取#

真实工作中数据基本都来自文件,Pandas 提供了一堆 read_xxx 方法:

df = pd.read_csv("orders.csv")          # CSV 文件
df = pd.read_excel("orders.xlsx")       # Excel 文件
df = pd.read_json("orders.json")        # JSON 文件
df = pd.read_sql("SELECT * FROM orders", conn)  # 数据库

本课程不展开讲这些(那是另一个话题),但你要有这个印象:上面所有的 read_xxx 返回的也都是 DataFrame,所以本课程讲的所有操作,对读进来的表一样适用。

知识点 2:查看 DataFrame 的形状#

shape 是最该先看的一个属性#

df.shape 告诉你这张表有几行几列,它返回一个元组(tuple):

df.shape

输出:

(8, 8)

读法是:8 行 8 列。注意顺序是「先行后列」,跟数学里的矩阵一样。

如果你只关心行数或只关心列数:

len(df)        # 行数:8
df.shape[0]    # 行数:8
df.shape[1]    # 列数:8

columns 和 index#

df.columns   # 列名

输出:

Index(['订单号', '下单日期', '城市', '商品', '销量', '单价', '金额', '客户评分'], dtype='object')
df.index     # 行索引

输出:

RangeIndex(start=0, stop=8, step=1)

看懂了这两个,你对一张表就基本有数了:有哪些列、每列叫什么、行是怎么编号的。

一个小坑 df.columns 打印出来带个 Index([...], dtype='object') 的壳,看着有点烦。想看干净的列表,用 df.columns.tolist(),得到的就是一个普通的 Python 列表:

df.columns.tolist()
# ['订单号', '下单日期', '城市', '商品', '销量', '单价', '金额', '客户评分']

空表检查#

拿到数据先确认一下「它到底有没有东西」:

pd.DataFrame().shape          # (0, 0)——完全空的表
pd.DataFrame({"a": []}).shape # (1, 0)——一列,但一行都没有

如果是 (0, 0),说明你的字典是空的或者读文件失败了,值得回头查一下。

知识点 3:选择 DataFrame 的列#

这一节是本课程最容易搞混的地方,所以讲慢一点。

仅取一列#

df["城市"]

输出:

0    北京
1    上海
2    北京
3    广州
4    上海
5    北京
6    深圳
7    广州
Name: 城市, dtype: object

此时返回的是 Series(一列)。

如果你想把它存起来:

cities = df["城市"]
type(cities)   # <class 'pandas.core.series.Series'>

同时取多列#

注意这里有两层方括号,外层是「取东西」的语法,内层的中括号是一个 Python 列表,里面装着列名。

subset = df[["城市", "商品", "销量"]]
subset

输出:

  城市  商品  销量
0  北京  手机   2
1  上海  电脑   1
2  北京  耳机   3
3  广州  手机   2
4  上海  键盘   5
5  北京  显示器   1
6  深圳  耳机   4
7  广州  手机   2

返回的是 DataFrame(一张表)。

两者的区别#

用一句话说清:

  • 单层方括号 df["列名"] → Series(一列,带索引)。

  • 双层方括号 df[["列名1", "列名2"]] → DataFrame(一张表)。

为什么要设计成两种?因为它们在后续操作上真的不一样:

df["销量"].sum()      # 对这一列求和 → 一个数字 20
df[["销量"]].sum()    # 对这张表(只有一列)求和 → 一张表
df["销量"] * 2        # 每一列都乘 2 → Series
df[["销量"]] * 2      # 整张表乘 2 → DataFrame

上面两个 * 2 的输出长得几乎一样,但返回的类型不同,后面能接的方法也不同。多花一秒钟记住这个区别,能省掉后面一堆「为什么我的代码报错了」的困惑。

取不存在的列会怎样#

df["性别"]   # KeyError: '性别'

报错了。因为 Pandas 不知道「性别」这一列该放什么值。

如果你想「有就用,没有就返回空表」,可以用 df.get("性别"):

df.get("性别")   # 返回 None,不报错

知识点 4:理解数据类型#

看某一列的类型#

df["销量"].dtype

输出:

dtype('int64')

看所有列的类型#

df.dtypes

输出:

订单号       int64
下单日期      str
城市         str
商品         str
销量         int64
单价       float64
金额       float64
客户评分    float64
dtype: object

后缀是什么意思#

初学者看到 int64、str 这种名字常一脸茫然。其实它们就是「数据类型 + 内存宽度」:

类型全称 / 含义什么时候出现例子
int6464 位整数整数字面量,全都是整数时销量、订单号
float6464 位浮点数有小数点,或整数和小数混在一起单价、金额、客户评分
str字符串对象类型装了字符串时城市、商品、下单日期
bool布尔值只有 True / False某个「是否已付款」的标记列
datetime64[ns]日期时间专门转成日期类型之后df["下单日期"] 转成日期后

几点要留意的:

第一,为什么「销量」是 int64 而「金额」是 float64? 因为 Python 里 2 是整数、7998.0 是小数,Pandas 原样保留了。这就是为什么你写数据时要注意:想要整数就写 7998,别写 7998.0。

pd.DataFrame({"a": [1, 2]}).dtypes["a"]      # int64
pd.DataFrame({"a": [1.0, 2.0]}).dtypes["a"]  # float64

第二,把一列里混着数字和文字,会强制变成 object。 这是实际工作里最常见的「数据脏」的来源,第 3 章会专门讲怎么处理它。

info()比 dtypes 更全#

df.info()

输出:

<class 'pandas.DataFrame'>
RangeIndex: 8 entries, 0 to 7
Data columns (total 8 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   订单号     8 non-null      int64  
 1   下单日期    8 non-null      str    
 2   城市      8 non-null      str    
 3   商品      8 non-null      str    
 4   销量      8 non-null      int64  
 5   单价      8 non-null      float64
 6   金额      8 non-null      float64
 7   客户评分    8 non-null      float64
dtypes: float64(3), int64(2), str(3)
memory usage: 644.0 bytes

这行信息非常有用,请重点看 Non-Null Count 这一列:

  • 如果显示 8 non-null,说明这列 8 个值一个不缺;

  • 如果显示 6 non-null,说明有 2 个缺失值(8 - 6 = 2)。

上面每一列都是 8 non-null,说明我们的数据是干净的。等你面对真实的 Excel 文件时,这一列会立刻帮你定位到哪些列有窟窿。

describe()数值列的统计摘要#

df.describe()

输出:

               订单号        销量           单价          金额      客户评分
count     8.00000  8.000000     8.000000     8.00000  8.000000
mean   1004.50000  2.500000  2849.000000  4872.50000  4.375000
std      2.44949  1.414214  2659.752942  3356.23969  0.377018
min    1001.00000  1.000000   299.000000  1299.00000  3.900000
25%    1002.75000  1.750000   599.000000  1721.50000  4.075000
50%    1004.50000  2.000000  2649.000000  5197.00000  4.350000
75%    1006.25000  3.250000  3999.000000  7998.00000  4.650000
max    1008.00000  5.000000  7999.000000  7999.00000  4.900000

每一行是一个统计量:

  • count——有多少个非空值;

  • mean——平均值;

  • std——标准差,衡量数据有多分散;

  • min / max——最小值和最大值;

  • 25% / 50% / 75%——四分位数,50% 就是中位数。

只统计数值列,字符串列自动被跳过。如果你想让字符串列也参与统计(比如看每个城市出现了几次):

df.describe(include="all")

知识点 5:head() 和 tail()#

表可能有几百万行,一屏根本显示不下。head() 和 tail() 让你只看头尾几行。

head() 看开头#

df.head()

默认显示前 5 行:

     订单号        下单日期  城市  商品  销量      单价      金额  客户评分
0    1001  2024-01-05  北京  手机   2  3999.0   7998.0   4.5
1    1002  2024-01-08  上海  电脑   1  7999.0   7999.0   4.0
2    1003  2024-01-12  北京  耳机   3   599.0   1797.0   4.8
3    1004  2024-02-03  广州  手机   2  3999.0   7998.0   3.9
4    1005  2024-02-15  上海  键盘   5   299.0   1495.0   4.2

想看 3 行就传参数:

df.head(3)

tail() 看结尾#

df.tail(3)

输出:

     订单号        下单日期  城市  商品  销量      单价      金额  客户评分
5    1006  2024-03-02  北京  显示器   1  1299.0   1299.0   4.6
6    1007  2024-03-20  深圳  耳机   4   599.0   2396.0   4.1
7    1008  2024-04-08  广州  手机   2  3999.0   7998.0   4.9

它们俩有什么区别#

一句话: head() 从上往下看,tail() 从下往上看。

但它们的用途经常被搞混:

场景用哪个为什么
想知道数据长什么样、字段什么含义head()开头几行通常最完整规范
想知道数据是怎么「结束」的tail()结尾常暴露格式不一致、导出截断等问题
排查「最后几行是不是空的」tail()很多系统导出会在末尾留空行

一个实战小技巧:拿到陌生数据,先 head() 看结构,再 tail() 看有没有脏尾巴。两次加起来 10 行,基本就能把这张表的「长相」摸清。

注意: head() 返回的是新的一份数据(前 5 行),改它不会影响 df。但如果你想修改原表的前几行,请用 df.head() 之前先 df = df.head() 重新赋值,或者直接用 df.loc[...]。这是第 2 章的内容。

本节小结#

回顾一下这一节的 5 个知识点:

你想做的事用这个得到什么
造一张表pd.DataFrame(字典)DataFrame
看几行几列df.shape(行数, 列数)
看列名 / 行号df.columns / df.index列名列表 / 行索引
取一列df["城市"]Series
取多列df[["城市", "销量"]]DataFrame
看数据类型df.dtypes / df.info()每列的类型和缺失情况
看数值摘要df.describe()均值、中位数、标准差等
预览数据df.head() / df.tail()头几行 / 尾几行

拿到陌生数据的固定三步: ① df.shape 看规模;② df.info() 看类型和缺失;③ df.head() 看长相。三步做完,一张表在你心里就有轮廓了。

下一节我们不学新东西,而是动手把这 5 个操作练熟,顺便把「取一列和多列到底差在哪」这个问题彻底解决。

阅读 --