Pandas数据索引与切片实战技巧详解 如何高效处理数据集中的筛选与定位问题

在数据分析和处理的过程中,Pandas 是 Python 中最常用的库之一。它提供了强大的数据结构和操作工具,使得处理表格数据变得简单高效。然而,面对庞大的数据集,如何快速、准确地进行数据索引、切片、筛选和定位,往往是决定工作效率的关键。本文将深入探讨 Pandas 中数据索引与切片的实战技巧,帮助你高效处理数据集中的筛选与定位问题。
1. 理解 Pandas 的核心数据结构
在深入技巧之前,我们需要先回顾 Pandas 的两个核心数据结构:
Series
和
DataFrame
。
Series
:一维数组,类似于 Python 列表或 NumPy 数组,但带有索引标签。
DataFrame
:二维表格结构,由多个 Series 组成,每列是一个 Series,行和列都有索引。
理解这些结构是掌握索引和切片的基础。在 DataFrame 中,我们通常关注行索引(index)和列索引(columns)。
2. 基础索引与切片
2.1 使用
[]
进行列选择
最简单的索引方式是使用方括号
[]
。对于 DataFrame,
[]
默认用于列选择。
import pandas as pd

# 创建一个示例 DataFrame
data = {
‘Name’: [‘Alice’, ‘Bob’, ‘Charlie’, ‘David’],
‘Age’: [25, 30, 35, 40],
‘City’: [‘New York’, ‘Los Angeles’, ‘Chicago’, ‘Houston’]
}
df = pd.DataFrame(data)

# 选择单列
print(df[‘Name’])
输出:
0 Alice
1 Bob
2 Charlie
3 David
Name: Name, dtype: object
选择多列:
print(df[[‘Name’, ‘City’]])
2.2 使用
.loc
和
.iloc
进行行选择
.loc
和
.iloc
是 Pandas 中用于行选择的两个主要方法。
.loc
:基于标签(label)的索引。
.iloc
:基于整数位置(integer position)的索引。
使用
.loc
进行标签索引
# 设置索引
df.set_index(‘Name’, inplace=True)

# 选择单行
print(df.loc[‘Alice’])
输出:
Age 25
City New York
Name: Alice, dtype: object
选择多行:
print(df.loc[[‘Alice’, ‘David’]])
使用
.iloc
进行位置索引
# 选择第0行
print(df.iloc[0])
输出:
Age 25
City New York
Name: Alice, dtype: object
选择多行:
print(df.iloc[[0, 3]])
2.3 同时选择行和列
.loc
和
.iloc
也可以同时选择行和列,语法为
df.loc[row_indexer, col_indexer]
。
# 使用 .loc 选择行和列
print(df.loc[‘Alice’, ‘Age’])
输出:
25
# 使用 .iloc 选择行和列
print(df.iloc[0, 0])
输出:
25
3. 布尔索引与条件筛选
布尔索引是 Pandas 中最强大的筛选工具之一。它允许你根据条件筛选数据。
3.1 单条件筛选
# 筛选年龄大于30的人
print(df[df[‘Age’] > 30])
输出:
Age City
Name
Charlie 35 Chicago
David 40 Houston
3.2 多条件筛选
使用
&
(与)和
|
(或)进行多条件筛选,注意条件要用括号括起来。
# 筛选年龄大于30且城市为Chicago的人
print(df[(df[‘Age’] > 30) & (df[‘City’] == ‘Chicago’)])
输出:
Age City
Name
Charlie 35 Chicago
3.3 使用
query
方法
query
方法提供了一种更简洁的语法进行条件筛选。
# 使用 query 筛选
print(df.query(‘Age > 30 and City == “Chicago”‘))
输出:
Age City
Name
Charlie 35 Chicago
4. 高级索引技巧
4.1 使用
isin
进行多值筛选
isin
方法允许你检查值是否在指定的列表中。
# 筛选城市为New York或Chicago的人
print(df[df[‘City’].isin([‘New York’, ‘Chicago’])])
输出:
Age City
Name
Alice 25 New York
Charlie 35 Chicago
4.2 使用
between
进行范围筛选
between
方法用于筛选在指定范围内的值。
# 筛选年龄在25到35之间的人
print(df[df[‘Age’].between(25, 35)])
输出:
Age City
Name
Alice 25 New York
Bob 30 Los Angeles
Charlie 35 Chicago
4.3 使用
str
访问器进行字符串筛选
对于字符串列,可以使用
.str
访问器进行模式匹配。
# 筛选城市名称以 ‘N’ 开头的人
print(df[df[‘City’].str.startswith(‘N’)])
输出:
Age City
Name
Alice 25 New York
4.4 使用
pd.cut
进行分箱筛选
pd.cut
可以将数值数据分箱,便于分组分析。
# 将年龄分为三个区间
bins = [0, 25, 35, 50]
labels = [‘Young’, ‘Middle’, ‘Old’]
df[‘Age_Group’] = pd.cut(df[‘Age’], bins=bins, labels=labels)

print(df)
输出:
Age City Age_Group
Name
Alice 25 New York Young
Bob 30 Los Angeles Middle
Charlie 35 Chicago Middle
David 40 Houston Old
5. 索引的重置与设置
5.1 设置索引
使用
set_index
方法可以将某一列设置为索引。
df.reset_index(inplace=True) # 先重置索引
df.set_index(‘Name’, inplace=True)
5.2 重置索引
使用
reset_index
方法可以将索引重置为默认的整数索引,并将原索引变为列。
df.reset_index(inplace=True)
print(df)
输出:
Name Age City Age_Group
0 Alice 25 New York Young
1 Bob 30 Los Angeles Middle
2 Charlie 35 Chicago Middle
3 David 40 Houston Old
6. 多级索引(MultiIndex)
多级索引允许你在多个维度上索引数据,适用于复杂的数据结构。
6.1 创建多级索引
# 创建多级索引 DataFrame
arrays = [[‘A’, ‘A’, ‘B’, ‘B’], [1, 2, 1, 2]]
index = pd.MultiIndex.from_arrays(arrays, names=[‘first’, ‘second’])
df_multi = pd.DataFrame({‘Data’: [10, 20, 30, 40]}, index=index)

print(df_multi)
输出:
Data
first second
A 1 10
2 20
B 1 30
2 40
6.2 多级索引的切片
# 选择 first 为 A 的所有行
print(df_multi.loc[‘A’])
输出:
Data
second
1 10
2 20
# 选择 first 为 A 且 second 为 1 的行
print(df_multi.loc[(‘A’, 1)])
输出:
Data 10
Name: (A, 1), dtype: int64
7. 高效筛选与定位的实战技巧
7.1 使用
query
方法提高可读性
query
方法不仅语法简洁,而且在处理大型数据集时可能更快。
# 使用 query 进行复杂筛选
large_df = pd.DataFrame({
‘A’: range(10000),
‘B’: range(10000, 20000),
‘C’: [‘x’, ‘y’] * 5000
})

# 筛选 A > 5000 且 C == ‘x’
result = large_df.query(‘A > 5000 and C == “x”‘)
print(result.head())
7.2 使用
eval
进行动态表达式评估
eval
方法允许你使用字符串表达式进行计算,适用于动态生成条件。
# 使用 eval 进行计算
large_df.eval(‘D = A + B’, inplace=True)
print(large_df.head())
7.3 使用
filter
方法筛选列
filter
方法可以根据列名模式筛选列。
# 筛选列名包含 ‘A’ 的列
print(large_df.filter(like=’A’, axis=1))
7.4 使用
take
方法按位置选择行
take
方法可以按位置选择行,类似于
iloc
,但支持更多功能。
# 选择前5行
print(large_df.take(range(5)))
7.5 使用
lookup
方法查找特定值
lookup
方法允许你根据行和列标签查找值。
# 查找前5行的 A 和 B 列的值
rows = range(5)
cols = [‘A’, ‘B’]
print(large_df.lookup(rows, cols))
输出:
array([ 0, 1, 2, 3, 4])
7.6 使用
at
和
iat
进行快速标量访问
at
和
iat
用于快速访问单个值,比
.loc
和
.iloc
更快。
# 使用 at 访问单个值
large_df.at[0, ‘A’] = 100
print(large_df.at[0, ‘A’])
输出:
100
# 使用 iat 访问单个值
large_df.iat[0, 0] = 200
print(large_df.iat[0, 0])
输出:
200
8. 性能优化技巧
8.1 使用
numexpr
引擎
在使用
query
或
eval
时,可以指定
numexpr
引擎来提高性能。
# 使用 numexpr 引擎
result = large_df.query(‘A > 5000 and C == “x”‘, engine=’numexpr’)
8.2 避免链式索引
链式索引(如
df[df[‘A’] > 0][‘B’]
)可能导致不可预测的行为,应尽量避免。推荐使用
.loc
或
.iloc
。
8.3 使用
copy
方法避免 SettingWithCopyWarning
当你对 DataFrame 的子集进行操作时,可能会遇到 SettingWithCopyWarning。使用
copy
方法可以避免此问题。
# 使用 copy 方法
subset = df[df[‘Age’] > 30].copy()
subset[‘Age’] = 100 # 不会触发警告
9. 实战案例:处理真实数据集
9.1 加载数据
# 加载 Titanic 数据集
url = ”
titanic = pd.read_csv(url)
print(titanic.head())
9.2 数据筛选
# 筛选年龄大于30的乘客
adults = titanic[titanic[‘Age’] > 30]
print(adults.head())
9.3 多条件筛选
# 筛选年龄大于30且船舱等级为1的乘客
first_class_adults = titanic[(titanic[‘Age’] > 30) & (titanic[‘Pclass’] == 1)]
print(first_class_adults.head())
9.4 使用
query
方法
# 使用 query 筛选
first_class_adults = titanic.query(‘Age > 30 and Pclass == 1’)
print(first_class_adults.head())
9.5 使用
groupby
进行分组筛选
# 计算每个船舱等级的平均年龄
mean_age_by_class = titanic.groupby(‘Pclass’)[‘Age’].mean()
print(mean_age_by_class)
9.6 使用
transform
进行分组筛选
# 筛选年龄大于该船舱等级平均年龄的乘客
titanic[‘Mean_Age’] = titanic.groupby(‘Pclass’)[‘Age’].transform(‘mean’)
filtered = titanic[titanic[‘Age’] > titanic[‘Mean_Age’]]
print(filtered.head())
10. 总结
本文详细介绍了 Pandas 中数据索引与切片的多种技巧,从基础到高级,涵盖了布尔索引、多级索引、性能优化以及实战案例。掌握这些技巧,可以显著提高数据处理的效率和准确性。在实际应用中,建议根据具体需求选择合适的方法,并注意性能优化,以应对大规模数据集的挑战。
通过不断练习和实践,你将能够更加熟练地运用 Pandas 进行数据筛选与定位,从而在数据分析工作中游刃有余。
# Pandas数据索引与切片实战技巧详解 如何高效处理数据集中的筛选与定位问题
引言:为什么需要掌握Pandas索引与切片技巧
在数据科学和分析工作中,我们经常需要处理成千上万行的数据。想象一下,你有一个包含10万条销售记录的数据集,需要快速找出”2023年第一季度,华东地区,销售额超过1万元的电子产品”。如果使用传统的循环遍历,不仅代码冗长,效率也极低。而Pandas提供的强大索引和切片功能,可以在毫秒级完成这类复杂查询。
本文将从基础到高级,系统讲解Pandas中数据索引与切片的实战技巧,帮助你高效处理数据集中的筛选与定位问题。
1. 基础索引操作:掌握核心方法
1.1 列选择:三种常用方法
Pandas提供了多种选择列的方式,每种都有其适用场景:
import pandas as pd
import numpy as np

# 创建示例数据
data = {
‘姓名’: [‘张三’, ‘李四’, ‘王五’, ‘赵六’, ‘钱七’],
‘年龄’: [25, 30, 35, 28, 32],
‘城市’: [‘北京’, ‘上海’, ‘广州’, ‘深圳’, ‘杭州’],
‘薪资’: [8000, 12000, 15000, 10000, 13000],
‘部门’: [‘技术’, ‘销售’, ‘技术’, ‘市场’, ‘技术’]
}
df = pd.DataFrame(data)

# 方法1:单列选择(返回Series)
salary_series = df[‘薪资’]
print(“单列选择结果:”)
print(salary_series)
print(f”类型:{type(salary_series)}”)

# 方法2:多列选择(返回DataFrame)
subset_df = df[[‘姓名’, ‘薪资’, ‘部门’]]
print(“\n多列选择结果:”)
print(subset_df)

# 方法3:属性访问(仅适用于列名是合法变量名时)
# 注意:如果列名包含空格或特殊字符,此方法会失败
age_col = df.年龄
print(“\n属性访问结果:”)
print(age_col)
输出结果:
单列选择结果:
0 8000
1 12000
2 15000
3 10000
4 13000
Name: 薪资, dtype: int64
类型:

多列选择结果:
姓名 薪资 部门
0 张三 8000 技术
1 李四 12000 销售
2 王五 15000 技术
3 赵六 10000 市场
4 钱七 13000 技术

属性访问结果:
0 25
1 30
2 35
3 28
4 32
Name: 年龄, dtype: int64
技巧总结:
单列选择返回Series,多列选择返回DataFrame
列名最好使用字符串形式,避免属性访问的限制
列选择是最高效的操作之一,应该优先使用
1.2 行选择:loc vs iloc
行选择是Pandas中最常用的操作之一,理解
loc
和
iloc
的区别至关重要:
# 设置索引以便演示
df_indexed = df.set_index(‘姓名’)
print(“原始数据:”)
print(df_indexed)

# 1. loc:基于标签的索引
print(“\n=== loc 标签索引 ===”)
# 单行选择
print(“选择’李四’这一行:”)
print(df_indexed.loc[‘李四’])

# 多行选择
print(“\n选择’李四’和’王五’这两行:”)
print(df_indexed.loc[[‘李四’, ‘王五’]])

# 切片选择(包含结束标签)
print(“\n从’李四’到’赵六’的切片:”)
print(df_indexed.loc[‘李四’:’赵六’])

# 2. iloc:基于位置的索引
print(“\n=== iloc 位置索引 ===”)
# 单行选择
print(“选择第1行(索引为0):”)
print(df_indexed.iloc[0])

# 多行选择
print(“\n选择第1和第3行:”)
print(df_indexed.iloc[[0, 2]])

# 切片选择(不包含结束位置)
print(“\n从第1行到第3行的切片:”)
print(df_indexed.iloc[0:3])

# 3. 同时选择行和列
print(“\n=== 同时选择行和列 ===”)
print(“选择’李四’行的’年龄’和’薪资’列:”)
print(df_indexed.loc[‘李四’, [‘年龄’, ‘薪资’]])

print(“\n选择第1-3行,第1-2列:”)
print(df_indexed.iloc[0:3, 0:2])
关键区别:
loc
:左闭右闭区间
[start, end]
,基于标签
iloc
:左闭右开区间
[start, end)
,基于位置
混合使用时,
loc
更安全,因为它明确指定了标签
2. 布尔索引:最强大的筛选工具
2.1 单条件筛选
布尔索引是Pandas中最灵活的筛选方式:
# 重置索引以便演示
df_reset = df.copy()

# 筛选年龄大于30的员工
print(“年龄大于30的员工:”)
print(df_reset[df_reset[‘年龄’] > 30])

# 筛选城市为’北京’的员工
print(“\n城市为’北京’的员工:”)
print(df_reset[df_reset[‘城市’] == ‘北京’])

# 筛选薪资在10000-15000之间的员工
print(“\n薪资在10000-15000之间的员工:”)
print(df_reset[(df_reset[‘薪资’] >= 10000) & (df_reset[‘薪资’] <= 15000)]) 2.2 多条件组合筛选 # 使用 &(与)、|(或)、~(非)进行组合 # 注意:每个条件必须用括号括起来 # 条件1:年龄大于28且薪资大于10000 condition1 = (df_reset['年龄'] > 28) & (df_reset[‘薪资’] > 10000)
print(“年龄>28且薪资>10000:”)
print(df_reset[condition1])

# 条件2:城市是北京或上海
condition2 = df_reset[‘城市’].isin([‘北京’, ‘上海’])
print(“\n城市是北京或上海:”)
print(df_reset[condition2])

# 条件3:年龄大于25且(城市是北京或部门是技术)
condition3 = (df_reset[‘年龄’] > 25) & ((df_reset[‘城市’] == ‘北京’) | (df_reset[‘部门’] == ‘技术’))
print(“\n年龄>25且(城市=北京或部门=技术):”)
print(df_reset[condition3])

# 条件4:非技术部门
condition4 = df_reset[‘部门’] != ‘技术’
print(“\n非技术部门:”)
print(df_reset[condition4])

# 条件5:姓名包含’张’或’李’
condition5 = df_reset[‘姓名’].str.contains(‘张|李’)
print(“\n姓名包含’张’或’李’:”)
print(df_reset[condition5])
2.3 使用query方法进行查询
query
方法提供了一种更简洁的查询语法:
# 使用query进行筛选
print(“使用query筛选:”)
print(df_reset.query(‘年龄 > 30 and 薪资 > 10000’))

# 在query中使用变量
min_age = 28
min_salary = 12000
print(f”\n使用query筛选(年龄>{min_age},薪资>{min_salary}):”)
print(df_reset.query(‘年龄 > @min_age and 薪资 > @min_salary’))

# query支持字符串方法
print(“\n使用query进行字符串匹配:”)
print(df_reset.query(‘城市.str.contains(“北京|上海”)’, engine=’python’))
3. 高级索引技巧
3.1 多级索引(MultiIndex)
当数据具有多个维度时,多级索引非常有用:
# 创建多级索引数据
arrays = [
[‘A’, ‘A’, ‘B’, ‘B’, ‘C’, ‘C’],
[‘一月’, ‘二月’, ‘一月’, ‘二月’, ‘一月’, ‘二月’]
]
index = pd.MultiIndex.from_arrays(arrays, names=[‘部门’, ‘月份’])
multi_df = pd.DataFrame({
‘销售额’: [100, 120, 80, 90, 150, 160],
‘利润’: [20, 25, 15, 18, 30, 35]
}, index=index)

print(“多级索引数据:”)
print(multi_df)

# 多级索引的选择
print(“\n选择部门A的所有数据:”)
print(multi_df.loc[‘A’])

print(“\n选择部门A一月的数据:”)
print(multi_df.loc[(‘A’, ‘一月’)])

print(“\n选择所有部门的一月数据:”)
print(multi_df.xs(‘一月’, level=’月份’))
3.2 索引的重置与设置
# 设置索引
df_set_index = df.set_index(‘姓名’)
print(“设置索引后:”)
print(df_set_index)

# 重置索引
df_reset_index = df_set_index.reset_index()
print(“\n重置索引后:”)
print(df_reset_index)

# 多列设置为索引
df_multi_index = df.set_index([‘城市’, ‘部门’])
print(“\n多列索引:”)
print(df_multi_index)

# 重置部分索引
df_reset_partial = df_multi_index.reset_index(level=’部门’)
print(“\n重置部分索引:”)
print(df_reset_partial)
3.3 索引的排序与重新索引
# 随机打乱数据
df_shuffled = df.sample(frac=1, random_state=42).reset_index(drop=True)
print(“打乱后的数据:”)
print(df_shuffled)

# 按薪资排序
df_sorted = df_shuffled.sort_values(‘薪资’, ascending=False)
print(“\n按薪资降序排列:”)
print(df_sorted)

# 重新索引(创建新的索引顺序)
df_reindexed = df_sorted.reset_index(drop=True)
print(“\n重新索引后:”)
print(df_reindexed)

# 重新索引(指定新的索引)
new_index = [‘员工1’, ‘员工2’, ‘员工3’, ‘员工4’, ‘员工5’]
df_new_index = df_reindexed.set_index(pd.Index(new_index))
print(“\n指定新索引:”)
print(df_new_index)
4. 高效筛选与定位的实战技巧
4.1 使用isin进行多值筛选
# 创建更大的数据集用于演示
np.random.seed(42)
large_df = pd.DataFrame({
‘ID’: range(1000),
‘Category’: np.random.choice([‘A’, ‘B’, ‘C’, ‘D’], 1000),
‘Value’: np.random.randint(100, 1000, 1000),
‘Region’: np.random.choice([‘East’, ‘West’, ‘North’, ‘South’], 1000)
})

# 使用isin进行多值筛选
target_categories = [‘A’, ‘C’]
target_regions = [‘East’, ‘West’]

# 方法1:分别筛选后组合
filtered1 = large_df[
large_df[‘Category’].isin(target_categories) &
large_df[‘Region’].isin(target_regions)
]

# 方法2:使用query
filtered2 = large_df.query(
‘Category in @target_categories and Region in @target_regions’
)

print(f”原始数据量:{len(large_df)}”)
print(f”筛选后数据量:{len(filtered1)}”)
print(“\n前5行:”)
print(filtered1.head())
4.2 使用between进行范围筛选
# 筛选Value在300-600之间的数据
range_filtered = large_df[large_df[‘Value’].between(300, 600)]

# 使用query进行范围筛选
range_filtered_query = large_df.query(‘300 <= Value <= 600') print(f"范围筛选结果:{len(range_filtered)}条") print("\n前5行:") print(range_filtered.head()) 4.3 使用str访问器进行字符串匹配 # 创建包含文本数据的数据集 text_df = pd.DataFrame({ 'Product': ['iPhone13', 'iPhone14', 'MacBookPro', 'iPadAir', 'AirPods'], 'Price': [5999, 6999, 12999, 4399, 1399], 'Description': ['Apple手机', '最新苹果手机', '苹果笔记本', '苹果平板', '无线耳机'] }) # 使用str访问器 print("产品名称以iPhone开头:") print(text_df[text_df['Product'].str.startswith('iPhone')]) print("\n产品名称包含'Air':") print(text_df[text_df['Product'].str.contains('Air')]) print("\n描述包含'苹果':") print(text_df[text_df['Description'].str.contains('苹果')]) # 正则表达式匹配 print("\n产品名称匹配正则表达式(iPhone\d或Mac):") print(text_df[text_df['Product'].str.match(r'iPhone\d|Mac')]) 4.4 使用pd.cut进行分箱筛选 # 对数值进行分箱 large_df['Value_Group'] = pd.cut( large_df['Value'], bins=[0, 200, 400, 600, 800, 1000], labels=['0-200', '200-400', '400-600', '600-800', '800-1000'] ) print("分箱后的数据:") print(large_df[['Value', 'Value_Group']].head(10)) # 筛选特定分箱 mid_range = large_df[large_df['Value_Group'] == '400-600'] print(f"\n中等范围(400-600)的数据量:{len(mid_range)}") 4.5 使用pd.qcut进行等频分箱 # 等频分箱(每个箱的数据量大致相等) large_df['Value_Qcut'] = pd.qcut(large_df['Value'], q=4, labels=['Q1', 'Q2', 'Q3', 'Q4']) print("等频分箱结果:") print(large_df[['Value', 'Value_Qcut']].head(10)) # 筛选最高25%的数据 top_25 = large_df[large_df['Value_Qcut'] == 'Q4'] print(f"\n最高25%的数据量:{len(top_25)}") 5. 性能优化技巧 5.1 避免链式索引 链式索引可能导致不可预测的行为和性能问题: # 错误的方式(链式索引) # df[df['Age'] > 30][‘Salary’] = 15000 # 这会触发SettingWithCopyWarning

# 正确的方式1:使用.loc
df.loc[df[‘年龄’] > 30, ‘薪资’] = 15000

# 正确的方式2:使用.where
df[‘薪资’] = df[‘薪资’].where(df[‘年龄’] <= 30, 15000) # 正确的方式3:使用mask df['薪资'] = df['薪资'].mask(df['年龄'] > 30, 15000)
5.2 使用eval进行高效计算
# 对于大型数据集,使用eval可以提高性能
# 创建大型数据集
n = 100000
large_df = pd.DataFrame({
‘A’: np.random.randn(n),
‘B’: np.random.randn(n),
‘C’: np.random.randn(n)
})

# 使用eval进行复杂计算
result1 = large_df.query(‘A > 0 and B < 0 and C > 0′)
result2 = large_df[(large_df[‘A’] > 0) & (large_df[‘B’] < 0) & (large_df['C'] > 0)]

print(f”使用query:{len(result1)}条”)
print(f”使用布尔索引:{len(result2)}条”)
print(f”结果是否相同:{result1.equals(result2)}”)

# 使用eval创建新列
large_df.eval(‘D = A * B + C’, inplace=True)
print(“\n使用eval创建新列D:”)
print(large_df.head())
5.3 使用numexpr引擎加速
# 安装numexpr:pip install numexpr
# 使用numexpr引擎可以显著加速复杂查询

# 对于大型数据集,使用numexpr
try:
import numexpr
result_fast = large_df.query(‘A > 0 and B < 0', engine='numexpr') print(f"使用numexpr引擎查询结果:{len(result_fast)}条") except ImportError: print("numexpr未安装,使用默认引擎") 5.4 使用take方法进行快速位置选择 # 使用take方法进行快速位置选择 indices = [0, 10, 20, 30, 40] selected = large_df.take(indices) print("使用take选择特定位置:") print(selected) # 与iloc的区别:take接受索引列表,iloc接受切片或单个索引 6. 实战案例:综合应用 6.1 案例1:销售数据分析 # 创建销售数据 np.random.seed(42) sales_data = pd.DataFrame({ 'Date': pd.date_range('2023-01-01', periods=100, freq='D'), 'Product': np.random.choice(['手机', '电脑', '平板', '耳机'], 100), 'Region': np.random.choice(['华北', '华东', '华南', '华西'], 100), 'Quantity': np.random.randint(1, 20, 100), 'Price': np.random.randint(1000, 10000, 100) }) # 计算销售额 sales_data['Sales'] = sales_data['Quantity'] * sales_data['Price'] # 需求1:找出2023年第一季度,华北地区,销售额超过50000的记录 q1_sales = sales_data[ (sales_data['Date'] >= ‘2023-01-01’) &
(sales_data[‘Date’] <= '2023-03-31') & (sales_data['Region'] == '华北') & (sales_data['Sales'] > 50000)
]

print(“需求1结果:”)
print(q1_sales)

# 需求2:找出每种产品在每个地区的平均销售额
avg_sales = sales_data.groupby([‘Product’, ‘Region’])[‘Sales’].mean().reset_index()
print(“\n需求2结果:”)
print(avg_sales)

# 需求3:找出销售额排名前10的记录
top_10 = sales_data.nlargest(10, ‘Sales’)
print(“\n需求3结果:”)
print(top_10)
6.2 案例2:用户行为分析
# 创建用户行为数据
user_data = pd.DataFrame({
‘UserID’: np.random.randint(1000, 2000, 500),
‘Action’: np.random.choice([‘click’, ‘view’, ‘purchase’, ‘share’], 500),
‘Page’: np.random.choice([‘home’, ‘product’, ‘cart’, ‘checkout’], 500),
‘Duration’: np.random.randint(10, 600, 500),
‘Timestamp’: pd.date_range(‘2023-01-01′, periods=500, freq=’T’)
})

# 需求1:找出购买行为且停留时间超过300秒的用户
purchase_users = user_data[
(user_data[‘Action’] == ‘purchase’) &
(user_data[‘Duration’] > 300)
]

print(“购买且停留时间长的用户:”)
print(purchase_users.head())

# 需求2:找出每个页面的平均停留时间
avg_duration = user_data.groupby(‘Page’)[‘Duration’].mean()
print(“\n各页面平均停留时间:”)
print(avg_duration)

# 需求3:找出高频用户(出现次数>5次的用户)
user_counts = user_data[‘UserID’].value_counts()
frequent_users = user_counts[user_counts > 5].index
frequent_data = user_data[user_data[‘UserID’].isin(frequent_users)]

print(f”\n高频用户数据:{len(frequent_data)}条”)
print(f”涉及用户数:{len(frequent_users)}”)
7. 常见问题与解决方案
7.1 SettingWithCopyWarning问题
# 问题:链式赋值可能导致警告
# df[df[‘Age’] > 30][‘Salary’] = 15000 # 警告

# 解决方案1:使用.loc
df.loc[df[‘年龄’] > 30, ‘薪资’] = 15000

# 解决方案2:使用.copy()
temp_df = df[df[‘年龄’] > 30].copy()
temp_df[‘薪资’] = 15000
df.update(temp_df)
7.2 索引对齐问题
# 索引对齐是Pandas的强大特性,但也可能导致意外结果
df1 = pd.DataFrame({‘A’: [1, 2, 3]}, index=[0, 1, 2])
df2 = pd.DataFrame({‘A’: [10, 20, 30]}, index=[1, 2, 3])

# 加法操作会自动对齐索引
result = df1 + df2
print(“索引对齐结果:”)
print(result)

# 如果不希望对齐,先重置索引
result_no_align = df1.reset_index(drop=True) + df2.reset_index(drop=True)
print(“\n不对齐结果:”)
print(result_no_align)
7.3 处理缺失值
# 创建包含缺失值的数据
df_missing = df.copy()
df_missing.loc[1, ‘薪资’] = np.nan
df_missing.loc[3, ‘城市’] = np.nan

print(“包含缺失值的数据:”)
print(df_missing)

# 筛选非缺失值
print(“\n薪资非空的记录:”)
print(df_missing[df_missing[‘薪资’].notna()])

print(“\n城市非空的记录:”)
print(df_missing[df_missing[‘城市’].notna()])

# 填充缺失值后筛选
df_filled = df_missing.fillna({‘薪资’: 0, ‘城市’: ‘未知’})
print(“\n填充后薪资>10000的记录:”)
print(df_filled[df_filled[‘薪资’] > 10000])
8. 最佳实践总结
8.1 性能最佳实践
优先使用向量化操作
:避免使用循环,使用Pandas内置函数
合理使用索引
:将常用筛选列设置为索引
避免链式索引
:使用.loc或.iloc进行单次索引
使用query和eval
:对于大型数据集,它们通常更快
选择合适的数据类型
:使用category类型处理重复字符串
8.2 代码可读性最佳实践
使用描述性变量名
:如
condition_age
而不是
c1
复杂条件分解
:将复杂条件分解为多个变量
添加注释
:说明筛选逻辑
使用query方法
:对于复杂查询,query更易读
8.3 调试技巧
# 1. 使用shape查看筛选结果大小
print(f”筛选前:{df.shape},筛选后:{df[df[‘年龄’] > 30].shape}”)

# 2. 使用value_counts检查条件分布
print(df[‘年龄’] > 30).value_counts()

# 3. 使用describe查看统计信息
print(df[df[‘年龄’] > 30][‘薪资’].describe())

# 4. 使用sample随机查看样本
print(df[df[‘年龄’] > 30].sample(5))
结语
Pandas的索引与切片功能是数据处理的核心技能。通过掌握从基础的列选择、行定位,到高级的布尔索引、多级索引,再到性能优化技巧,你将能够高效处理各种复杂的数据筛选需求。
记住,优秀的Pandas代码不仅要运行快速,还要易于理解和维护。在实际工作中,根据数据规模、查询复杂度和团队习惯,选择最适合的方法。
持续练习这些技巧,你将在数据分析工作中游刃有余,轻松应对各种数据挑战!