I'm not sure /why/ you want to assign to $h{undef} which is what your trying, my best suggestion would be to explicitly use $h{ $val // '__NOT PRESENT__' } in perl 5.10. This still leaves it as an exercise to the reader, on what to do when you have two undefs you want to save too...
This is pseudo-data, which probably doesn't represent a real world problem very well. My fix would be to skip over the undef vals.
foreach my $d(@data){
my %h;
foreach my $c(0 .. $#categories){
my $val=$d->[$c];
next unless defined $val;
my $cat=$categories[$c];
$h{$val}=$cat;
}
push @master, \%h;
}