使用 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 的两种基本格式:
- 表示要转换为
xarray.DataArray
的二维矩阵的数据帧,其中 index
和 columns
已经正确标记了坐标轴。
- 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
我有一个数据框字典,其中每个字典键对应于样本名称,数据框本身有一个 "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 的两种基本格式:
- 表示要转换为
xarray.DataArray
的二维矩阵的数据帧,其中index
和columns
已经正确标记了坐标轴。 - 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()
:
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