列表(Lists)
Python 最常用的数据结构 —— 理解 R vector 和 Stata 变量的 Python 版本
什么是列表?
列表(List)是 Python 中最基础的数据结构,用于存储有序的、可修改的元素集合。
对比理解
| 概念 | Python | R | Stata |
|---|---|---|---|
| 有序集合 | list | vector(向量) | 变量(Variable) |
| 示例 | [1, 2, 3] | c(1, 2, 3) | gen x = ... |
关键特点:
- 有序:元素有固定顺序
- 可变:可以修改、添加、删除元素
- 允许重复:同一个值可以出现多次
- 混合类型:可以包含不同类型的数据(但不推荐)
创建列表
1. 基本创建
python
# 空列表
empty_list = []
# 整数列表
ages = [25, 30, 35, 40, 45]
# 字符串列表
names = ["Alice", "Bob", "Carol", "David"]
# 混合类型(不推荐,但可以)
mixed = [25, "Alice", 3.14, True]
print(ages) # [25, 30, 35, 40, 45]
print(names) # ['Alice', 'Bob', 'Carol', 'David']2. 使用 range() 创建
python
# 生成 0 到 9
numbers = list(range(10))
print(numbers) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 生成 1 到 10
numbers = list(range(1, 11))
print(numbers) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 生成偶数
evens = list(range(0, 20, 2))
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]3. 使用列表推导式
python
# 生成平方数
squares = [x**2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
# 生成偶数
evens = [x for x in range(20) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]访问列表元素
1. 索引访问(从 0 开始)
python
students = ["Alice", "Bob", "Carol", "David", "Emma"]
# 正向索引(从 0 开始)
print(students[0]) # Alice(第1个)
print(students[1]) # Bob(第2个)
print(students[4]) # Emma(第5个)
# 负向索引(从 -1 开始)
print(students[-1]) # Emma(最后一个)
print(students[-2]) # David(倒数第2个)️ 注意:Python 索引从 0 开始,而 R 和 Stata 从 1 开始!
| 语言 | 第一个元素 | 最后一个元素 |
|---|---|---|
| Python | list[0] | list[-1] |
| R | vector[1] | vector[length(vector)] |
| Stata | var[1] | var[_N] |
2. 切片(Slicing)
python
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 基本切片 [start:end](不包括 end)
print(numbers[2:5]) # [2, 3, 4]
print(numbers[0:3]) # [0, 1, 2]
print(numbers[5:]) # [5, 6, 7, 8, 9](从索引5到结尾)
print(numbers[:5]) # [0, 1, 2, 3, 4](从开头到索引5)
print(numbers[:]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9](全部)
# 带步长的切片 [start:end:step]
print(numbers[::2]) # [0, 2, 4, 6, 8](每隔一个)
print(numbers[1::2]) # [1, 3, 5, 7, 9](奇数)
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0](反转)社科应用示例:
python
# 受访者年龄数据
ages = [25, 28, 30, 35, 40, 45, 50, 55, 60, 65]
# 获取前5个受访者
first_five = ages[:5]
print(first_five) # [25, 28, 30, 35, 40]
# 获取后5个受访者
last_five = ages[-5:]
print(last_five) # [45, 50, 55, 60, 65]
# 获取中年组(索引2到7)
middle_age = ages[2:7]
print(middle_age) # [30, 35, 40, 45, 50]️ 修改列表
1. 修改单个元素
python
scores = [85, 90, 78, 92, 88]
# 修改第一个成绩
scores[0] = 95
print(scores) # [95, 90, 78, 92, 88]
# 修改最后一个成绩
scores[-1] = 90
print(scores) # [95, 90, 78, 92, 90]2. 添加元素
python
students = ["Alice", "Bob"]
# append(): 在末尾添加一个元素
students.append("Carol")
print(students) # ['Alice', 'Bob', 'Carol']
# insert(): 在指定位置插入
students.insert(1, "David") # 在索引1处插入
print(students) # ['Alice', 'David', 'Bob', 'Carol']
# extend(): 添加多个元素
students.extend(["Emma", "Frank"])
print(students) # ['Alice', 'David', 'Bob', 'Carol', 'Emma', 'Frank']
# + 运算符: 合并列表
new_students = students + ["Grace", "Henry"]
print(new_students) # ['Alice', 'David', 'Bob', 'Carol', 'Emma', 'Frank', 'Grace', 'Henry']3. 删除元素
python
numbers = [1, 2, 3, 4, 5, 3]
# remove(): 删除第一个匹配的值
numbers.remove(3)
print(numbers) # [1, 2, 4, 5, 3](只删除了第一个3)
# pop(): 删除指定索引的元素(默认最后一个)
last = numbers.pop()
print(last) # 3
print(numbers) # [1, 2, 4, 5]
first = numbers.pop(0)
print(first) # 1
print(numbers) # [2, 4, 5]
# del: 删除指定索引或切片
del numbers[1]
print(numbers) # [2, 5]
# clear(): 清空列表
numbers.clear()
print(numbers) # []列表操作
1. 基本操作
python
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
# 长度
print(len(numbers)) # 8
# 最大值/最小值/求和
print(max(numbers)) # 9
print(min(numbers)) # 1
print(sum(numbers)) # 31
# 平均值(需要自己计算)
average = sum(numbers) / len(numbers)
print(average) # 3.875
# 排序(修改原列表)
numbers.sort()
print(numbers) # [1, 1, 2, 3, 4, 5, 6, 9]
# 反转
numbers.reverse()
print(numbers) # [9, 6, 5, 4, 3, 2, 1, 1]
# sorted(): 返回新列表(不修改原列表)
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
sorted_numbers = sorted(numbers)
print(sorted_numbers) # [1, 1, 2, 3, 4, 5, 6, 9]
print(numbers) # [3, 1, 4, 1, 5, 9, 2, 6](原列表未变)2. 查找元素
python
majors = ["Economics", "Sociology", "Economics", "Political Science"]
# count(): 统计出现次数
print(majors.count("Economics")) # 2
# index(): 找到第一次出现的索引
print(majors.index("Sociology")) # 1
# in: 检查是否存在
print("Economics" in majors) # True
print("Physics" in majors) # False实战案例
案例 1:问卷分数统计
python
# 学生成绩
scores = [85, 92, 78, 90, 88, 76, 95, 82, 89, 91]
# 描述性统计
print("=== 成绩统计 ===")
print(f"样本量: {len(scores)}")
print(f"最高分: {max(scores)}")
print(f"最低分: {min(scores)}")
print(f"总分: {sum(scores)}")
print(f"平均分: {sum(scores)/len(scores):.2f}")
# 及格率
passing = [s for s in scores if s >= 60]
passing_rate = len(passing) / len(scores) * 100
print(f"及格率: {passing_rate:.1f}%")
# 成绩分布
excellent = len([s for s in scores if s >= 90])
good = len([s for s in scores if 80 <= s < 90])
fair = len([s for s in scores if 70 <= s < 80])
poor = len([s for s in scores if s < 70])
print(f"\n=== 成绩分布 ===")
print(f"优秀(90+): {excellent} 人")
print(f"良好(80-89): {good} 人")
print(f"中等(70-79): {fair} 人")
print(f"及格(60-69): {poor} 人")案例 2:收入数据清洗
python
# 原始收入数据(包含异常值)
raw_incomes = [50000, 65000, -5000, 80000, 1000000, 55000, 70000, 0]
# 数据清洗
print("=== 收入数据清洗 ===")
print(f"原始数据量: {len(raw_incomes)}")
# 筛选有效数据(非负且不超过50万)
clean_incomes = []
for income in raw_incomes:
if 0 < income <= 500000:
clean_incomes.append(income)
print(f"清洗后数据量: {len(clean_incomes)}")
print(f"剔除数据量: {len(raw_incomes) - len(clean_incomes)}")
# 更简洁的写法(列表推导式)
clean_incomes = [inc for inc in raw_incomes if 0 < inc <= 500000]
# 统计
print(f"\n=== 清洗后统计 ===")
print(f"平均收入: ${sum(clean_incomes)/len(clean_incomes):,.0f}")
print(f"中位数: ${sorted(clean_incomes)[len(clean_incomes)//2]:,.0f}")
print(f"最高收入: ${max(clean_incomes):,.0f}")
print(f"最低收入: ${min(clean_incomes):,.0f}")案例 3:分组统计
python
# 受访者年龄
ages = [22, 25, 28, 30, 35, 38, 42, 45, 50, 55, 60, 65, 28, 32, 40]
# 年龄分组
youth = [age for age in ages if age < 30]
middle = [age for age in ages if 30 <= age < 50]
senior = [age for age in ages if age >= 50]
print("=== 年龄分组统计 ===")
print(f"青年(<30岁): {len(youth)} 人, 平均 {sum(youth)/len(youth):.1f} 岁")
print(f"中年(30-49岁): {len(middle)} 人, 平均 {sum(middle)/len(middle):.1f} 岁")
print(f"老年(50+岁): {len(senior)} 人, 平均 {sum(senior)/len(senior):.1f} 岁")
# 各组占比
total = len(ages)
print(f"\n=== 年龄分布 ===")
print(f"青年: {len(youth)/total*100:.1f}%")
print(f"中年: {len(middle)/total*100:.1f}%")
print(f"老年: {len(senior)/total*100:.1f}%")对比:Python List vs R Vector vs Stata Variable
创建数据
| 操作 | Python | R | Stata |
|---|---|---|---|
| 创建 | ages = [25, 30, 35] | ages <- c(25, 30, 35) | gen age = ... |
| 长度 | len(ages) | length(ages) | count |
| 访问第一个 | ages[0] | ages[1] | age[1] |
| 访问最后一个 | ages[-1] | ages[length(ages)] | age[_N] |
统计操作
| 操作 | Python | R | Stata |
|---|---|---|---|
| 求和 | sum(ages) | sum(ages) | egen total = sum(age) |
| 平均 | sum(ages)/len(ages) | mean(ages) | summarize age |
| 最大值 | max(ages) | max(ages) | egen max_age = max(age) |
| 排序 | sorted(ages) | sort(ages) | sort age |
常见错误
错误 1:索引越界
python
students = ["Alice", "Bob", "Carol"]
print(students[3]) # IndexError: list index out of range
print(students[2]) # Carol(最后一个是索引2)错误 2:混淆 append() 和 extend()
python
numbers = [1, 2, 3]
numbers.append([4, 5])
print(numbers) # [1, 2, 3, [4, 5]](整个列表作为一个元素)
numbers = [1, 2, 3]
numbers.extend([4, 5])
print(numbers) # [1, 2, 3, 4, 5](逐个添加)错误 3:直接赋值 vs 复制
python
# 直接赋值(两个变量指向同一个列表)
list1 = [1, 2, 3]
list2 = list1
list2.append(4)
print(list1) # [1, 2, 3, 4](list1 也变了!)
# 复制列表
list1 = [1, 2, 3]
list2 = list1.copy() # 或 list2 = list1[:]
list2.append(4)
print(list1) # [1, 2, 3](list1 未变)
print(list2) # [1, 2, 3, 4]练习题
练习 1:GPA 计算
python
# 学生成绩(百分制)
scores = [85, 92, 78, 88, 95, 82, 90, 76, 89, 91]
# 任务:
# 1. 转换为 4.0 GPA 制(90-100: 4.0, 80-89: 3.0, 70-79: 2.0, 60-69: 1.0)
# 2. 计算平均 GPA
# 3. 统计各档次人数练习 2:数据筛选
python
# 受访者收入
incomes = [45000, 75000, 120000, 35000, 95000, 60000, 150000, 50000]
# 任务:
# 1. 筛选出中等收入者(50000-100000)
# 2. 计算中等收入者的平均收入
# 3. 将所有收入从小到大排序练习 3:问卷编号生成
python
# 任务:生成 100 个问卷编号
# 格式: Q001, Q002, Q003, ..., Q100
# 提示:使用列表推导式 + 字符串格式化下一步
在下一节中,我们将学习 元组(Tuples),它是列表的"不可变版本",适合存储不应被修改的数据。
继续学习!