首页 > 解决方案 > 处理我的测量数据的最佳库和实现

问题描述

我有很多测量数据要在 Python 中分析。每个数据集由一个参数集(带有数字、日期和字符串的标量)和两条曲线组成。

目标是能够过滤(根据标准选择)、分组、聚类、分析(例如,组中所有曲线和参数的平均值)和可视化数据集或它们的组。

我开始使用 Pandas 实现这一点,并创建了一个 Dataframe,其中每个参数都有一个列,测量 ID 作为索引。然后我为曲线添加了一列,使得该列中的每个字段都包含两条曲线作为两个 numpy 数组的字典。

这是一个示例实现(真实的数据框有数千个数据集和数十个参数列)

import numpy as np
import pandas as pd

example_dataset_nr = 5
# Column titles
columns = ['DateTime', 'PositionX', 'Filter', 'Curves']

# Generate arbitrary parameter data to fill example Dataframe
dates = [pd.Timestamp(i*10000000) for i in range(example_dataset_nr)]
positions = np.random.rand(example_dataset_nr)
filters = ['green']*example_dataset_nr

# Generate curves, such that each field in the Dataframes "Curves"-column contains
# a dict with two curves, each as a array of points:
curves = [{'curve_voltage': np.random.randint(0, 100, size=(100,2)), 'curve_current': np.random.randint(0, 100, size=(100))} for i in range(example_dataset_nr)]

# Create Dataframe
df = pd.DataFrame(data=np.array([dates, positions, filters, curves]).T, columns=columns)
df['PositionX'] = df['PositionX'].astype(np.float)
df.index.rename('MeasurementID', inplace=True)
print(df.to_string())

现在,如果我用“df.mean()”之类的操作分析数据,Pandas 当然不知道如何处理曲线。我希望 pandas 像在其他数字字段上一样对曲线进行操作。例如,假设 df.mean(),Pandas 应该计算所有曲线的平均值,而不仅仅是 Dataframe 中的参数。

# Get the mean of all numeric types. Want to get the mean curves of all 'curve_voltage' and 'curve_current', too.
df.mean()

我想知道,在 Python 中实现这种行为的最佳方式是什么?

以下是一些建议:

  1. Pandas:对曲线使用单独的数据框或系列,并通过外键将它们连接到纯“参数数据框”。但接下来的问题是如何自动将所有方法从“参数数据帧”转发到“曲线数据帧”而不重新实现它们?
  2. 熊猫:子类数据框。或任何其他扩展 Pandas 的方式。我阅读了https://pandas.pydata.org/pandas-docs/stable/development/extending.html,但我不确定哪个是正确的方法。再次以有意义的方式转发方法的相同问题。
  3. Xarray:我从未使用过它,但是 Xarray 是不是更适合我的需求的工具,然后是 pandas?
  4. 数据库:数据库是否更适合使用 SQL 之类的东西?
  5. 还有其他可行的选择吗?

标签: pythonpandasnumpypython-xarray

解决方案


我认为这对于 xarray 来说是一个很好的用例,因为它自然支持将表格(一维)数据与更高维数据(你的曲线)结合起来。

使用 xarray,您可以像这样构建数据集:

import xarray as xr

ds = xr.Dataset(
    {
        'DateTime': (['MeasurementID'], dates),
        'PositionX': (['MeasurementID'], positions),
        'Filter': (['MeasurementID'], filters),
        'curve_voltage': (['MeasurementID', 'curve_x', 'curve_y'], [row['curve_voltage'] for row in curves]),
        'curve_current': (['MeasurementID', 'curve_x'], [row['curve_current'] for row in curves]),
    },
    coords={
        'MeasurementID': np.arange(len(dates)),
        'curve_x': np.arange(100),
        'curve_y': np.arange(2)
    }
)

并像这样使用它:

>>> ds
<xarray.Dataset>
Dimensions:        (MeasurementID: 5, curve_x: 100, curve_y: 2)
Coordinates:
  * MeasurementID  (MeasurementID) int64 0 1 2 3 4
  * curve_x        (curve_x) int64 0 1 2 3 4 5 6 7 8 ... 92 93 94 95 96 97 98 99
  * curve_y        (curve_y) int64 0 1
Data variables:
    DateTime       (MeasurementID) datetime64[ns] 1970-01-01 ... 1970-01-01T00:00:00.040000
    PositionX      (MeasurementID) float64 0.7422 0.4789 0.7673 0.2552 0.8817
    Filter         (MeasurementID) <U5 'green' 'green' 'green' 'green' 'green'
    curve_voltage  (MeasurementID, curve_x, curve_y) int64 11 40 51 ... 38 26 64
    curve_current  (MeasurementID, curve_x) int64 88 24 57 32 75 ... 60 25 40 3

>>> ds['curve_voltage'].mean()  # global average over all voltage curves
<xarray.DataArray 'curve_voltage' ()>
array(49.26)

>>> ds['curve_voltage'].mean('curve_x')  # average only over curve_x dimension
ds['curve_voltage'].mean('curve_x')

<xarray.DataArray 'curve_voltage' (MeasurementID: 5, curve_y: 2)>
array([[47.06, 50.73],
       [53.1 , 45.41],
       [51.41, 50.33],
       [49.12, 46.26],
       [47.94, 51.24]])
Coordinates:
  * MeasurementID  (MeasurementID) int64 0 1 2 3 4
  * curve_y        (curve_y) int64 0 1

当然,您可以(并且应该)为附加维度指定比curve_x和更有意义的名称curve_y


推荐阅读