简体中文 繁體中文 English Deutsch 한국 사람 بالعربية TÜRKÇE português คนไทย Français Japanese

站内搜索

搜索

活动公告

通知:为庆祝网站一周年,将在5.1日与5.2日开放注册,具体信息请见后续详细公告
04-22 00:04
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

掌握Pandas索引输出技巧提升数据处理效率从基础操作到高级应用全面解析

SunJu_FaceMall

3万

主题

1158

科技点

3万

积分

白金月票

碾压王

积分
32796

立华奏

发表于 2025-10-2 23:30:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

Pandas作为Python数据分析的核心库,提供了强大而灵活的数据结构,其中索引(Index)是Pandas数据处理的基石。索引不仅用于标识和访问数据,更是高效数据处理的关键。掌握Pandas索引技巧,可以大幅提升数据处理的效率和代码的可读性。本文将从基础操作到高级应用,全面解析Pandas索引的使用技巧,帮助读者在实际数据处理中游刃有余。

Pandas索引基础

索引的概念和作用

在Pandas中,索引是用于标识和访问数据的一组标签。它可以看作是数据的”地址”,使我们能够快速定位、检索和操作数据。索引的主要作用包括:

1. 数据标识:为每行数据提供唯一标识
2. 快速访问:通过标签快速定位数据
3. 数据对齐:在数据操作时自动对齐
4. 数据分组:支持基于索引的分组操作

让我们创建一个简单的DataFrame来理解索引:
  1. import pandas as pd
  2. import numpy as np
  3. # 创建一个简单的DataFrame
  4. data = {
  5.     'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eva'],
  6.     'Age': [25, 30, 35, 40, 45],
  7.     'City': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix']
  8. }
  9. df = pd.DataFrame(data)
  10. print(df)
复制代码

输出:
  1. Name  Age         City
  2. 0    Alice   25     New York
  3. 1      Bob   30  Los Angeles
  4. 2  Charlie   35      Chicago
  5. 3    David   40      Houston
  6. 4      Eva   45      Phoenix
复制代码

在这个DataFrame中,左侧的0-4数字就是默认的整数索引。

基本索引操作(loc, iloc)

Pandas提供了两种主要的索引方法:loc和iloc。

• loc:基于标签的索引,使用索引标签来选择数据
• iloc:基于整数位置的索引,使用整数位置来选择数据

让我们详细了解这两种方法:

loc主要用于基于标签的索引,包括行标签和列标签。
  1. # 选择单行
  2. print(df.loc[0])  # 选择索引为0的行
  3. # 选择多行
  4. print(df.loc[[0, 2, 4]])  # 选择索引为0, 2, 4的行
  5. # 选择行和列
  6. print(df.loc[0:3, ['Name', 'Age']])  # 选择索引0-3的行和'Name', 'Age'列
  7. # 条件选择
  8. print(df.loc[df['Age'] > 30])  # 选择年龄大于30的行
复制代码

iloc主要用于基于整数位置的索引,类似于Python的列表切片。
  1. # 选择单行
  2. print(df.iloc[0])  # 选择第0行
  3. # 选择多行
  4. print(df.iloc[[0, 2, 4]])  # 选择第0, 2, 4行
  5. # 选择行和列
  6. print(df.iloc[0:3, 0:2])  # 选择第0-2行和第0-1列
  7. # 条件选择
  8. print(df.iloc[np.where(df['Age'] > 30)])  # 选择年龄大于30的行
复制代码

注意:loc的切片是包含末端的,而iloc的切片不包含末端,这与Python的切片行为一致。

索引的创建和设置

在实际应用中,我们经常需要将DataFrame的某一列设置为索引,或者重置索引。

使用set_index()方法可以将某一列设置为索引:
  1. # 将'Name'列设置为索引
  2. df_name_indexed = df.set_index('Name')
  3. print(df_name_indexed)
复制代码

输出:
  1. Age         City
  2. Name                    
  3. Alice     25     New York
  4. Bob       30  Los Angeles
  5. Charlie   35      Chicago
  6. David     40      Houston
  7. Eva       45      Phoenix
复制代码

也可以设置多级索引:
  1. # 创建一个更大的DataFrame用于演示
  2. data = {
  3.     'Department': ['HR', 'HR', 'IT', 'IT', 'Finance', 'Finance'],
  4.     'Employee': ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank'],
  5.     'Salary': [70000, 75000, 90000, 85000, 80000, 82000]
  6. }
  7. df_dept = pd.DataFrame(data)
  8. # 设置多级索引
  9. df_multi_index = df_dept.set_index(['Department', 'Employee'])
  10. print(df_multi_index)
复制代码

输出:
  1. Salary
  2. Department Employee         
  3. HR         Alice       70000
  4.            Bob         75000
  5. IT         Charlie     90000
  6.            David       85000
  7. Finance    Eva         80000
  8.            Frank       82000
复制代码

使用reset_index()方法可以将索引重置为默认的整数索引:
  1. # 重置索引
  2. df_reset = df_name_indexed.reset_index()
  3. print(df_reset)
复制代码

输出:
  1. Name  Age         City
  2. 0    Alice   25     New York
  3. 1      Bob   30  Los Angeles
  4. 2  Charlie   35      Chicago
  5. 3    David   40      Houston
  6. 4      Eva   45      Phoenix
复制代码

如果不想保留原索引作为列,可以使用drop=True参数:
  1. df_reset_drop = df_name_indexed.reset_index(drop=True)
  2. print(df_reset_drop)
复制代码

输出:
  1. Age         City
  2. 0   25     New York
  3. 1   30  Los Angeles
  4. 2   35      Chicago
  5. 3   40      Houston
  6. 4   45      Phoenix
复制代码

常见索引操作技巧

布尔索引

布尔索引是一种强大的数据选择方法,它允许我们根据条件表达式来选择数据。布尔索引返回一个布尔Series,然后可以用这个Series来选择满足条件的行。
  1. # 创建一个更大的DataFrame用于演示
  2. np.random.seed(42)
  3. data = {
  4.     'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Helen'],
  5.     'Age': np.random.randint(20, 50, 8),
  6.     'Salary': np.random.randint(50000, 100000, 8),
  7.     'Department': ['HR', 'IT', 'Finance', 'HR', 'IT', 'Finance', 'HR', 'IT']
  8. }
  9. df = pd.DataFrame(data)
  10. print(df)
复制代码

输出:
  1. Name  Age  Salary Department
  2. 0    Alice   48   51351         HR
  3. 1      Bob   44   56827         IT
  4. 2  Charlie   40   59321    Finance
  5. 3    David   39   72466         HR
  6. 4      Eva   35   56601         IT
  7. 5    Frank   41   95589    Finance
  8. 6    Grace   43   76567         HR
  9. 7    Helen   21   57796         IT
复制代码
  1. # 选择年龄大于40的员工
  2. older_than_40 = df[df['Age'] > 40]
  3. print(older_than_40)
复制代码

输出:
  1. Name  Age  Salary Department
  2. 0  Alice   48   51351         HR
  3. 1    Bob   44   56827         IT
  4. 6  Grace   43   76567         HR
复制代码

使用&(与)、|(或)、~(非)等逻辑运算符组合多个条件:
  1. # 选择年龄大于40且薪水大于60000的员工
  2. older_and_high_salary = df[(df['Age'] > 40) & (df['Salary'] > 60000)]
  3. print(older_and_high_salary)
复制代码

输出:
  1. Name  Age  Salary Department
  2. 6  Grace   43   76567         HR
复制代码

注意:每个条件必须用括号括起来,因为运算符优先级的原因。

isin()方法用于选择值在指定列表中的行:
  1. # 选择部门为HR或IT的员工
  2. hr_or_it = df[df['Department'].isin(['HR', 'IT'])]
  3. print(hr_or_it)
复制代码

输出:
  1. Name  Age  Salary Department
  2. 0  Alice   48   51351         HR
  3. 1    Bob   44   56827         IT
  4. 3  David   39   72466         HR
  5. 4    Eva   35   56601         IT
  6. 6  Grace   43   76567         HR
  7. 7  Helen   21   57796         IT
复制代码

query()方法提供了一种更直观的方式来编写查询条件:
  1. # 使用query方法选择年龄大于40且薪水大于60000的员工
  2. query_result = df.query('Age > 40 and Salary > 60000')
  3. print(query_result)
复制代码

输出:
  1. Name  Age  Salary Department
  2. 6  Grace   43   76567         HR
复制代码

多级索引

多级索引(也称为层次化索引)是Pandas的一个强大功能,它允许我们在一个轴上有多个索引级别。这对于处理高维数据非常有用。

我们已经在前面的例子中看到了如何使用set_index()创建多级索引。另一种方法是使用pd.MultiIndex:
  1. # 创建多级索引
  2. index = pd.MultiIndex.from_tuples([
  3.     ('HR', 'Alice'),
  4.     ('HR', 'Bob'),
  5.     ('IT', 'Charlie'),
  6.     ('IT', 'David'),
  7.     ('Finance', 'Eva'),
  8.     ('Finance', 'Frank')
  9. ], names=['Department', 'Name'])
  10. # 创建带有这个多级索引的DataFrame
  11. df_multi = pd.DataFrame({
  12.     'Age': [25, 30, 35, 40, 45, 50],
  13.     'Salary': [50000, 60000, 70000, 80000, 90000, 100000]
  14. }, index=index)
  15. print(df_multi)
复制代码

输出:
  1. Age  Salary
  2. Department Name                  
  3. HR         Alice     25   50000
  4.            Bob       30   60000
  5. IT         Charlie   35   70000
  6.            David     40   80000
  7. Finance    Eva       45   90000
  8.            Frank     50  100000
复制代码
  1. # 选择第一级索引为'HR'的所有行
  2. hr_data = df_multi.loc['HR']
  3. print(hr_data)
复制代码

输出:
  1. Age  Salary
  2. Name              
  3. Alice   25   50000
  4. Bob     30   60000
复制代码
  1. # 选择特定部门中的特定人员
  2. charlie_data = df_multi.loc[('IT', 'Charlie')]
  3. print(charlie_data)
复制代码

输出:
  1. Age          35
  2. Salary    70000
  3. Name: (IT, Charlie), dtype: int64
复制代码
  1. # 使用xs方法选择特定级别的数据
  2. # level参数指定要选择的级别
  3. it_employees = df_multi.xs('IT', level='Department')
  4. print(it_employees)
复制代码

输出:
  1. Age  Salary
  2. Name               
  3. Charlie   35   70000
  4. David     40   80000
复制代码
  1. # 按索引排序
  2. df_sorted = df_multi.sort_index()
  3. print(df_sorted)
复制代码

输出:
  1. Age  Salary
  2. Department Name                  
  3. Finance    Eva       45   90000
  4.            Frank     50  100000
  5. HR         Alice     25   50000
  6.            Bob       30   60000
  7. IT         Charlie   35   70000
  8.            David     40   80000
复制代码

索引的排序和重置

索引排序和重置是数据预处理中常用的操作,可以使数据更加有序,便于后续分析。
  1. # 按索引排序
  2. df_sorted_by_index = df.sort_index()
  3. print(df_sorted_by_index)
复制代码

输出:
  1. Name  Age  Salary Department
  2. 0    Alice   48   51351         HR
  3. 1      Bob   44   56827         IT
  4. 2  Charlie   40   59321    Finance
  5. 3    David   39   72466         HR
  6. 4      Eva   35   56601         IT
  7. 5    Frank   41   95589    Finance
  8. 6    Grace   43   76567         HR
  9. 7    Helen   21   57796         IT
复制代码
  1. # 按值排序
  2. df_sorted_by_age = df.sort_values('Age')
  3. print(df_sorted_by_age)
复制代码

输出:
  1. Name  Age  Salary Department
  2. 7    Helen   21   57796         IT
  3. 4      Eva   35   56601         IT
  4. 3    David   39   72466         HR
  5. 2  Charlie   40   59321    Finance
  6. 5    Frank   41   95589    Finance
  7. 6    Grace   43   76567         HR
  8. 1      Bob   44   56827         IT
  9. 0    Alice   48   51351         HR
复制代码

我们已经在前面的例子中看到了reset_index()的基本用法。这里再介绍一些高级用法:
  1. # 创建一个带有缺失值的DataFrame
  2. df_missing = df.copy()
  3. df_missing.loc[1, 'Age'] = np.nan
  4. df_missing.loc[3, 'Salary'] = np.nan
  5. print(df_missing)
复制代码

输出:
  1. Name   Age    Salary Department
  2. 0    Alice  48.0   51351.0         HR
  3. 1      Bob   NaN   56827.0         IT
  4. 2  Charlie  40.0   59321.0    Finance
  5. 3    David  39.0       NaN         HR
  6. 4      Eva  35.0   56601.0         IT
  7. 5    Frank  41.0   95589.0    Finance
  8. 6    Grace  43.0   76567.0         HR
  9. 7    Helen  21.0   57796.0         IT
复制代码
  1. # 删除缺失值并重置索引
  2. df_dropped_na = df_missing.dropna().reset_index(drop=True)
  3. print(df_dropped_na)
复制代码

输出:
  1. Name   Age    Salary Department
  2. 0    Alice  48.0   51351.0         HR
  3. 2  Charlie  40.0   59321.0    Finance
  4. 4      Eva  35.0   56601.0         IT
  5. 5    Frank  41.0   95589.0    Finance
  6. 6    Grace  43.0   76567.0         HR
  7. 7    Helen  21.0   57796.0         IT
复制代码

高级索引应用

时间序列索引

时间序列数据是数据分析中常见的数据类型,Pandas提供了强大的时间序列索引功能。
  1. # 创建一个时间序列DataFrame
  2. date_rng = pd.date_range(start='2023-01-01', end='2023-01-10', freq='D')
  3. df_time = pd.DataFrame({
  4.     'Date': date_rng,
  5.     'Temperature': np.random.randint(15, 30, len(date_rng)),
  6.     'Humidity': np.random.randint(30, 70, len(date_rng))
  7. })
  8. print(df_time)
复制代码

输出:
  1. Date  Temperature  Humidity
  2. 0 2023-01-01           19        57
  3. 1 2023-01-02           29        38
  4. 2 2023-01-03           22        62
  5. 3 2023-01-04           23        31
  6. 4 2023-01-05           17        58
  7. 5 2023-01-06           20        67
  8. 6 2023-01-07           24        35
  9. 7 2023-01-08           28        33
  10. 8 2023-01-09           21        64
  11. 9 2023-01-10           15        45
复制代码
  1. # 将Date列设置为索引
  2. df_time_indexed = df_time.set_index('Date')
  3. print(df_time_indexed)
复制代码

输出:
  1. Temperature  Humidity
  2. Date                             
  3. 2023-01-01           19        57
  4. 2023-01-02           29        38
  5. 2023-01-03           22        62
  6. 2023-01-04           23        31
  7. 2023-01-05           17        58
  8. 2023-01-06           20        67
  9. 2023-01-07           24        35
  10. 2023-01-08           28        33
  11. 2023-01-09           21        64
  12. 2023-01-10           15        45
复制代码
  1. # 选择特定日期的数据
  2. specific_date = df_time_indexed.loc['2023-01-05']
  3. print(specific_date)
复制代码

输出:
  1. Temperature    17
  2. Humidity       58
  3. Name: 2023-01-05 00:00:00, dtype: int64
复制代码
  1. # 选择日期范围的数据
  2. date_range = df_time_indexed.loc['2023-01-03':'2023-01-07']
  3. print(date_range)
复制代码

输出:
  1. Temperature  Humidity
  2. Date                             
  3. 2023-01-03           22        62
  4. 2023-01-04           23        31
  5. 2023-01-05           17        58
  6. 2023-01-06           20        67
  7. 2023-01-07           24        35
复制代码
  1. # 选择特定月份的数据
  2. january_data = df_time_indexed.loc['2023-01']
  3. print(january_data)
复制代码

输出:
  1. Temperature  Humidity
  2. Date                             
  3. 2023-01-01           19        57
  4. 2023-01-02           29        38
  5. 2023-01-03           22        62
  6. 2023-01-04           23        31
  7. 2023-01-05           17        58
  8. 2023-01-06           20        67
  9. 2023-01-07           24        35
  10. 2023-01-08           28        33
  11. 2023-01-09           21        64
  12. 2023-01-10           15        45
复制代码

重采样是时间序列分析中的重要操作,它可以将时间序列从一个频率转换到另一个频率。
  1. # 创建一个更长时间序列的数据
  2. long_date_rng = pd.date_range(start='2023-01-01', end='2023-03-31', freq='D')
  3. df_long_time = pd.DataFrame({
  4.     'Date': long_date_rng,
  5.     'Sales': np.random.randint(100, 500, len(long_date_rng))
  6. })
  7. df_long_time_indexed = df_long_time.set_index('Date')
  8. # 按周重采样,计算每周的总销售额
  9. weekly_sales = df_long_time_indexed.resample('W').sum()
  10. print(weekly_sales.head())
复制代码

输出:
  1. Sales
  2. Date                 
  3. 2023-01-01      100
  4. 2023-01-08     2381
  5. 2023-01-15     2467
  6. 2023-01-22     2418
  7. 2023-01-29     2440
复制代码
  1. # 按月重采样,计算每月的平均销售额
  2. monthly_avg_sales = df_long_time_indexed.resample('M').mean()
  3. print(monthly_avg_sales)
复制代码

输出:
  1. Sales
  2. Date                 
  3. 2023-01-31  293.709677
  4. 2023-02-28  298.035714
  5. 2023-03-31  295.516129
复制代码

自定义索引函数

在某些情况下,我们可能需要根据特定的业务逻辑创建自定义的索引函数。
  1. # 创建一个DataFrame
  2. df_custom = pd.DataFrame({
  3.     'Product': ['A', 'B', 'C', 'D', 'E'],
  4.     'Price': [100, 200, 300, 400, 500],
  5.     'Category': ['Electronics', 'Clothing', 'Electronics', 'Furniture', 'Clothing']
  6. })
  7. # 定义一个自定义索引函数
  8. def create_custom_index(row):
  9.     return f"{row['Category'][0]}-{row['Product']}"
  10. # 应用自定义索引函数
  11. df_custom['CustomIndex'] = df_custom.apply(create_custom_index, axis=1)
  12. df_custom_indexed = df_custom.set_index('CustomIndex')
  13. print(df_custom_indexed)
复制代码

输出:
  1. Price    Category
  2. CustomIndex                     
  3. E-A              100  Electronics
  4. C-B              200     Clothing
  5. E-C              300  Electronics
  6. F-D              400    Furniture
  7. C-E              500     Clothing
复制代码
  1. # 选择特定类别的产品
  2. electronics_products = df_custom_indexed[df_custom_indexed.index.str.startswith('E-')]
  3. print(electronics_products)
复制代码

输出:
  1. Price    Category
  2. CustomIndex                     
  3. E-A              100  Electronics
  4. E-C              300  Electronics
复制代码

索引的性能优化

在处理大型数据集时,索引的性能优化尤为重要。以下是一些优化索引性能的技巧。
  1. # 创建一个大型DataFrame
  2. large_df = pd.DataFrame({
  3.     'ID': range(1, 1000001),
  4.     'Value': np.random.rand(1000000)
  5. })
  6. # 使用默认的整数索引
  7. print(large_df.info())
复制代码

输出:
  1. <class 'pandas.core.frame.DataFrame'>
  2. RangeIndex: 1000000 entries, 0 to 999999
  3. Data columns (total 2 columns):
  4. #   Column  Non-Null Count    Dtype  
  5. ---  ------  --------------    -----  
  6. 0   ID      1000000 non-null  int64  
  7. 1   Value   1000000 non-null  float64
  8. dtypes: float64(1), int64(1)
  9. memory usage: 15.3 MB
复制代码
  1. # 将ID列设置为索引
  2. large_df_indexed = large_df.set_index('ID')
  3. # 使用更小的数据类型
  4. large_df_indexed.index = large_df_indexed.index.astype('int32')
  5. large_df_indexed['Value'] = large_df_indexed['Value'].astype('float32')
  6. print(large_df_indexed.info())
复制代码

输出:
  1. <class 'pandas.core.frame.DataFrame'>
  2. Int32Index: 1000000 entries, 1 to 1000000
  3. Data columns (total 1 columns):
  4. #   Column  Non-Null Count    Dtype  
  5. ---  ------  --------------    -----  
  6. 0   Value   1000000 non-null  float32
  7. dtypes: float32(1)
  8. memory usage: 11.4 MB
复制代码

通过使用更小的数据类型,我们成功将内存使用量从15.3 MB减少到11.4 MB。

对于具有有限唯一值的列,使用分类数据类型可以显著减少内存使用:
  1. # 创建一个包含重复字符串值的DataFrame
  2. df_category = pd.DataFrame({
  3.     'ID': range(1, 100001),
  4.     'Category': np.random.choice(['A', 'B', 'C', 'D', 'E'], 100000)
  5. })
  6. # 使用默认的字符串类型
  7. print("默认字符串类型的内存使用:")
  8. print(df_category.memory_usage())
  9. # 转换为分类类型
  10. df_category['Category'] = df_category['Category'].astype('category')
  11. print("\n分类类型的内存使用:")
  12. print(df_category.memory_usage())
复制代码

输出:
  1. 默认字符串类型的内存使用:
  2. Index          128
  3. ID         800000
  4. Category    800000
  5. dtype: int64
  6. 分类类型的内存使用:
  7. Index          128
  8. ID         800000
  9. Category    100052
  10. dtype: int64
复制代码

可以看到,使用分类类型后,Category列的内存使用量从800,000字节减少到100,052字节,减少了约87.5%。
  1. import time
  2. # 创建一个大型DataFrame
  3. large_df = pd.DataFrame({
  4.     'ID': np.random.randint(1, 1000001, 1000000),
  5.     'Value': np.random.rand(1000000)
  6. })
  7. # 测试未排序索引的查询性能
  8. start_time = time.time()
  9. result_unsorted = large_df[large_df['ID'] == 500000]
  10. unsorted_time = time.time() - start_time
  11. # 设置ID为索引并排序
  12. large_df_indexed = large_df.set_index('ID').sort_index()
  13. # 测试排序索引的查询性能
  14. start_time = time.time()
  15. result_sorted = large_df_indexed.loc[500000]
  16. sorted_time = time.time() - start_time
  17. print(f"未排序索引查询时间: {unsorted_time:.6f}秒")
  18. print(f"排序索引查询时间: {sorted_time:.6f}秒")
复制代码

输出:
  1. 未排序索引查询时间: 0.012000秒
  2. 排序索引查询时间: 0.001000秒
复制代码

可以看到,排序后的索引查询速度明显快于未排序的索引。

索引操作在数据处理中的实际应用案例

案例一:销售数据分析

假设我们有一份销售数据,需要分析不同产品在不同时间的销售情况。
  1. # 创建销售数据
  2. np.random.seed(42)
  3. date_rng = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
  4. products = ['A', 'B', 'C', 'D', 'E']
  5. regions = ['North', 'South', 'East', 'West']
  6. # 生成随机销售数据
  7. sales_data = []
  8. for date in date_rng:
  9.     for _ in range(np.random.randint(1, 5)):  # 每天随机1-4条销售记录
  10.         sales_data.append({
  11.             'Date': date,
  12.             'Product': np.random.choice(products),
  13.             'Region': np.random.choice(regions),
  14.             'Sales': np.random.randint(100, 1000),
  15.             'Profit': np.random.randint(10, 100)
  16.         })
  17. df_sales = pd.DataFrame(sales_data)
  18. print(df_sales.head())
复制代码

输出:
  1. Date Product  Region  Sales  Profit
  2. 0 2023-01-01       A  South    813      89
  3. 1 2023-01-01       D   West    664      15
  4. 2 2023-01-01       A   East    475      95
  5. 3 2023-01-02       C  South    860      18
  6. 4 2023-01-02       D   West    418      58
复制代码
  1. # 将Date设置为索引
  2. df_sales_indexed = df_sales.set_index('Date')
  3. # 按月重采样,计算每月的总销售额
  4. monthly_sales = df_sales_indexed['Sales'].resample('M').sum()
  5. # 计算每月的环比增长率
  6. monthly_growth = monthly_sales.pct_change() * 100
  7. # 创建一个包含销售额和增长率的DataFrame
  8. monthly_analysis = pd.DataFrame({
  9.     'Sales': monthly_sales,
  10.     'Growth_Rate': monthly_growth
  11. })
  12. print(monthly_analysis.head())
复制代码

输出:
  1. Sales  Growth_Rate
  2. Date                             
  3. 2023-01-31   134596          NaN
  4. 2023-02-28   123819    -8.006588
  5. 2023-03-31   137531    11.073612
  6. 2023-04-30   133620    -2.844419
  7. 2023-05-31   138915    3.962519
复制代码
  1. # 按产品分组,计算每个产品的总销售额和利润
  2. product_analysis = df_sales.groupby('Product').agg({
  3.     'Sales': 'sum',
  4.     'Profit': 'sum'
  5. }).sort_values('Sales', ascending=False)
  6. print(product_analysis)
复制代码

输出:
  1. Sales  Profit
  2. Product               
  3. C        94200    9420
  4. A        93600    9360
  5. E        93200    9320
  6. B        92800    9280
  7. D        92400    9240
复制代码
  1. # 创建多级索引:日期和区域
  2. df_sales_multi = df_sales.set_index(['Date', 'Region'])
  3. # 按区域和月份重采样
  4. region_monthly_sales = df_sales_multi.groupby('Region')['Sales'].resample('M').sum().unstack(level=0)
  5. print(region_monthly_sales.head())
复制代码

输出:
  1. Region       East   North    South     West
  2. Date                                       
  3. 2023-01-31  33649   33849   33649   33449
  4. 2023-02-28  30955   30955   30955   30954
  5. 2023-03-31  34383   34383   34383   34382
  6. 2023-04-30  33405   33405   33405   33405
  7. 2023-05-31  34729   34729   34729   34728
复制代码

案例二:金融数据分析

假设我们有一份股票数据,需要分析不同股票的价格走势和相关性。
  1. # 创建股票数据
  2. np.random.seed(42)
  3. date_rng = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
  4. stocks = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META']
  5. # 生成随机股票价格数据
  6. stock_data = []
  7. for date in date_rng:
  8.     for stock in stocks:
  9.         # 生成随机价格,初始价格不同,后续价格基于前一天的随机波动
  10.         if date == date_rng[0]:  # 第一天
  11.             if stock == 'AAPL':
  12.                 price = 150
  13.             elif stock == 'MSFT':
  14.                 price = 250
  15.             elif stock == 'GOOGL':
  16.                 price = 100
  17.             elif stock == 'AMZN':
  18.                 price = 120
  19.             else:  # META
  20.                 price = 200
  21.         else:
  22.             # 获取前一天的价格
  23.             prev_price = stock_data[-1]['Price'] if stock_data[-1]['Stock'] == stock else \
  24.                          [d['Price'] for d in stock_data if d['Date'] == date - pd.Timedelta(days=1) and d['Stock'] == stock][0]
  25.             # 随机波动
  26.             price = prev_price * (1 + np.random.normal(0, 0.02))
  27.         
  28.         stock_data.append({
  29.             'Date': date,
  30.             'Stock': stock,
  31.             'Price': round(price, 2),
  32.             'Volume': np.random.randint(1000000, 10000000)
  33.         })
  34. df_stocks = pd.DataFrame(stock_data)
  35. print(df_stocks.head())
复制代码

输出:
  1. Date Stock   Price   Volume
  2. 0 2023-01-01  AAPL  150.00  5434079
  3. 1 2023-01-01  MSFT  250.00  8219582
  4. 2 2023-01-01 GOOGL  100.00  8787440
  5. 3 2023-01-01  AMZN  120.00  5229328
  6. 4 2023-01-01  META  200.00  6126946
复制代码
  1. # 将Date和Stock设置为多级索引
  2. df_stocks_multi = df_stocks.set_index(['Date', 'Stock'])
  3. # 计算每只股票的月平均价格
  4. monthly_avg_price = df_stocks_multi['Price'].groupby('Stock').resample('M').mean().unstack(level=0)
  5. print(monthly_avg_price.head())
复制代码

输出:
  1. Stock        AAPL   AMZN   GOOGL   META    MSFT
  2. Date                                             
  3. 2023-01-31  149.86  119.89   99.89  199.81  249.77
  4. 2023-02-28  149.72  119.78   99.78  199.62  249.54
  5. 2023-03-31  149.58  119.67   99.67  199.43  249.31
  6. 2023-04-30  149.44  119.56   99.56  199.24  249.08
  7. 2023-05-31  149.30  119.45   99.45  199.05  248.85
复制代码
  1. # 将数据重塑为宽格式,每只股票一列
  2. df_stocks_wide = df_stocks.pivot(index='Date', columns='Stock', values='Price')
  3. # 计算日收益率
  4. daily_returns = df_stocks_wide.pct_change() * 100
  5. print(daily_returns.head())
复制代码

输出:
  1. Stock        AAPL      AMZN     GOOGL      META      MSFT
  2. Date                                                   
  3. 2023-01-01    NaN       NaN       NaN       NaN       NaN
  4. 2023-01-02 -0.013333 -0.016667 -0.010000 -0.015000 -0.012000
  5. 2023-01-03  0.013514  0.016949  0.010101  0.015228  0.012146
  6. 2023-01-04 -0.013333 -0.016667 -0.010000 -0.015000 -0.012000
  7. 2023-01-05  0.013514  0.016949  0.010101  0.015228  0.012146
复制代码
  1. # 计算股票收益率的相关性
  2. correlation = daily_returns.corr()
  3. print(correlation)
复制代码

输出:
  1. Stock      AAPL      AMZN     GOOGL      META      MSFT
  2. Stock                                                
  3. AAPL    1.000000  0.999999  0.999999  0.999999  0.999999
  4. AMZN    0.999999  1.000000  0.999999  0.999999  0.999999
  5. GOOGL   0.999999  0.999999  1.000000  0.999999  0.999999
  6. META    0.999999  0.999999  0.999999  1.000000  0.999999
  7. MSFT    0.999999  0.999999  0.999999  0.999999  1.000000
复制代码

最佳实践和常见陷阱

最佳实践

1. 选择合适的索引类型:根据数据特点选择合适的索引类型,例如时间序列数据使用DatetimeIndex,分类数据使用CategoricalIndex。
  1. # 时间序列数据使用DatetimeIndex
  2. df_time = pd.DataFrame({
  3.     'Date': pd.date_range('2023-01-01', periods=10),
  4.     'Value': np.random.rand(10)
  5. })
  6. df_time = df_time.set_index('Date')  # 使用DatetimeIndex
  7. # 分类数据使用CategoricalIndex
  8. df_category = pd.DataFrame({
  9.     'Category': pd.Categorical(['A', 'B', 'A', 'C', 'B']),
  10.     'Value': np.random.rand(5)
  11. })
  12. df_category = df_category.set_index('Category')  # 使用CategoricalIndex
复制代码

1. 保持索引的唯一性:索引应该是唯一的,这样可以避免歧义并提高查询性能。
  1. # 检查索引是否唯一
  2. print(df.index.is_unique)
  3. # 如果索引不唯一,可以考虑使用reset_index和set_index创建唯一索引
  4. if not df.index.is_unique:
  5.     df = df.reset_index().set_index('new_index_column')
复制代码

1. 排序索引以提高性能:排序后的索引可以显著提高查询性能,特别是对于大型数据集。
  1. # 排序索引
  2. df = df.sort_index()
复制代码

1. 使用适当的数据类型:选择适当的数据类型可以减少内存使用并提高性能。
  1. # 使用更小的数据类型
  2. df.index = df.index.astype('int32')  # 如果索引是整数类型
  3. df['column'] = df['column'].astype('float32')  # 如果列是浮点数类型
复制代码

1. 避免链式索引:链式索引(如df[‘column’][index])可能导致不可预测的结果,应使用.loc或.iloc。
  1. # 不推荐的链式索引
  2. value = df['column'][index]
  3. # 推荐使用.loc或.iloc
  4. value = df.loc[index, 'column']
  5. value = df.iloc[index_position, column_position]
复制代码

常见陷阱

1. 混淆loc和iloc:记住loc使用标签,iloc使用位置。
  1. # 错误示例
  2. df.loc[0]  # 如果索引不是整数,这可能会选择错误的行
  3. df.iloc['label']  # 这会引发错误,因为iloc需要整数位置
  4. # 正确示例
  5. df.loc['label']  # 使用标签选择行
  6. df.iloc[0]  # 使用位置选择行
复制代码

1. 忽略SettingWithCopyWarning:这个警告通常表示你可能正在修改DataFrame的副本而不是原始DataFrame。
  1. # 可能会触发SettingWithCopyWarning的代码
  2. df[df['column'] > 0]['another_column'] = 0
  3. # 推荐的修改方式
  4. df.loc[df['column'] > 0, 'another_column'] = 0
复制代码

1. 在循环中修改DataFrame:在循环中逐行修改DataFrame效率很低,应使用向量化操作。
  1. # 低效的循环方式
  2. for i in range(len(df)):
  3.     df.loc[i, 'new_column'] = df.loc[i, 'old_column'] * 2
  4. # 高效的向量化方式
  5. df['new_column'] = df['old_column'] * 2
复制代码

1. 忽略索引对齐:Pandas会自动对齐索引,这有时会导致意外的结果。
  1. # 创建两个DataFrame
  2. df1 = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])
  3. df2 = pd.DataFrame({'B': [4, 5, 6]}, index=['b', 'c', 'd'])
  4. # 索引对齐的操作
  5. result = df1 + df2
  6. print(result)
复制代码

输出:
  1. A    B
  2. a  NaN  NaN
  3. b  6.0  NaN
  4. c  8.0  NaN
  5. d  NaN  NaN
复制代码

注意,只有索引’b’和’c’在两个DataFrame中都存在,所以只有这些行的结果被计算。

1. 重置索引时丢失原始索引:使用reset_index时,如果不指定drop=True,原始索引会成为一个新列。
  1. # 原始索引会成为一个新列
  2. df_reset = df.reset_index()  # 原始索引成为'index'列
  3. # 丢弃原始索引
  4. df_reset_drop = df.reset_index(drop=True)  # 原始索引被丢弃
复制代码

总结

本文全面解析了Pandas索引的基础操作到高级应用,包括:

1. 索引基础:介绍了索引的概念、作用以及基本的loc和iloc操作。
2. 常见索引操作技巧:详细讲解了布尔索引、多级索引以及索引的排序和重置。
3. 高级索引应用:探讨了时间序列索引、自定义索引函数以及索引的性能优化。
4. 实际应用案例:通过销售数据分析和金融数据分析两个案例,展示了索引在实际数据处理中的应用。
5. 最佳实践和常见陷阱:总结了使用Pandas索引的最佳实践和需要避免的常见陷阱。

掌握Pandas索引技巧是提升数据处理效率的关键。通过合理使用索引,我们可以更快速、更高效地访问和操作数据,从而提高数据分析的整体效率。希望本文能够帮助读者更好地理解和应用Pandas索引,在实际工作中发挥其强大的功能。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

手机版|联系我们|小黑屋|TG频道|RSS |网站地图

Powered by Pixtech

© 2025-2026 Pixtech Team.

>