如何解决xarray expand_dim添加更高级别的维度 设置功能定义 xarray部分
我正在尝试合并一个数据数组列表,然后添加一个维,以便对每个串联的数据数组进行标记。我以为这是expand_dims的用例,但是尝试了SO的各种解决方案后,我陷入了困境。我认为我缺少有关xarray的基本知识。 这些似乎最接近:
im使用pandas数据框从文件名中编译元数据,然后分组并遍历组以创建数据集,使用skimage.io.ImageCollection将多个图像文件加载到nparray中,并最终创建xarray对象
独立示例
设置
#%% load libraries
from itertools import product
from PIL import Image
import numpy as np
import pandas as pd
import xarray as xr
import glob
from skimage import io
import re
#%% Synthetic data generator
ext = 'png'
delim = '_'
datadir = os.path.join('data','syn')
os.makedirs(datadir,exist_ok=True)
cartag = ['A1','A2']
date = ['2020-05-31','2020-06-01','2020-06-02']
frame = ['Fp','Fmp']
parameter = ['FvFm','t40','t60']
list_vals = [cartag,date,frame,parameter]
mesh = list(product(*list_vals))
mesh = np.array(mesh)
for entry in mesh:
print(entry)
img = np.random.random_sample((8,8))*255
img = img.astype('uint8')
fn = delim.join(entry)+'.png'
pimg = Image.fromarray(img)
pimg.save(os.path.join(datadir,fn))
#%% import synthetic images
fns = [
fn for fn in glob.glob(pathname=os.path.join(datadir,'*%s' % ext))
]
flist = list()
for fullfn in fns:
fn = os.path.basename(fullfn)
fn,_ = os.path.splitext(fn)
f = fn.split(delim)
f.append(fullfn)
flist.append(f)
fdf = pd.DataFrame(flist,columns=[
'plantbarcode','timestamp','frame','parameter','filename'
])
fdf=fdf.sort_values(['timestamp','plantbarcode','frame'])
功能定义
#%%
def get_tind_seconds(parameter):
tind = re.search("\d+",parameter)
if tind is not None:
tind = int(tind.group())
elif parameter == 'FvFm':
tind = 0
else:
raise ValueError("the parameter '%s' is not supported" % parameter)
return (tind)
xarray部分
dfgrps = fdf.groupby(['plantbarcode','parameter'])
ds = list()
for grp,grpdf in dfgrps:
# print(grpdf.parameter.unique())
parameter = grpdf.parameter.unique()[0]
tind = get_tind_seconds(
parameter
) #tind is an integer representing seconds since start of experiment
# print(tind)
filenames = grpdf.filename.to_list()
imgcol = io.ImageCollection(filenames)
imgstack = imgcol.concatenate() #imgstack is Now 2x8x8 ndarray
indf = grpdf.frame #the 2 dim are frames Fp and Fmp
# print(indf)
arr = xr.DataArray(name=parameter,data=imgstack,dims=('frame','y','x'),coords={
# 'frame': indf,'parameter': [parameter,parameter]
# 'tind_s': [tind,tind]
},attrs={
'jobdate': grpdf.timestamp.unique()[0],'plantbarcode': grpdf.plantbarcode.unique()[0]
})
# arr = arr.expand_dims(
# dims={'tind_s': tind}
# ) #<- somehow I need to label each dataarray with another dimension assigning it the dim/coord `tind`
ds.append(arr)
dstest = xr.concat(ds,dim='parameter')
目标是每天有一个不同的文件,即植物条形码。因此,在这种情况下为4个文件。其中的图像可通过参数和帧索引。 tind_s通常可用于为每个参数绘制每个图像的摘要统计信息,因此我也想使该图像变暗/协调-我不确定何时使用它。看起来昏暗必须匹配输入的数据,因此在这种情况下为2帧x 8x8像素。
原始
使用熊猫数据框从文件名(这里是前几项)中编译元数据
frameid plantbarcode experiment datetime jobdate cameralabel filename frame parameter
4 5 A1 doi 2020-05-31 21:01:55 2020-06-01 PSII0 data/psII/A1-doi-20200531T210155-PSII0-5.png Fp FvFm
5 6 A1 doi 2020-05-31 21:01:55 2020-06-01 PSII0 data/psII/A1-doi-20200531T210155-PSII0-6.png Fmp FvFm
6 7 A1 doi 2020-05-31 21:01:55 2020-06-01 PSII0 data/psII/A1-doi-20200531T210155-PSII0-7.png Fp t40_ALon
7 8 A1 doi 2020-05-31 21:01:55 2020-06-01 PSII0 data/psII/A1-doi-20200531T210155-PSII0-8.png Fmp t40_ALon
8 9 A1 doi 2020-05-31 21:01:55 2020-06-01 PSII0 data/psII/A1-doi-20200531T210155-PSII0-9.png Fp t60_ALon
9 10 A1 doi 2020-05-31 21:01:55 2020-06-01 PSII0 data/psII/A1-doi-20200531T210155-PSII0-10.png Fmp t60_ALon
...
然后分组并遍历各个组以创建数据集,使用skimage.io.ImageCollection将多个图像文件加载到nparray中,并最终创建xarray对象
import os
import cppcpyutils as cppc
import re
from skimage import io
import xarray as xr
import numpy as np
import pandas as pd
delimiter = "(.{2})-(.+)-(\d{8}T\d{6})-(.+)-(\d+)"
filedf = cppc.io.import_snapshots('data/psII',camera='psII',delimiter=delimiter)
filedf = filedf.reset_index().set_index('frameid')
pimframes_map = pd.read_csv('data/pimframes_map.csv',index_col = 'frameid')
filedf = filedf.join(pimframes_map,on = 'frameid').reset_index().query('frameid not in [3,4,5,6]')
dfgrps = filedf.groupby(['experiment','jobdate','datetime','parameter'])
ds=list()
for grp,grpdf in dfgrps:
# print(grpdf.parameter.unique())
parameter = grpdf.parameter.unique()[0]
tind = get_tind_seconds(parameter) #tind is an integer representing seconds since start of experiment
# print(tind)
filenames = grpdf.filename.to_list()
imgcol = io.ImageCollection(filenames)
imgstack = imgcol.concatenate() #imgstack is Now 2x640x480 ndarray
indf = grpdf.frame #the 2 dim are frames Fp and Fmp
# print(indf)
arr = xr.DataArray(name=parameter,dims=('induction frame',coords={'induction frame': indf},attrs={'plantbarcode': grpdf.plantbarcode.unique()[0],'jobdate': grpdf.jobdate.unique()[0]})
arr = arr.expand_dims(dims = {'tind_s': tind}) #<- somehow I need to label each dataarray with another dimension assigning it the dim/coord `tind`
ds.append(arr)
expand_dims行导致ValueError: dimensions ('dims',) must have the same length as the number of data dimensions,ndim=0
如果我尝试遵循上面链接的第二个SO,则在其中我提供“ tind_s”作为坐标,它会抱怨相对于暗角有太多。
ValueError: coordinate tind_s has dimensions ('tind_s',),but these are not a subset of the DataArray dimensions ('induction frame','x')
然后我想在tind_s是坐标的情况下合并在一起
dstest=xr.concat(ds[0:4],dim = 'tind_s')
另一种尝试
我确实弄清楚了可以在np.expand_dims()
上使用imgstack
,然后指定多余的dim和coord,但这会导致数组为nan。另外,xr.concat()的结果是数据数组而不是数据集,因此无法保存(?)。在xarray中有直接的方法可以做到这一点吗?
我也将属性转换为暗淡
dfgrps = filedf.groupby(
['experiment','parameter'])
dalist = list()
for grp,grpdf in dfgrps:
print(grpdf.parameter.unique())
parameter = grpdf.parameter.unique()[0]
tind = get_tind_seconds(parameter)
# print(tind)
print(grpdf.plantbarcode.unique())
print(grpdf.jobdate.unique()[0])
filenames = grpdf.filename.to_list()
imgcol = io.ImageCollection(filenames)
imgstack = imgcol.concatenate()
imgstack = np.expand_dims(imgstack,axis=0)
imgstack = np.expand_dims(imgstack,axis=0)
indf = grpdf.frame #xr.Variable('induction frame',grpdf.frame)
# tind = xr.Variable('tind',[tind])
# print(indf)
arr = xr.DataArray(data=imgstack,dims=('jobdate','tind_s','induction frame',coords={
'plantbarcode': grpdf.plantbarcode.unique(),'tind_s': [tind],'induction frame': indf,'jobdate': grpdf.jobdate.unique()}
)
dalist.append(arr)
ds = xr.concat(dalist,dim='jobdate')
for循环之后:print(arr)
<xarray.DataArray (jobdate: 1,plantbarcode: 1,tind_s: 1,induction frame: 2,y: 640,x: 480)>
array([[[[[[0,...,0],[1,1,[0,2,1],0]],[[0,[2,0]]]]]],dtype=uint8)
Coordinates:
* plantbarcode (plantbarcode) object 'A2'
* tind_s (tind_s) int64 60
* induction frame (induction frame) object 'Fp' 'Fmp'
* jobdate (jobdate) datetime64[ns] 2020-06-03
Dimensions without coordinates: y,x
和print(ds)
print(ds)
<xarray.DataArray (jobdate: 18,plantbarcode: 2,tind_s: 3,x: 480)>
array([[[[[[ 0.,0.,1.],[ 0.,1.,2.,0.],[ 1.,7.,4.,4.],0.]],[[ 0.,1.]]],[[[nan,nan,nan],[nan,...
[nan,nan]]],[[[ 0.,[ 2.,0.]]]]]])
Coordinates:
* plantbarcode (plantbarcode) object 'A1' 'A2'
* tind_s (tind_s) int64 0 40 60
* induction frame (induction frame) object 'Fp' 'Fmp'
* jobdate (jobdate) datetime64[ns] 2020-06-01 ... 2020-06-03
Dimensions without coordinates: y,x
我不知道nan数组的来源。对我来说也很奇怪,即使concat中使用了什么dim,每个条目都有一个coord值(在这种情况下为18个文件),即使它们不是唯一的,而其他dims仅显示为唯一值。
如果有人愿意在此处下载小型数据集,请使用link(很抱歉,链接中的建议,我会尝试提供可以即时生成的综合数据集)>
解决方法
您的原始代码在arr.expand_dims(dims={'tind_s': tind})
中包含一个细微的错误(typo):我想您想要dim
而不是dims
,后者被xarray解释为新的尺寸标签(请参见doc)。另外,tind
用作沿新维度创建的元素数量,这可能也不是您想要的。
您的其他尝试(即在创建DataArray
之前扩展数据维度)是IMO的更好方法,但是可以进一步改进。假设您在同一级联维度上有多个标签,建议您创建一个多索引并将其分配给级联维度,即类似
import numpy as np
import pandas as pd
import xarray as xr
da_list = []
props = []
prop_names = ['experiment','plantbarcode','tind']
for i in range(10):
tind = i
indf = ['Fp','Fmp']
data = np.ones((2,640,480)) * i
da = xr.DataArray(
data=data[None,...],dims=('props','frame','y','x'),coords={'frame': indf}
)
props.append((f'experiment{i}',i*2,i))
da_list.append(da)
prop_idx = pd.MultiIndex.from_tuples(props,names=prop_names)
da_concat = xr.concat(da_list,'props')
da_concat.coords['props'] = prop_idx
给出:
<xarray.DataArray (props: 10,frame: 2,y: 640,x: 480)>
array([[[[0.,0.,...,0.],[0.,0.]],[[0.,0.]]],[[[1.,1.,1.],[1.,...
[8.,8.,8.],[8.,8.]]],[[[9.,9.,9.],[9.,9.]],[[9.,9.]]]])
Coordinates:
* frame (frame) <U3 'Fp' 'Fmp'
* props (props) MultiIndex
- experiment (props) object 'experiment0' 'experiment1' ... 'experiment9'
- plantbarcode (props) int64 0 2 4 6 8 10 12 14 16 18
- tind (props) int64 0 1 2 3 4 5 6 7 8 9
Dimensions without coordinates: y,x
,
我在xarray邮件列表上看到了您的问题。调试这个问题很困难,因为它很复杂并且取决于您的数据。如果可以稍微简化一下,也许使用合成数据而不是数据文件,那就太好了。有关此方面的建议,请参见https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports。
如果您共享print(arr)
的输出,这也将有所帮助,以便我们了解您的DataArrays的内容和结构。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。