当前位置: 首页 > news >正文

从0到1学Pandas(九):Pandas 高级数据结构与操作

目录

  • 一、探秘多级索引
    • 1.1 创建多级索引
    • 1.2 多级索引操作
    • 1.3 索引转换
  • 二、探索 Panel 与 xarray
    • 2.1 Panel 数据结构
    • 2.2 xarray 库
    • 2.3 高维数据操作
  • 三、时间序列高级应用
    • 3.1 时区处理
    • 3.2 时间序列重采样与频率转换
    • 3.3 时间序列分解与预测
  • 四、数据透视与重塑高级技巧
    • 4.1 复杂透视表
    • 4.2 宽表与长表转换
    • 4.3 数据重构策略


一、探秘多级索引

在数据处理的复杂世界中,我们常常会遇到具有多个维度的数据,多级索引便是 Pandas 提供给我们处理这类数据的强大工具,它能够让我们以一种更灵活、高效的方式来组织和分析数据。接下来,我们将深入探索多级索引的创建、操作以及索引转换的奥秘。

1.1 创建多级索引

在 Pandas 中,创建多级索引主要有以下几种方式,下面以创建学生成绩表为例进行讲解:

  • 使用MultiIndex.from_tuples:将元组组成的列表转换为多级索引。假设我们有学生成绩数据,代码如下:
import pandas as pd
import numpy as np# 行索引元组列表
row_tuples = [('2023', '学期1'), ('2023', '学期2'), ('2024', '学期1'), ('2024', '学期2')]
# 列索引元组列表
col_tuples = [('张三', '语文'), ('张三', '数学'), ('李四', '语文'), ('李四', '数学')]# 创建行多级索引
row_index = pd.MultiIndex.from_tuples(row_tuples, names=['学年', '学期'])
# 创建列多级索引
col_index = pd.MultiIndex.from_tuples(col_tuples, names=['姓名', '科目'])# 随机生成成绩数据
scores = np.random.randint(60, 100, size=(4, 4))# 创建DataFrame
df = pd.DataFrame(scores, index=row_index, columns=col_index)
print(df)
  • 使用MultiIndex.from_arrays:通过数组创建多级索引。以同样的学生成绩数据为例,代码如下:
import pandas as pd
import numpy as np# 行索引数组
row_levels = [['2023', '2023', '2024', '2024'], ['学期1', '学期2', '学期1', '学期2']]
# 列索引数组
col_levels = [['张三', '张三', '李四', '李四'], ['语文', '数学', '语文', '数学']]# 创建行多级索引
row_index = pd.MultiIndex.from_arrays(row_levels, names=['学年', '学期'])
# 创建列多级索引
col_index = pd.MultiIndex.from_arrays(col_levels, names=['姓名', '科目'])# 随机生成成绩数据
scores = np.random.randint(60, 100, size=(4, 4))# 创建DataFrame
df = pd.DataFrame(scores, index=row_index, columns=col_index)
print(df)
  • 使用MultiIndex.from_product:通过笛卡尔积创建多级索引,这是一种比较常用且简洁的方式。代码如下:
import pandas as pd
import numpy as np# 行索引的两个维度
row_year = ['2023', '2024']
row_term = ['学期1', '学期2']
# 列索引的两个维度
col_name = ['张三', '李四']
col_subject = ['语文', '数学']# 创建行多级索引
row_index = pd.MultiIndex.from_product([row_year, row_term], names=['学年', '学期'])
# 创建列多级索引
col_index = pd.MultiIndex.from_product([col_name, col_subject], names=['姓名', '科目'])# 随机生成成绩数据
scores = np.random.randint(60, 100, size=(4, 4))# 创建DataFrame
df = pd.DataFrame(scores, index=row_index, columns=col_index)
print(df)

1.2 多级索引操作

基于多级索引,我们可以进行丰富的数据操作,这使得我们能够从不同角度对数据进行深入分析。

  • 数据选择:使用loc方法可以基于多级索引进行数据选择。例如,要选择 2023 学年第一学期的数据,可以这样操作:
selected_data = df.loc[('2023', '学期1')]
print(selected_data)

如果要选择 2023 学年第一学期张三的语文成绩,则可以使用以下代码:

specific_data = df.loc[('2023', '学期1'), ('张三', '语文')]
print(specific_data)
  • 数据切片:利用loc结合切片操作,我们可以选择某一范围内的数据。比如,选择 2023 学年所有学期的数据:
sliced_data = df.loc[('2023', slice(None))]
print(sliced_data)

这里的slice(None)表示选择 “学期” 这一级索引的所有值。

  • 数据聚合:结合groupby和聚合函数,我们可以对多级索引数据进行聚合操作。例如,计算每个学生所有学期、所有科目的平均成绩:
aggregated_data = df.groupby(level='姓名').mean()
print(aggregated_data)

上述代码通过groupby按照 “姓名” 这一级索引进行分组,然后计算每组的平均值。

1.3 索引转换

在实际数据处理中,有时需要在多级索引和普通索引之间进行转换,以满足不同的分析需求,同时还可能涉及数据结构的重塑。

  • 多级索引转普通索引:使用reset_index方法可以将多级索引转换为普通列。例如:
df_reset = df.reset_index()
print(df_reset)

这将把原来的行多级索引 “学年” 和 “学期” 转换为普通列,DataFrame 的索引变为默认的整数索引。

  • 普通索引转多级索引:通过set_index方法可以将普通列设置为多级索引。假设我们有一个已经将多级索引转换为普通索引的 DataFrame,现在想把 “学年” 和 “学期” 列重新设置为行多级索引:
df_set = df_reset.set_index(['学年', '学期'])
print(df_set)
  • 数据结构重塑:stack和unstack方法用于重塑数据结构。stack方法将列索引旋转为行索引,增加行索引的级别;unstack方法则相反,将行索引旋转为列索引,增加列索引的级别。例如,对前面的 DataFrame 进行stack操作:
stacked_df = df.stack()
print(stacked_df)

此时,原来的列多级索引中的 “科目” 这一级被旋转到了行索引,与原有的行多级索引构成了新的行多级索引。若要将其还原,可以使用unstack方法:

unstacked_df = stacked_df.unstack()
print(unstacked_df)

二、探索 Panel 与 xarray

在处理数据时,我们常常会遇到维度超过二维的情况,这就需要借助更强大的数据结构和工具。Pandas 中的 Panel 数据结构以及 xarray 库为我们处理高维数据提供了有效的解决方案。接下来,我们将深入了解它们的特性和使用方法。

2.1 Panel 数据结构

Panel 是 Pandas 中用于处理三维数据的结构,它有三个轴,分别是 items(0 轴)、major_axis(1 轴)和 minor_axis(2 轴) 。其中,items 轴上的每个元素都对应一个 DataFrame,major_axis 描述每个 DataFrame 的行索引,minor_axis 描述每个 DataFrame 的列索引。虽然自 Pandas 0.25 版本后,Panel 结构已被废弃,但了解它有助于我们理解数据结构的发展和演变。

  • 创建 Panel 对象
    • 使用 ndarray 数组创建:可以通过 numpy 生成的三维数组来创建 Panel。示例代码如下:
import pandas as pd
import numpy as np# 返回均匀分布的随机样本值位于[0,1)之间
data = np.random.rand(2, 4, 5)
p = pd.Panel(data)
print(p)
  • 使用 DataFrame 对象创建:也可以通过包含 DataFrame 的字典来创建 Panel。例如:
import pandas as pd
import numpy as npdata = {'Item1': pd.DataFrame(np.random.randn(4, 3)),'Item2': pd.DataFrame(np.random.randn(4, 2))}
p = pd.Panel(data)
print(p)
  • 从 Panel 对象中选取数据:我们可以使用 Panel 的三个轴来选取数据。比如,使用 items 轴选取数据:
import pandas as pd
import numpy as npdata = {'Item1': pd.DataFrame(np.random.randn(4, 3)),'Item2': pd.DataFrame(np.random.randn(4, 2))}
p = pd.Panel(data)
print(p['Item1'])

上述代码中,我们选择了名为 ‘Item1’ 的数据,输出结果是一个 4 行 3 列的 DataFrame,其行、列索引分别对应 major_axis 和 minor_axis。

2.2 xarray 库

xarray 是一个基于 NumPy 的库,专门用于处理带有维度和坐标的多维数据,它提供了 DataArray 和 Dataset 两种核心数据结构。

  • DataArray:类似于 NumPy 数组,但包含了坐标和维度标签,这使得数据更易于理解和操作。例如,创建一个 DataArray:
import xarray as xr
import numpy as np# 创建一个简单的DataArray
data = np.random.rand(4, 3)
times = ['2024-12-01', '2024-12-02', '2024-12-03', '2024-12-04']
locations = ['New York', 'London', 'Tokyo']
da = xr.DataArray(data, dims=['time', 'location'],coords={'time': times, 'location': locations},name='temperature')
print(da)
  • Dataset:可以看作是一个由多个 DataArray 组成的字典,这些 DataArray 共享相同的坐标系,适合存储和处理多变量的多维数据。例如:
import xarray as xr
import numpy as np# 创建一个简单的Dataset
data = np.random.rand(4, 3)
times = ['2024-12-01', '2024-12-02', '2024-12-03', '2024-12-04']
locations = ['New York', 'London', 'Tokyo']
ds = xr.Dataset({"temperature": (['time', 'location'], data),"humidity": (['time', 'location'], np.random.rand(4, 3))
},coords={"time": times,"location": locations})
print(ds)

xarray 库提供了丰富的方法来读取、处理和分析多维数据,例如使用open_dataset读取 NetCDF 文件,通过索引和切片操作选取数据等。例如,读取一个 NetCDF 文件并进行简单的索引操作:

import xarray as xr# 打开NetCDF文件
ds = xr.open_dataset('example.nc')
# 选择特定时间和位置的数据
subset = ds.sel(time='2024-12-01', location='New York')
print(subset)

2.3 高维数据操作

结合 xarray 库,我们可以在高维数据结构上进行各种复杂的数据操作。

  • 数据选择:通过sel和isel方法,可以基于标签或位置进行数据选择。例如,从之前创建的ds中选择特定时间范围和位置的数据:
# 选择时间在2024-12-02之后,位置为London的数据
selected_data = ds.sel(time=slice('2024-12-02', None), location='London')
print(selected_data)
  • 数据计算:xarray 支持各种数学运算和统计计算,并且会自动处理维度对齐。例如,计算温度的平均值:
mean_temperature = ds['temperature'].mean(dim=['time', 'location'])
print(mean_temperature)
  • 数据可视化:xarray 与 Matplotlib 等可视化库集成良好,可以方便地对高维数据进行可视化。例如,绘制温度的时间序列图:
import matplotlib.pyplot as pltds['temperature'].sel(location='New York').plot()
plt.show()

通过以上操作,我们能够充分利用 xarray 库对高维数据进行高效的处理和分析,挖掘数据背后的信息。

三、时间序列高级应用

在时间序列分析中,我们经常会遇到各种复杂的情况,如不同时区的数据处理、更精细的重采样需求以及对时间序列的深入分解和预测。接下来,我们将深入探讨这些高级应用,帮助大家更好地处理时间序列数据。

3.1 时区处理

在实际应用中,时间序列数据可能来自不同的时区,Pandas 提供了强大的工具来处理时区相关的问题。假设我们有一份包含不同时区时间戳的销售数据,首先,我们可以使用tz_localize方法将无时区信息的数据本地化到指定时区,然后使用tz_convert方法进行时区转换。示例代码如下:

import pandas as pd# 创建包含时间戳的销售数据,假设无时区信息
sales_data = pd.DataFrame({'timestamp': ['2024-12-01 10:00:00', '2024-12-02 15:30:00'],'sales_amount': [1000, 1500]
})
sales_data['timestamp'] = pd.to_datetime(sales_data['timestamp'])# 将时间戳本地化到UTC时区
sales_data['timestamp'] = sales_data['timestamp'].dt.tz_localize('UTC')# 将UTC时区转换为纽约时区
sales_data['timestamp'] = sales_data['timestamp'].dt.tz_convert('US/Eastern')
print(sales_data)

上述代码中,我们首先将timestamp列转换为datetime类型,然后将其本地化到UTC时区,最后转换为US/Eastern(纽约)时区。通过这样的操作,我们可以统一处理不同时区的时间序列数据,确保时间计算和分析的准确性。

3.2 时间序列重采样与频率转换

除了基本的重采样操作,我们还可以进行更高级的基于时间段的聚合和插值。例如,我们有一份每日销售数据,想要按季度进行聚合,并对缺失值进行线性插值。可以使用resample方法结合聚合函数和interpolate方法来实现。示例代码如下:

import pandas as pd
import numpy as np# 创建每日销售数据,包含缺失值
date_rng = pd.date_range(start='2024-01-01', end='2024-12-31', freq='D')
sales_data = pd.DataFrame({'sales': np.random.randint(500, 2000, size=len(date_rng))}, index=date_rng)
# 人为制造一些缺失值
sales_data.iloc[10:20, 0] = np.nan
sales_data.iloc[50:60, 0] = np.nan# 按季度重采样并求和,对缺失值进行线性插值
quarterly_sales = sales_data.resample('Q').sum().interpolate(method='linear')
print(quarterly_sales)

在上述代码中,我们使用resample(‘Q’)将每日数据按季度进行重采样,然后使用sum函数进行聚合,最后通过interpolate(method=‘linear’)对聚合后的数据中可能存在的缺失值进行线性插值,使得数据更加完整,便于后续分析。

3.3 时间序列分解与预测

在时间序列分析中,我们常常希望了解数据的趋势、季节性和残差等成分,以便更好地理解数据的内在规律并进行预测。通过statsmodels库中的seasonal_decompose函数,我们可以实现时间序列的趋势分解。假设我们有一份每月的商品销量数据,代码如下:

import pandas as pd
import numpy as np
from statsmodels.tsa.seasonal import seasonal_decompose
import matplotlib.pyplot as plt# 创建每月商品销量数据
date_rng = pd.date_range(start='2020-01-01', end='2024-12-01', freq='M')
sales_data = pd.DataFrame({'sales': np.random.randint(1000, 5000, size=len(date_rng))}, index=date_rng)# 进行时间序列分解
result = seasonal_decompose(sales_data['sales'], model='additive', period=12)# 绘制分解结果
result.plot()
plt.show()

上述代码中,我们使用seasonal_decompose函数对销量数据进行分解,model='additive’表示使用加法模型进行分解,period=12表示数据的周期为 12 个月(即一年)。通过result.plot()可以直观地看到数据的趋势、季节性和残差成分。

对于简单的预测,我们可以使用一些基本的方法,如移动平均法。移动平均法是一种简单的时间序列预测方法,它通过计算过去一段时间内数据的平均值来预测未来的值。以之前的每月商品销量数据为例,计算 5 个月的移动平均作为预测值,代码如下:

# 计算5个月的移动平均作为预测值
sales_data['moving_avg_prediction'] = sales_data['sales'].rolling(window=5).mean()
print(sales_data[['sales','moving_avg_prediction']])

上述代码中,使用rolling(window=5)创建了一个 5 个月的移动窗口,然后使用mean方法计算每个窗口内数据的平均值,得到的结果作为预测值存储在新的列moving_avg_prediction中。通过这种方式,我们可以根据历史数据的移动平均来对未来数据进行简单的预测。

四、数据透视与重塑高级技巧

4.1 复杂透视表

在数据分析中,我们常常需要对数据进行多维度的汇总和分析,复杂透视表就是一个强大的工具。pandas.pivot_table函数可以帮助我们创建包含多个聚合函数和分组条件的复杂透视表。下面通过一个销售数据的示例来详细说明:

假设我们有一份销售数据,包含日期、地区、产品、销售额和销售量等信息,我们想要统计每个地区、每个产品在不同月份的销售额总和以及销售量的平均值。示例代码如下:

import pandas as pd
import numpy as np# 创建示例销售数据
data = {'date': ['2024-01-01', '2024-01-02', '2024-02-01', '2024-02-03'],'region': ['North', 'South', 'North', 'South'],'product': ['A', 'B', 'A', 'B'],'sales_amount': [1000, 1500, 1200, 1800],'quantity': [50, 75, 60, 90]
}
df = pd.DataFrame(data)# 将date列转换为datetime类型,方便按月份分组
df['date'] = pd.to_datetime(df['date'])# 创建复杂透视表
pivot_table = pd.pivot_table(df, values=['sales_amount', 'quantity'], index=['region', 'product'], columns=df['date'].dt.month, aggfunc={'sales_amount':'sum', 'quantity':'mean'},fill_value=0)
print(pivot_table)

在上述代码中,我们使用pivot_table函数创建透视表。values参数指定了需要进行聚合操作的列,这里是sales_amount和quantity;index参数设置了用于分组的列,即region和product;columns参数通过df[‘date’].dt.month将日期按月份进行分组;aggfunc参数指定了不同列的聚合函数,sales_amount列使用sum函数求和,quantity列使用mean函数求平均值;fill_value参数用于填补缺失值,这里将缺失值填充为 0。通过这样的操作,我们可以得到一个复杂的透视表,从多个维度对销售数据进行了汇总分析。

4.2 宽表与长表转换

在数据处理过程中,我们经常需要在宽格式和长格式数据之间进行灵活转换,以满足不同的分析需求。Pandas 提供了melt和pivot函数来实现这一目的。

  • melt函数:宽表转长表
    melt函数用于将宽表格式转换为长表格式,通常用于将多列数据合并到一列中。其基本语法为:pd.melt(frame, id_vars=None, value_vars=None, var_name=None, value_name=‘value’)。其中,frame是要转换的 DataFrame;id_vars是不需要被转换的列,这些列将在转换后的 DataFrame 中保持不变;value_vars是需要被转换的列,默认会转换除id_vars以外的所有列;var_name是在转换后的 DataFrame 中,新列的列名,表示变量名;value_name是在转换后的 DataFrame 中,新列的列名,表示变量值。

例如,我们有一个包含学生成绩的宽表数据,希望将其转换为长表格式,以便分析各科成绩。示例代码如下:

import pandas as pd# 创建示例数据
data = {'姓名': ['Alice', 'Bob', 'Charlie'],'数学': [85, 90, 95],'英语': [78, 82, 88],'物理': [92, 87, 94]
}
df = pd.DataFrame(data)# 使用melt将宽表转换为长表
melted_df = pd.melt(df, id_vars=['姓名'], var_name='科目', value_name='分数')
print(melted_df)

上述代码中,我们使用melt函数将宽表df转换为长表melted_df。id_vars=[‘姓名’]指定了姓名列保持不变,var_name='科目’指定新的变量列为科目,用于表示原来的学科列名,value_name='分数’指定新的值列为分数,用于存储对应的成绩值。

  • pivot函数:长表转宽表
    pivot函数用于将长表格式转换为宽表格式,通常用于将唯一值展开为多列。其基本语法为:pd.pivot(data, index, columns, values)。其中,data是要转换的 DataFrame;index用于透视表的行索引;columns用于透视表的列索引;values是需要在透视表中显示的数据。

假设我们已经将学生成绩的数据转换为长表格式,现在希望将其还原为宽表。示例代码如下:

# 使用pivot将长表转换为宽表
pivot_df = melted_df.pivot(index='姓名', columns='科目', values='分数')
print(pivot_df)

这里,我们使用pivot函数将长表melted_df还原为宽表pivot_df。index='姓名’指定姓名列为行索引,columns='科目’指定科目列为列索引,values='分数’指定分数列的值填充到新的宽表中。通过这样的操作,我们可以在宽表和长表之间灵活转换数据,以适应不同的数据分析任务。

4.3 数据重构策略

在复杂业务场景中,数据重构是一项关键任务,它能够帮助我们更好地组织和分析数据。以下是一些实用的技巧和策略,并结合具体案例进行讲解。

  • 基于业务逻辑拆分与合并表:在处理数据时,根据业务逻辑将大表拆分为多个小表,或者将多个小表合并为一个大表,能够提高数据处理的效率和灵活性。例如,在电商业务中,我们有订单表、用户表和商品表。订单表记录了订单的基本信息,如订单号、用户 ID、商品 ID、下单时间等;用户表记录了用户的详细信息,如用户 ID、姓名、地址、联系方式等;商品表记录了商品的信息,如商品 ID、商品名称、价格、库存等。为了分析用户的购买行为,我们可能需要将这三张表进行合并。示例代码如下:
import pandas as pd# 创建示例订单表
orders = pd.DataFrame({'order_id': [1, 2, 3],'user_id': [101, 102, 101],'product_id': [201, 202, 203],'order_time': ['2024-12-01 10:00:00', '2024-12-02 15:30:00', '2024-12-03 09:15:00']
})# 创建示例用户表
users = pd.DataFrame({'user_id': [101, 102],'user_name': ['Alice', 'Bob'],'user_address': ['Beijing', 'Shanghai'],'user_contact': ['13800138000', '13900139000']
})# 创建示例商品表
products = pd.DataFrame({'product_id': [201, 202, 203],'product_name': ['Product A', 'Product B', 'Product C'],'product_price': [100, 200, 150],'product_stock': [50, 30, 40]
})# 通过user_id合并订单表和用户表
merged_orders_users = pd.merge(orders, users, on='user_id')# 再通过product_id合并商品表
final_data = pd.merge(merged_orders_users, products, on='product_id')
print(final_data)

上述代码中,我们首先通过user_id将orders表和users表进行合并,得到merged_orders_users表,然后再通过product_id将merged_orders_users表和products表进行合并,最终得到包含订单、用户和商品信息的final_data表,方便进行综合分析。

  • 使用stack和unstack重塑数据结构:stack和unstack方法可以在多级索引之间进行转换,从而重塑数据结构。例如,我们有一个包含不同城市不同月份销售额的 DataFrame,行索引是城市,列索引是月份,数据是销售额。现在我们希望将月份这一级索引旋转到行索引,增加行索引的级别。示例代码如下:
import pandas as pd
import numpy as np# 创建示例数据
data = {'Jan': [1000, 1500],'Feb': [1200, 1800],'Mar': [900, 1100]
}
cities = ['Beijing', 'Shanghai']
df = pd.DataFrame(data, index=cities)# 使用stack方法重塑数据结构
stacked_df = df.stack()
print(stacked_df)

在上述代码中,df.stack()将列索引Jan、Feb、Mar旋转到了行索引,与原有的行索引Beijing、Shanghai构成了新的行多级索引。如果要将其还原,可以使用unstack方法:

# 使用unstack方法还原数据结构
unstacked_df = stacked_df.unstack()
print(unstacked_df)

通过这种方式,我们可以根据具体的业务需求灵活地重塑数据结构,以便更好地进行数据分析和处理。

http://www.dtcms.com/a/301595.html

相关文章:

  • Adobe Animate中文版 v2024.24.0.10.14
  • 洛谷 装箱问题 动态规划-变形背包问题
  • OpenCL study - code03 rgb2gray
  • 进度条制作--Linux知识的小应用
  • 电商平台中,订单未支付过期,如何实现自动关单?
  • 字节前端面试知识点总结
  • 使用GIS中基于森林的分类与回归模型来估算房屋价值
  • c++17--std::variant
  • 决策树算法小结(上)
  • cmake入门学习
  • HCIE学习之路:路由引入
  • 嵌入式硬件篇---ESP32拓展板
  • C语言中 %zu 的用法
  • Javascript中的instanceof
  • VMware Workstation Pro虚拟机的下载和安装图文保姆级教程(附下载链接)
  • 点云的协方差矩阵的三个特征值代表什么?
  • 5.7 多处理器的基本概念 (答案见原书 P278)
  • 6、企业信息化
  • 大模型应用主要组成
  • 一、openEuler 安装git 详细操作步骤
  • 俄罗斯方块游戏开发(面向对象编程)
  • CPA青少年编程能力等级测评试卷及答案 Python编程(三级)
  • Go的defer和recover
  • Windows 11 安装 jdk 8
  • Cgroup 控制组学习(三)在容器中使用 CGroups
  • goland编写go语言导入自定义包出现: package xxx is not in GOROOT (/xxx/xxx) 的解决方案
  • 微服务架构面试题
  • PiscCode使用OpenCV实现漂浮方块特效
  • 编程语言Java——核心技术篇(五)IO流:数据洪流中的航道设计
  • 仓库管理系统-2-后端之基于继承基类的方式实现增删改查