Python Xarray:如何将3维DataArray转换为2维堆叠的Pandas数据框。

3

我有一个3D的DataArray数据,它是多个模型运行的时间序列数据。因此,行是由模拟时间步骤索引的,列是有关模型捕获的各种变量,而深度坐标表示单个模拟运行,因为我多次运行整个模拟。

我的目标是将这个3D的DataArray转换成2D的dataframe,以便我可以将其导出为CSV文件。为了做到这一点,我需要将每个模拟运行堆叠在一起,这样3D数组就被转换为2D数组。

我有一些生成测试数据的代码,但我对不够熟悉,不知道如何进行这种堆叠操作。

这里是一些用于生成测试数据的代码。

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

results_matrix = np.zeros([5, 7, 4])
simulation_matrix = xr.DataArray(results_matrix,
                                      coords={'simdata': ['val1', 'val2','val3','val4'],
                                              'run': range(5),
                                              'year': range(7)},
                                      dims=('run', 'year', 'simdata'))

itercount = 0
for i in tqdm(range(5)):
    simulation_matrix[i, :, :] = i
    itercount += 1

该代码将生成一个类似于DataArray的数据数组。
<xarray.DataArray (run: 5, year: 7, simdata: 4)>
array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],
 ... Additional arrays truncated

我希望将此转换为二维的 Pandas 数据帧,类似于:
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [1., 0., 0., 0.],
        [1., 0., 0., 0.],
        [1., 0., 0., 0.],
        [1., 0., 0., 0.],
        [1., 0., 0., 0.],
        [1., 0., 0., 0.],
        [1., 0., 0., 0.]]]

有任何建议吗?

更新:

根据@rahlf23和@DSM的评论,我尝试使用simulation_matrix.to_dataframe('fred').unstack(),并取得了一些成功。

        fred
simdata val1    val2    val3    val4
run year                
0  0    0   0.0 0.0 0.0 0.0
   1    0.0 0.0 0.0 0.0
   2    0.0 0.0 0.0 0.0
   3    0.0 0.0 0.0 0.0
   4    0.0 0.0 0.0 0.0
   5    0.0 0.0 0.0 0.0
   6    0.0 0.0 0.0 0.0
1   0   1.0 1.0 1.0 1.0
   1    1.0 1.0 1.0 1.0
   2    1.0 1.0 1.0 1.0
   3    1.0 1.0 1.0 1.0
   4    1.0 1.0 1.0 1.0
   5    1.0 1.0 1.0 1.0
   6    1.0 1.0 1.0 1.0

我尝试过了,但好像没有起作用。我尝试了 simulation_matrix.to_dataframe().unstack() 但是出现了错误 cannot convert an unnamed DataArray to a DataFrame: use the ``name`` parameter 。使用 unstack 是正确的想法吗?文档中没有显示任何代码示例,所以很难确定这些命令的作用。 - krishnab
尝试使用simulation_matrix.iloc[:,:,1].to_pandas():http://xarray.pydata.org/en/stable/generated/xarray.DataArray.to_pandas.html - rahlf23
1
你可以在 to_dataframe 中添加一个名称,例如 .to_dataframe("fred").unstack(),但我不确定你期望的顺序是什么:我认为你想要整行都是1,而不是[1, 0, 0, 0]。 - DSM
好的,进展不错。我尝试了 simulation_matrix.to_dataframe('fred').unstack() 然后它似乎以正确的方式处理了一些东西。问题是它似乎将运行编号只留下了一个单一的值而没有填充该列。让我更新一下原始帖子,看看情况如何。 - krishnab
1
@krishnab:这只是多重索引的表示方式。您可以添加.reset_index()来确认它们是否都在那里。 - DSM
显示剩余4条评论
2个回答

2

使用您的测试数据,您可以使用to_pandas()pd.concat()

df = pd.concat([simulation_matrix.loc[i,:,:].to_pandas() for i in range(simulation_matrix.shape[2])])

产生:

simdata  val1  val2  val3  val4
year                           
0         0.0   0.0   0.0   0.0
1         0.0   0.0   0.0   0.0
2         0.0   0.0   0.0   0.0
3         0.0   0.0   0.0   0.0
4         0.0   0.0   0.0   0.0
5         0.0   0.0   0.0   0.0
6         0.0   0.0   0.0   0.0
0         1.0   1.0   1.0   1.0
1         1.0   1.0   1.0   1.0
2         1.0   1.0   1.0   1.0
3         1.0   1.0   1.0   1.0
4         1.0   1.0   1.0   1.0
5         1.0   1.0   1.0   1.0
6         1.0   1.0   1.0   1.0
0         2.0   2.0   2.0   2.0
1         2.0   2.0   2.0   2.0
2         2.0   2.0   2.0   2.0
3         2.0   2.0   2.0   2.0
4         2.0   2.0   2.0   2.0
5         2.0   2.0   2.0   2.0
6         2.0   2.0   2.0   2.0
0         3.0   3.0   3.0   3.0
1         3.0   3.0   3.0   3.0
2         3.0   3.0   3.0   3.0
3         3.0   3.0   3.0   3.0
4         3.0   3.0   3.0   3.0
5         3.0   3.0   3.0   3.0
6         3.0   3.0   3.0   3.0

太好了。我看到你是怎么做的了。非常感谢你在这方面的帮助。 - krishnab
没问题,很高兴我能帮到你! - rahlf23

2
你可以使用 .to_dataframe 然后使用 unstack,只需要传递一个名称附加到数据集(成为包含该值的列)即可:
In [41]: simulation_matrix.to_dataframe("results").unstack()
Out[41]: 
         results               
simdata     val1 val2 val3 val4
run year                       
0   0        0.0  0.0  0.0  0.0
    1        0.0  0.0  0.0  0.0
    2        0.0  0.0  0.0  0.0
    3        0.0  0.0  0.0  0.0
    4        0.0  0.0  0.0  0.0
    5        0.0  0.0  0.0  0.0
    6        0.0  0.0  0.0  0.0
1   0        1.0  1.0  1.0  1.0
    1        1.0  1.0  1.0  1.0
    2        1.0  1.0  1.0  1.0
    3        1.0  1.0  1.0  1.0
    4        1.0  1.0  1.0  1.0
    5        1.0  1.0  1.0  1.0
    6        1.0  1.0  1.0  1.0
2   0        2.0  2.0  2.0  2.0
    1        2.0  2.0  2.0  2.0
    2        2.0  2.0  2.0  2.0
    3        2.0  2.0  2.0  2.0
    4        2.0  2.0  2.0  2.0
    5        2.0  2.0  2.0  2.0
    6        2.0  2.0  2.0  2.0
3   0        3.0  3.0  3.0  3.0
    1        3.0  3.0  3.0  3.0
    2        3.0  3.0  3.0  3.0
    3        3.0  3.0  3.0  3.0
    4        3.0  3.0  3.0  3.0
    5        3.0  3.0  3.0  3.0
    6        3.0  3.0  3.0  3.0
4   0        4.0  4.0  4.0  4.0
    1        4.0  4.0  4.0  4.0
    2        4.0  4.0  4.0  4.0
    3        4.0  4.0  4.0  4.0
    4        4.0  4.0  4.0  4.0
    5        4.0  4.0  4.0  4.0
    6        4.0  4.0  4.0  4.0

尽管默认表示仅显示重复组中的第一个,但所有“run”值都在其中:

In [50]: df = simulation_matrix.to_dataframe("results").unstack()

In [51]: df.reset_index().head()
Out[51]: 
        run year results               
simdata             val1 val2 val3 val4
0         0    0     0.0  0.0  0.0  0.0
1         0    1     0.0  0.0  0.0  0.0
2         0    2     0.0  0.0  0.0  0.0
3         0    3     0.0  0.0  0.0  0.0
4         0    4     0.0  0.0  0.0  0.0

这真的很有帮助。非常感谢您的建议。这确实让我比之前更进一步了。 - krishnab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接