変数にはラベルをつけられますが,これケッコウ癖があって大変.

ベクトルの話

キホンのキ

まずは

> var1<-1
> var1  #デフォルトでラベルなし
[1] 1
> names(var1) #なのでNULL
NULL
> names(var1)<-"VAR1"   #ラベル付け
> var1  #ラベルも表示される
VAR1 
   1 
> names(var1)   #ラベルは"VAR1"
[1] "VAR1"

とすればラベルがつけられる.

ちなみにラベルは変数でもよい

> var1.n<-"VAR1"  
> names(var1)<-var1.n #var1.nという変数でラベルを設定
> var1 #O.K.
VAR1 
   1 

付値とラベル

では,付値においてラベルはどうなる?

> var1<-1;names(var1)<-"VAR1"  #var1のラベルは"VAR1"
> var2<-var1   #var2にvar1を付値
> var2   #var2のラベルも"VAR1"
VAR1 
   1 

どうやら付値に伴いラベルもつけられるらしい.

しかし付値するたびにラベルが変わってしまったら困るような状況は容易に想像できる.そして実際,これは起こる.

> var1<-1;names(var1)<-"VAR1"  #var1のラベルは"VAR1"
> var2<-2;names(var2)<-"VAR2"  #var2のラベルは"VAR2"
> var2  #確かに"VAR2"
VAR2 
   2 
> var2<-var1  #付値
> var2  #えっ?!
VAR1 
   1 

なんと付値に伴いラベルも変更されてしまった.確かに変数名はオブジェクトに束縛された単なる名前であり,付値という作用は右辺の名前が束縛されたオブジェクトに対して,新たに左辺の名前を束縛すること(要するに右辺と左辺の指すものが同一のオブジェクトになる)だから,この仕様はもっともなことなのだろうが, いかにもバグの温床になりそうな仕様である.

演算とラベル

さて,次にラベルを持った変数同士の演算ではどうなるのか?という問題がある.

> var1<-1;names(var1)<-"VAR1"
> var2<-2;names(var2)<-"VAR2"
> var3<-var1+var2 #ラベルを持つ変数同士で演算
> var3 #var1のラベルが使われる
VAR1 
   3 
> var3<-var2+var1 #var2のラベルが使われる
> var3
VAR2 
   3 
> var4<-4 #ラベルなしの変数
> var3<-var4+var2+var1 #var4がラベルなしなのでvar2のラベルが使われる
> var3
VAR2 
   7 

結論からいえば,(ラベルを持つ)最も左の項のラベルが使われるらしい. これは確かめたわけではないが,おそらく演算子の作用順序の問題で,右から左へと作用していくからなのだと思う.

ラベルとNULLとNAと

ラベルを持たないオブジェクトのラベルはNULLである. 値のないラベルを持つがオブジェクトのラベルはNAである. ややこしいが,これは後々非常に重要.

> rm(var1);var1<-1  #var1を定義
> var1  #ラベルはまだない
[1] 1
> names(var1)  #のでNULL
NULL
> names(var1)<-NA  #ラベルをNAにしてみよう
> var1  #NAだけど<>で囲まれてる
<NA> 
   1 
> is.na(names(var1)) #<NA>という文字列ではなく,ほんとにNA
[1] TRUE

ラベルをなくしたければNULLを与えればよい

> var1<-1;names(var1)<-"VAR1"
> var1
VAR1 
   1 
> names(var1)<-NULL  #ラベルはNULL
> var1  #ラベルが消えた
[1] 1

NAとくれば,NaN,Infはどうなんだろう?

> names(var1)<-NaN;var1 #ラベルはNaN
NaN 
  1 
> is.nan(names(var1)) #でもほんとにNaNではない.Infも同様.
[1] FALSE

NaN,Infでは,単に"NaN","Inf"という文字列としてラベルが与えられるようだ.

ほんとにベクトル

これまでの話はすべて要素がひとつのベクトルに対するラベルであった. 話は多少変わって,複数の要素を持つベクトルにラベルをつけることができる.

> v1<-c(1,2,3);names(v1)<-c("v1e1","v1e2","v1e3") #v1を定義
> v1 #ラベルもちゃんとついてます
v1e1 v1e2 v1e3 
   1    2    3 
> v2<-c(1,2,3);names(v2)<-c("v2e1","v2e2","v2e3") #v2を定義
> v2
v2e1 v2e2 v2e3 
   1    2    3 
> v3<-v1+v2 #演算
> v3 #こんな感じ
v1e1 v1e2 v1e3 
   2    4    6 
> v3<-v2+v1
> v3
v2e1 v2e2 v2e3 
   2    4    6 

まあこれは予想通りだと思う.

ラベルが足りない場合はNAで補われる.また,部分的にラベルにアクセスすることもできる.

> v4<-c(1,2,3);names(v4)<-"v4e1" #ひとつだけラベルをつけてみよう.c("v4e1")でも同じ
> v4 #足りない部分は<NA>.
v4e1 <NA> <NA> 
   1    2    3 
> names(v4)[1]  #1番目の要素のラベルだけ取り出す
[1] "v4e1"
> names(v4)[2]<-"v4e2" #二番目の要素だけにラベルをつける
> v4
v4e1 v4e2 <NA> 
   1    2    3 

部分的に名前を変更するには「ベクトルの要素のラベル」ではなく「ベクトルのラベルの要素」にアクセスしなければならない.

> v1<-c(1,2,3);names(v1)<-c("v1e1","v1e2","v1e3")
> v1
v1e1 v1e2 v1e3 
   1    2    3 
> names(v1[2])<-"v1e2'" #2番目の要素のラベルを変更
> v1 #はできない
v1e1 v1e2 v1e3 
   1    2    3 
> names(v1)[2]<-"v1e2'" #こっちは
> v1 #できる
 v1e1 v1e2'  v1e3 
    1     2     3 

これはおそらく,v1[2]というのがv1の二番目の要素のコピーを返すからだと思う. そう考えるとnames関数はRにおいては多少特殊なのである.

自動ラベリング

関数c()は引数をベクトルかリストかに結合する.ベクトルになるかリストになるかは引数しだいだけど,この中で自動的にラベル付けすることができる., ここではベクトルの場合考える.

> c(A=c(B=1,C=2), B=c(E=7,c(1,2)), D=c(1,3), F=1, G=c(B=c(1,2),1),c(1,2))
 A.B  A.C  B.E   B2   B3   D1   D2    F G.B1 G.B2   G3           
   1    2    7    1    2    1    3    1    1    2    1    1    2 

はっきりいってかなりややこしいけど,この例が理解できればもう何もいうことはない.

まず大原則として,引数の展開はより内側の引数から行われる.

  • 1-1. c(X)の時,Xにラベル付けはされない.
  • 1-2. ただしXがすでにラベルを持っているとき,そのラベルがそのまま使われる.
  • 2-1. c(A=b)の時,ラベルはAになる.
  • 2-2. ただしbがすでにラベルを持っているとき(たとえばBとする),ラベルはA.Bになる.
  • 3-1. c(A=c(x,y))の時,ラベルはA1,A2になる.
  • 3-2. ただしx,yがすでにラベルを持っているときは1,2は追加されずに2-2の規則に従う

おそらく自動ラベル付けの規則はこの3点だと思う.

上の例を説明すると,

  • A=c(B=1,C=2)では3-2が適用されている.
  • B=c(E=7,c(1,2))では,まずc(E=7,1,2)とc(1,2)に1-1が適用されて,E=7に対しては3-2が,1,2に対しては3-1が適用されて,B.E,B2,B3となる.

後の項も同じようなことなので,考えてみてください.

結論

ラベルが必要なときはできるだけ直前に明示的にnames()<-を使って指定するべき.


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Google
WWW を検索 OKADAJP.ORG を検索
Last-modified: 2015-03-01 (日) 01:15:59 (1721d)