Appending data when extracting nested fields as individual variables

1 次查看(过去 30 天)
Hi Matlab community,
I have a variable "hands" that contains several fields, and I am trying to make hand_type, one of the fields, as an individual variable. The size of "hands" varies between 1x1 struct and 1x2 struct, hence I used the if-elseif loop. When "hands" is 1x2 struct, I want the second group of data to be stored in a parallel cell next to the first group of data, hence the {end+1}, as I don't want them to be in the same cell and create an additional layer of nesting.
However, in the resulting "hand_type", whenever "hands" is 1x2 struct, "hand_type" only has 0x0 double. In comparison, when "hands" is 1x1 struct, "hand_type" has a value of a number (0, 1, etc).
Could someone help me to identify what I am doing wrong, and how I can fix the problem? The full script is attached.
Thank you in advance!
has_hands = ~cellfun(@isempty, {frames.hands});
filtered_frames = frames(has_hands);
id = {filtered_frames.id};
time = {filtered_frames.timestamp};
hands = {filtered_frames.hands};
hand_type = cell(size(hands));
for i = 1:numel(hands)
if isequal(size(hands{i}),[1,1])
hand_type{i} = hands{i}.type;
elseif isequal(size(hands{i}),[1,2])
hand_type{end+1} = hands{i}(1).type;
hand_type{end+1} = hands{i}(2).type;
end
  4 个评论
Voss
Voss 2024-4-30
@Julia Thanks for that!
However, it looks like the variable in the .mat file is not similar to what you describe in the question.
S = load('frames.mat')
S = struct with fields:
first100: [1x100 struct]
frames = S.first100
frames = 1x100 struct array with fields:
frames
temp = [frames.frames]
temp = 1x100
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 0 0
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
any(temp)
ans = logical
0
It is a struct array with one field (called "frames") containing all scalar zeros, instead of a struct array with multiple fields ("hands", "id", "timestamp").
Julia
Julia 2024-5-1
@Voss I'm so sorry about that! I made a mistake when extracting part "frames" (the original variable is too large to upload). The correct version of frames.mat is now uploaded, which should represent what I described in the question.

请先登录,再进行评论。

采纳的回答

Stephen23
Stephen23 2024-5-1
编辑:Stephen23 2024-5-1
The simple and efficient MATLAB approach using two comma-separated lists (no loops are required!):
first100 = load('frames.mat').first100
first100 = 1x100 struct array with fields:
id timestamp hands version
tmp = [first100.hands]; % 1x140 structure array
hand_type = [tmp.type] % 1x140 double array
hand_type = 1x140
0 0 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
  7 个评论
Julia
Julia 2024-5-1
编辑:Julia 2024-5-1
Edited: Sorry for bothering you! I think I figured it out by using bones_only = arrayfun(@(x) x.bones, thumb, 'UniformOutput', false);
Hi@Stephen23, can I ask for your help one more time?
I am trying to extract data from "digits" in "hands". For my new variable "thumb_1", I would need all data of "prev_joint" in row 1 for each "bones" structure. However, I am having troubles accessing that.
Here are the steps I have taken so far:
digits = [tmp.digits];
thumb = digits([digits.finger_id] == 0);
Then, when I tried to extract "bones", thumb_data = thumb.bones; only gave me a 1x4 struct instead the whole array of data. I tried vertcat and indexing, which had the same problem.
I'm really sorry if this is another stupid question.
Stephen23
Stephen23 2024-5-1
"For my new variable "thumb_1", I would need all data of "prev_joint" in row 1 for each "bones" structure. However, I am having troubles accessing that."
In total there are 2700 BONES structures: perhaps you only want to access a subset of them.
"Row 1" is confusing me... I do not see any arrays which have more than one row.
first100 = load('frames.mat').first100
first100 = 1x100 struct array with fields:
id timestamp hands version
tmp = [first100.hands]
tmp = 1x140 struct array with fields:
id type confidence visible_time pinch_distance grab_angle pinch_strength grab_strength palm digits arm
digits = [tmp.digits]
digits = 1x700 struct array with fields:
finger_id is_extended bones
id0 = [digits.finger_id]==0;
nnz(id0)
ans = 140
bones = [digits.bones]
bones = 1x2800 struct array with fields:
prev_joint next_joint width rotation
[bones.prev_joint]
ans = 1x8400
-116.7911 162.2039 -46.7425 -116.7911 162.2039 -46.7425 -119.9917 117.6783 -38.0319 -126.3976 96.3697 -35.3235 -108.4055 162.7472 -61.3988 -93.4886 98.3964 -77.4282 -92.6329 72.1629 -68.9765 -100.3854 67.2915 -57.0133 -113.6001 162.8399 -68.6146 -105.5847 102.6094 -90.1403
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Perhaps something like this:
thumb = [digits(id0).bones]
thumb = 1x560 struct array with fields:
prev_joint next_joint width rotation
or perhaps this, which returns the first element of each structure array:
first = cellfun(@(s)s(1),{digits(id0).bones})
first = 1x140 struct array with fields:
prev_joint next_joint width rotation
[first.prev_joint]
ans = 1x420
-116.7911 162.2039 -46.7425 -118.7844 162.6437 -45.3555 -121.9578 165.5228 -42.9163 -122.7603 168.2865 -42.1373 -55.5596 379.1909 -25.3262 -124.2343 170.6235 -41.0462 -56.3998 382.6714 -26.1379 -125.5027 172.1781 -40.9584 -57.1402 385.6229 -26.9821 -126.1411 173.0077 -41.2141
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>

请先登录,再进行评论。

更多回答(1 个)

SAI SRUJAN
SAI SRUJAN 2024-5-1
编辑:SAI SRUJAN 2024-5-1
Hi Julia,
I understand that you are facing an issue appending data when extracting nested fields as inidividual variables.
Please go through the following code sample to proceed further,
has_hands = ~cellfun(@isempty, {first100.hands});
filtered_first100 = first100(has_hands);
id = {filtered_first100.id};
time = {filtered_first100.timestamp};
hands = {filtered_first100.hands};
hand_type = {};
for i = 1:numel(hands)
if isequal(size(hands{i}), [1,1])
hand_type{end+1} = hands{i}.type;
elseif isequal(size(hands{i}), [1,2])
hand_type{end+1} = hands{i}(1).type;
hand_type{end+1} = hands{i}(2).type;
end
end
The variable 'hands' is a 1x99 struct, containing 41 structs within it, each of size [1,2]. Therefore, the expected size of 'hand_types' should be 140 double as we are parallelly storing the values instead of nesting.
I hope this helps!
  2 个评论
Stephen23
Stephen23 2024-5-1
编辑:Stephen23 2024-5-1
"The variable 'hands' is a 1x99 struct"
No, it is actually a cell array (not a structure). Lets check it right now (note that MATLAB tells us it is a cell array too):
first100 = load('frames.mat').first100;
has_hands = ~cellfun(@isempty, {first100.hands});
filtered_first100 = first100(has_hands);
hands = {filtered_first100.hands} % <- here you define HANDS as a cell array.
hands = 1x99 cell array
Columns 1 through 11 {1x1 struct} {1x1 struct} {1x1 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} Columns 12 through 22 {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} Columns 23 through 33 {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} Columns 34 through 44 {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} Columns 45 through 55 {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} Columns 56 through 66 {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} Columns 67 through 77 {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} {1x2 struct} Columns 78 through 88 {1x2 struct} {1x2 struct} {1x2 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x2 struct} {1x2 struct} {1x1 struct} {1x1 struct} {1x1 struct} Columns 89 through 99 {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct} {1x1 struct}
isstruct(hands) % is it a struct array? (hint: no)
ans = logical
0
iscell(hands) % it is a cell array (exactly as I wrote)
ans = logical
1
If you had used square brackets it would be a structure array (and more efficient data design).
"containing 41 structs within it, each of size [1,2]."
Lets now check that misinformation as well:
C = cellfun(@size,hands,'uni',0);
unique(vertcat(C{:}),'rows')
ans = 2x2
1 1 1 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Some of the structures are scalar (i.e. 1x1), some have size 1x2 (just as the OP correctly stated).
"Therefore, the expected size of 'hand_types' should be 140 double as we are parallelly storing the values instead of nesting."
But it won't be, because you defined it to be a cell array, not a double array (you can confirm this by actually running your code):
hand_type = {}; % <- cell array
Note that storing lots of scalar numerics in a cell array is very inefficient data design and should be avoided.
Julia
Julia 2024-5-1
It worked!! Thank you so much! Your help is really appreciated.
I see that I made a mistake when assigning an empty cell array to hand_type. Could you please help me to understand why hand_type = cell(size(hands)); was wrong, and what's the difference between it and hand_type = {};? Sorry I'm quite new to Matlab and may be asking silly questions.
Besides, may I ask a further question? If I also need to double the values in "id" and "time" when "hands" has size [1,2], so that the data in "hands" can still match the id and timestamp, is it possible to do?

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Matrix Indexing 的更多信息

产品


版本

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by