使用 xarray 基于列合并 pandas 数据帧

Using xarray to merge pandas dataframes based on a column

我有一个数据框字典,其中每个字典键对应于样本名称,数据框本身有一个 "time" 列和一些测量列(温度、浓度等)。样本之间的时间列不一致(不同样本的开始和结束时间不同,尽管我认为开始和结束之间的所有时间点都是 measured/have 相同的 dT)。

我想将所有数据合并到一个 xarray 中,其中一个轴是时间,另一个轴是测量类型,第三个轴是样本名称。由于并非所有样本都测量了所有时间,因此应将缺失数据替换为 nan。

我对 xarray 没有什么经验,但是做了一个简单的合并(从 xarray 的字典构造 xarray)我不知道如何使 "time" 成为轴之一(相反,每个只是连接所有的时间是数据列之一的样本)。

感谢您的帮助!

编辑:

这是我的虚拟数据代码

import pandas as pd
import xarray as xr

#make fake data
dfs = {'sample1':pd.DataFrame([[1,0,0],[2,0,0],[3,0,0]],columns = ["Time","ColA","ColB"]), 
    'sample2':pd.DataFrame([[2,1,1],[3,1,1],[4,1,1]],columns = ["Time","ColA","ColB"])}

#code I use for real data
xrs = {k: xr.DataArray(v) for k, v in dfs.items()}
merged = xr.Dataset(variables).to_array(dim="samples")

print(merged)

输出为:

<xarray.DataArray (samples: 2, dim_0: 3, dim_1: 3)>
array([[[1, 0, 0],
        [2, 0, 0],
        [3, 0, 0]],

       [[2, 1, 1],
        [3, 1, 1],
        [4, 1, 1]]], dtype=int64)
Coordinates:
  * dim_0    (dim_0) int64 0 1 2
  * dim_1    (dim_1) object 'Time' 'ColA' 'ColB'
  * samples  (samples) <U7 'sample1' 'sample2'

期望的输出:

<xarray.DataArray (samples: 2, Time: 4, dim_1: 2)>
array([[[0, 0],
    [0, 0],
    [0, 0],
    [nan, nan]],

   [[nan, nan]
    [1, 1],
    [1, 1],
    [1, 1]]], dtype=int64)
Coordinates:
  * Time     (Time) int64 1 2 3 4
  * dim_1    (dim_1) object 'ColA' 'ColB'
  * samples  (samples) <U7 'sample1' 'sample2'

Xarray 支持 converting from pandas 的两种基本格式:

  1. 表示要转换为 xarray.DataArray 的二维矩阵的数据帧,其中 indexcolumns 已经正确标记了坐标轴。
  2. DataFrames 表示扁平化 "tidy data",其中 index 中的 MultiIndex 级别对应于结果上所需的轴,columns 对应于 xarray.Dataset 中的所需变量。

你的格式最接近前者,我们试试吧。事实证明,您所缺少的只是调用 .set_index('Time') 以指示该列应用于标记轴:

In [23]: da = xr.Dataset({k: v.set_index('Time') for k, v in dfs.items()}).to_array(dim='samples')

In [24]: da
Out[24]:
<xarray.DataArray (samples: 2, Time: 4, dim_1: 2)>
array([[[  0.,   0.],
        [  0.,   0.],
        [  0.,   0.],
        [ nan,  nan]],

       [[ nan,  nan],
        [  1.,   1.],
        [  1.,   1.],
        [  1.,   1.]]])
Coordinates:
  * Time     (Time) int64 1 2 3 4
  * dim_1    (dim_1) object 'ColA' 'ColB'
  * samples  (samples) <U7 'sample1' 'sample2'

第二种方法也值得考虑,因为让你的数据整洁也会让你更容易使用 DataFrame(例如,轻松地在 Seaborn 中绘制你的数据)。

获得 xarray.DataArray 后,您可以使用 to_series():

将其转换回 pandas
In [22]: da.to_series()
Out[22]:
samples  Time  dim_1
sample1  1     ColA     0.0
               ColB     0.0
         2     ColA     0.0
               ColB     0.0
         3     ColA     0.0
               ColB     0.0
         4     ColA     NaN
               ColB     NaN
sample2  1     ColA     NaN
               ColB     NaN
         2     ColA     1.0
               ColB     1.0
         3     ColA     1.0
               ColB     1.0
         4     ColA     1.0
               ColB     1.0
dtype: float64

或者坚持使用 DataFrames,您可以使用 pd.melt 将您的宽数据 "melt" 变成长而整齐的形式,例如,

In [26]: melted = pd.melt(dfs['sample1'], id_vars=['Time'], var_name='Measurement')

In [27]: melted
Out[27]:
   Time Measurement  value
0     1        ColA      0
1     2        ColA      0
2     3        ColA      0
3     1        ColB      0
4     2        ColB      0
5     3        ColB      0

然后从 xarray 转换只需设置一个 MultiIndex 并调用 .to_xarray():

In [28]: melted.set_index(['Time', 'Measurement']).to_xarray()
Out[28]:
<xarray.Dataset>
Dimensions:      (Measurement: 2, Time: 3)
Coordinates:
  * Time         (Time) int64 1 2 3
  * Measurement  (Measurement) object 'ColA' 'ColB'
Data variables:
    value        (Time, Measurement) int64 0 0 0 0 0 0