You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中GC-MS数据对齐构建DataFrame的问题求助

GC-MS NetCDF数据对齐与结构化DataFrame构建问题

我正在Python中处理NetCDF格式的气相色谱-质谱(GC-MS)数据,在正确对齐数据以构建结构化DataFrame时遇到困难。目标是构建如下矩阵:

  • 行:保留时间(来自scan_acquisition_time)
  • 列:取整后的质荷比(来自mass_values)
  • 单元格:对应保留时间和质荷比的强度值(来自intensity_values)

目前问题是部分强度值在DataFrame中位置错位,与其他软件的正确输出不符。我尝试过透视表、按质荷比大小拆分强度值等方法,但均失败。

原始数据提取代码

import xarray as xr
import pandas as pd
import numpy as np

# Extract necessary data
retention_time = data['scan_acquisition_time'].values.squeeze()
intensity_values = data['intensity_values'].values.squeeze()
mass_values = data['mass_values'].values.squeeze()
scan_index = data['scan_index'].values.squeeze()
rounded_mass = np.round(mass_values).astype(int)  # Round mass values to integers
mass_min = np.round(min(mass_values)).astype(int)
mass_max = np.round(max(mass_values)).astype(int)
ideal_mass_values = list(range(mass_min, mass_max + 1))

数据结构示例

  • scan_acquisition_time: (4825,)
  • scan_index: (4825,)
  • mass_values: (2903174,)
  • intensity_values: (2903174,)

当前构建DataFrame的代码

if 'point_count' in data.variables:
    point_count = data['point_count'].values.squeeze()
else:
    raise ValueError("The dataset does not have the 'point_count' variable, necessary to map scans to intensity data")

# Repeat retention times for each point in each scan
retention_time_repeated = np.repeat(retention_time, point_count)

# Ensure lengths match
assert len(retention_time_repeated) == len(intensity_values), "Mismatch in retention_time and intensity_values length"

# Get unique retention times and define matrix dimensions
unique_retention_times, inverse_indices = np.unique(retention_time_repeated, return_inverse=True)
unique_masses = ideal_mass_values

# Initialize a zero-filled intensity matrix
intensity_matrix = np.zeros((len(unique_retention_times), len(unique_masses)))

# Create mass index mapping
mass_to_index = {mass: j for j, mass in enumerate(unique_masses)}

# Get indices for the intensity matrix
mass_indices = np.array([mass_to_index[mass] for mass in rounded_mass])

# Populate the intensity matrix in a vectorized manner
intensity_matrix[inverse_indices, mass_indices] += intensity_values

# Convert the matrix to a DataFrame for easier inspection
matrix_df = pd.DataFrame(
    intensity_matrix,
    index=unique_retention_times,
    columns=unique_masses
)

# Display part of the matrix for verification
print(matrix_df.head())

我的问题

  1. 如何确保强度值与保留时间、取整后的质荷比正确对齐?
  2. 是否需要引入scan_index辅助对齐?若需要,该如何操作?
  3. 有没有更优的Python数据处理方法避免对齐问题?

解答

1. 确保强度值正确对齐的核心修正

错位问题的核心原因是**np.unique的排序特性**:np.unique(retention_time_repeated)会返回排序后的保留时间,而inverse_indices对应排序后的索引,这会打乱原始扫描的顺序,导致强度值映射错位。

修正方案:

  • 直接使用原始retention_time作为行索引(GC-MS数据通常每个扫描对应唯一保留时间)
  • 基于原始扫描顺序构建行索引,而非依赖排序后的结果

修改后的核心代码片段:

# 直接用原始保留时间作为行索引,无需去重排序
unique_retention_times = retention_time
# 生成每个强度点对应的行索引(按原始扫描顺序)
row_indices = np.repeat(np.arange(len(unique_retention_times)), point_count)

# 初始化矩阵
intensity_matrix = np.zeros((len(unique_retention_times), len(unique_masses)))

# 填充矩阵(确保顺序完全匹配)
intensity_matrix[row_indices, mass_indices] += intensity_values

matrix_df = pd.DataFrame(
    intensity_matrix,
    index=unique_retention_times,
    columns=unique_masses
)

额外验证步骤:确认point_count的总和等于len(mass_values),如果point_count存在偏移,会直接导致保留时间重复错误。

2. 引入scan_index辅助对齐的操作方法

如果retention_time存在重复,或point_count数据不可靠,必须用scan_index确保对齐——它是每个扫描的唯一标识,比保留时间更可靠。

操作步骤:

# 1. 将scan_index重复对应到每个强度点
scan_index_repeated = np.repeat(scan_index, point_count)

# 2. 构建扫描ID到原始行索引的映射
unique_scans = scan_index
scan_to_row = {scan: idx for idx, scan in enumerate(unique_scans)}
row_indices = np.array([scan_to_row[scan] for scan in scan_index_repeated])

# 3. 用row_indices填充矩阵,确保每个扫描的强度点映射到正确行
intensity_matrix[row_indices, mass_indices] += intensity_values

3. 更优的Python数据处理方法

方法一:Pandas长表转宽表(直观易调试)

先构建包含所有维度信息的长表,再通过透视表转换为宽表,便于调试对齐问题:

# 构建长表,整合所有关联数据
long_df = pd.DataFrame({
    'retention_time': np.repeat(retention_time, point_count),
    'rounded_mass': rounded_mass,
    'intensity': intensity_values
})

# 转宽表,同一保留时间+质荷比的强度求和
matrix_df = long_df.pivot_table(
    index='retention_time',
    columns='rounded_mass',
    values='intensity',
    aggfunc='sum',
    fill_value=0
)

# 补全缺失的质荷比列并排序
for mass in ideal_mass_values:
    if mass not in matrix_df.columns:
        matrix_df[mass] = 0
matrix_df = matrix_df[sorted(matrix_df.columns)]

方法二:Xarray原生处理(适配NetCDF格式)

利用xarray的坐标对齐机制,减少手动索引操作,降低出错概率:

# 将数据整理为带坐标的xarray Dataset
ds = xr.Dataset({
    'intensity': xr.DataArray(
        intensity_values,
        dims=['point'],
        coords={
            'retention_time': ('point', np.repeat(retention_time, point_count)),
            'mass': ('point', rounded_mass)
        }
    )
})

# 按保留时间和质荷比聚合,转换为二维矩阵
matrix_ds = ds.intensity.groupby(['retention_time', 'mass']).sum().unstack('mass')

# 补全缺失的质荷比
matrix_ds = matrix_ds.reindex(mass=ideal_mass_values, fill_value=0)

# 转换为DataFrame
matrix_df = matrix_ds.to_dataframe().droplevel(0, axis=1)

内容的提问来源于stack exchange,提问作者lauradn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:01:12