「Rを用いた〇〇入門」ワークショップを担当するときの注意点

去年のFLEAT VIIでのワークショップは、時間(もとい時間のマネジメント)不足でだいぶ消化不良に終わってしまった。参加者の皆様には申し訳なく思っております。。

今回は、単なる“R”の入門講習ではなく“Rを用いた統計処理” の入門講習という依頼だったので、Rの入門だけで終わるわけにもいかずにいろいろ詰め込んでいたのだけど、それが裏目に出てしまった。

ほとぼりも冷めたと思うので、今後のために(これから先、そんな話は来ないかもしれないけど)、 純粋なR入門講習ではなく、Rを用いた〇〇入門講習という、時間に制約のあるワークショップを担当するときの、自分なりの注意点をまとめておきたい。

環境を統一する

今回は、会場PCだけでなく各自持参したPCも使用可能とした。その結果、Windows/Macネットに繋がっている/いないRStudioが入っている/いない会場PCを使用する/しないなど、参加者の環境が様々で、トラブルシューティングにかなり時間を食ってしまった。WSの時間は限られているので、そういった時間のロスは避けたい。したがって、参加者のPC環境を事前に、できるだけ統一しておくことが望ましい

一番楽な方法は、会場PCのR/RStudioを使うことだろう。 1 環境が全員一緒なのでサポートもしやすいし、ネットワーク接続も確保されている。

持ち込みPCを使用する場合は、生RもしくはRStudioのどちらを使用するかを予め決めておく。個人的には、RStudio入門講習でないのであれば、生Rでいいのではないかと思う。RStudioの使い方を説明してるうちに、肝心の中身の時間が減ってしまうのは避けたい。

また、追加でパッケージのインストールを行うことになるので、ネットワークへの接続も前提としておく。 2 会場の無線LANの情報を提示する、会場に無線LANがないなら各自での準備をお願いする、といった対策が必要だろう。

受講対象者を絞る

今回は、特に受講対象者は指定していなかった(と思う)。実際は、参加者のRスキルやPCスキルは様々で、これもWSの進行上悩ましい問題である。

今思えば、このツイートで先輩先生がおっしゃったとおり、受講対象者を絞るべきだったと思う。「変数への代入、データの読み込み、関数の読み込みなど、Rの基本的な操作ができる方」「Rは使っているが、〇〇パッケージを用いた〇〇はできない方」といった具合に、どういった層に向けてのWSなのかを明示する。そうすれば、ある程度は参加者の足並みを揃えることができたはずだ。さすがにPCスキルについて言及するのは野暮だと思うけど、もしかすると言ったほうがいいのかもしれない。

ハンズオン中心か、トーク中心かを決める

今回は、ハンズオンも入れつつトークも入れるという、半々の形であった。要するに、どっちつかずである。

先のツイートの先輩先生は、「話す内容を削ってハンズオンの時間を入れるといい」というアドバイスをされていたが、一方で別の先輩先生からは、「ハンズオンなしで全部トークにすればいい」というアドバイスもいただいた。

これはどちらも正しいと思う。つまり、どっちつかずではなく、どちらの形式を中心とするかを決めないといけないということだろう。まずはWSの目的に合った形式を選ぶ。もし技術の習得を目的とするならハンズオン中心とし、いちばん大事なハンズオンの時間をしっかり確保する。もし知識・考え方の習得を目的とするならトーク中心とし、ハンズオンはなし、もしくは必要最小限にしたほうがよい、ということだろう。

まとめると

以下のようなことを予め決めておいて、その上でアブストラクトに記載しておくとよい。

  • 使用PCやRStudioの有無など、環境を指定する
  • WSの対象となる層を具体的な条件で絞り込む
  • ハンズオン中心でいくか、トーク中心でいくかを決める

逆に言えば、受講する側はこれらを事前に確認しておけば、参加したけど期待はずれだった、みたいな事態を避けやすくなるのではないかと思う。

書き上げてから、これってRを用いた〇〇入門講習だけじゃなくて、R自体の入門講習にも同じことが言えるなって思った。まあいいや。


(続)Rで学生・生徒を指定した人数のグループに分ける関数

先日のNagoya.R #18で、以下の記事のグループ分け関数についてお話させてもらった。

Rで学生・生徒を指定した人数のグループに分ける関数

この関数について吉野睦さんから、もっと簡単に同じことができることを教えていただきました。この場をお借りして感謝申し上げます。ありがとうございました。ご提供いただいたコードを許可をいただいた上で以下に転載させていただきます。

rm(list=ls())
 
# エクセル名簿から貼り付けるとこんな感じ(改行だけ)
 
x <- c("
川口勇作
川口勇作
川口勇作
川口勇作
川口勇作
川口勇作
")
# こんな感じに縦に並んでいるものを貼り付ける

# 改行コードで分割する
x <- strsplit(x,"\n")[[1]]           # なぜかリスト形式になってしまうので[[1]]
x <- x[!nchar(x)==0]                 # 空文字列を取り除く
 
# ここからがメインルーチン
class <- 10
index <- rep(1:class,len=length(x))  # クラス番号生成
index <- sample(index)               # クラス番号をシャッフルする
x <- split(x,index)                  # クラス分けする
print(x,quote=FALSE)                 # 名前のダブルコーテーションを取って表示

流れとしては以下のとおり。

エクセルから、ダブルコーテーションなし、カンマなし、改行のみで貼り付けたことを想定し、

strsplit()関数で名前データ生成

あとはメインルーチンで、

クラス数を指定
rep()関数でクラス番号を生成
sample()関数でシャッフル
split()関数でクラス分け
print()関数で、ダブルコーテーションなし表示

自分はfor文の中でfor文を回すという効率の悪いやり方をしていた。以前Python Bootcampに参加したときにも感じたことだが、今の自分にはこういう効率の良いコードを書く能力が欠けているようだ。フィードバックをいただける環境に感謝。

【追記 2018/9/2】
吉野さんから以下のような追加情報をいただきました。ありがとうございました。

最後の、

print(x,quote=FALSE)

を、次のように変更して頂くと、リスト形式がデータフレームに変更できます。

y <- lapply(x,function(z){c(z,rep("",max(sapply(x,length))-length(z)))})
xx <- do.call(cbind,y)
print(xx,quote=FALSE)

 

Rで学生・生徒を指定した人数のグループに分ける関数

【追記 2018/5/13】コードをWordpressに貼り付けたときに一部の文字(””)が違う文字として貼り付けられてしまっていることに気づきました。現状では、そのまま貼り付けただけではエラーになりますので、ご注意ください。 -> 解決しました。

【追記 2018/5/29】特定の人数でエラーを吐くバグを修正しました。バグをご指摘くださった田村さんありがとうございました。

【追記 2018/5/31】出力の”member”が”menber”になってました。どれだけ麺好きなんだ。ということで修正しました。

【追記 2018/8/24】この関数について、Nagoya.Rでもっと簡単に同じことができるというコメントをいただきました。詳しくはこちら


表題の件について。前々から作ろうと思っていたけど、近いうちにNagoya.Rをやることになりそうなので、話の種に作ってみた。

以下をRのコンソールに貼り付ける。

Windowsの方はこちら

groupfunc <- function(p){
	d <- as.vector(read.table("clipboard", header = F, sep = ",")[,1])
 
	#学生数
	n <- length(d)
 
	#余りの人数
	r <- n%%p
 
	#空の行列を作成
	if(1 <= r){
		tb <- matrix(, nrow = trunc(n/p), ncol = (p+1)) #余りが1以上であれば、余分に1列を追加
	}else{
		tb <- matrix(, nrow = trunc(n/p), ncol = p)
	}
 
	#余った学生がいなくなるまで1人多くサンプリング
	for(i in 1:trunc(n/p)){
		if(i <= r){
			for(j in 1:(p+1)){
				tb[i,j] <- sample(d, 1)
				d <- d[-which(d %in% tb[i,j])]
			}
		}else{
			for(j in 1:p){
				tb[i,j] <- sample(d, 1)
				d <- d[-which(d %in% tb[i,j])]
			}
		}
	}
	result <- as.data.frame(tb) 
 
	#空行の削除(参考:http://id.fnshr.info/2017/08/14/r-blank-row-col/)
	#	is_blank の定義
	is_blank <- function(x) {is.na(x) | x == ""}
 
	# すべてが空欄である行を探す
	unnecessary_row <- apply(result, 1,
													 function(x){
														 all(is_blank(x))
													 })
 
	# 「すべてが空欄である行」以外を残す(=空行の除去)
	result <- result[!unnecessary_row,]
 
	#見出し行に名前を付与
	namae <- "member.1"
	for(k in 2:ncol(result)){
		namae <- append(namae, paste("member.", k))
	}
	colnames(result) <- namae
	result
}

【追記 2018/5/13】Macの方はこちらを。Macでは動かないことをご指摘くださった田村さんありがとうございました!

groupfunc <- function(p){
	d <- as.vector(read.table(pipe("pbpaste"), header = F, sep = ",")[,1])
 
	#学生数
	n <- length(d)
 
	#余りの人数
	r <- n%%p
 
	#空の行列を作成
	if(1 <= r){
		tb <- matrix(, nrow = trunc(n/p), ncol = (p+1)) #余りが1以上であれば、余分に1列を追加
	}else{
		tb <- matrix(, nrow = trunc(n/p), ncol = p)
	}
 
	#余った学生がいなくなるまで1人多くサンプリング
	for(i in 1:trunc(n/p)){
		if(i <= r){
			for(j in 1:(p+1)){
				tb[i,j] <- sample(d, 1)
				d <- d[-which(d %in% tb[i,j])]
			}
		}else{
			for(j in 1:p){
				tb[i,j] <- sample(d, 1)
				d <- d[-which(d %in% tb[i,j])]
			}
		}
	}
	result <- as.data.frame(tb) 
 
	#空行の削除(参考:http://id.fnshr.info/2017/08/14/r-blank-row-col/)
	#	is_blank の定義
	is_blank <- function(x) {is.na(x) | x == ""}
 
	# すべてが空欄である行を探す
	unnecessary_row <- apply(result, 1,
													 function(x){
														 all(is_blank(x))
													 })
 
	# 「すべてが空欄である行」以外を残す(=空行の除去)
	result <- result[!unnecessary_row,]
 
	#見出し行に名前を付与
	namae <- "member.1"
	for(k in 2:ncol(result)){
		namae <- append(namae, paste("member.", k))
	}
	colnames(result) <- namae
	result
}

( )の中の引数でグループ毎の人数を指定する。2人グループ(要するにペア)なら2を、3人グループなら3を入れる、といった感じで。

空行の削除は、以下の記事を参考とさせていただきました。

Rで空行・空列を除去する方法

人数がグループ数で割り切れない場合、余った人を各グループに1人ずつ割り当てるような仕様となっている。例えば30人で4人グループを作る場合、4人グループが5組と、5人グループが2組できる。これは自分が授業内で即興でグループを作るときのアルゴリズムに則っている。「いや自分なら4人グループ7組と2人ペア1組にする」という先生がいましたら、この関数はそういうのには対応していませんごめんなさい。

この仕様のせいで、思ったようなグループの人数にならないときがある。例えば40人で7人グループを作るとき、余った5人をできたグループに割り当てていくと、すべてのグループが8人になってしまう。これは余りの人数などで例外処理をしていけばいいのだろうけど、しんどいので今回は割愛。そもそも7人グループとか作ることなんて滅多にないと思う。

これをShinyアプリにするのが本当のねらいなのだけど、それはまた時間のあるときに。

順位相関係数の信頼区間の算出

何度もやってるのにどうも覚えられないのでここにまとめてメモ書き。

自分の研究は、質問紙などの順序尺度データだったり、正規性のないデータだったりを使うことが多いので、相関分析をする場合には必然的にピアソンの積率相関係数ではなく、順位相関係数を使うことが多い。

基本的にはスピアマンを使っているが、ケンドールが報告されているのをあまり見かけないのでいつかドヤ顔で使ってみたいという厨二心もある。

順位相関係数を出すだけならすぐにできる。Rだとこう(ダジャレではない)。

> cor(dat, method=”spearman”) #スピアマン

> cor(dat, method=”kendall”) #ケンドール

無相関検定とか信頼区間の算出をする場合はcor.test関数を使う(引数が2つ必要なことに注意)。

> cor.test(dat[,1],dat[,2],method=”spearman”)

Spearman’s rank correlation rho

data: dat[, 1] and dat[, 2]
S = 459.55, p-value = 0.001742
alternative hypothesis: true rho is not equal to 0
sample estimates:
rho
0.6544704

警告メッセージ:
cor.test.default(dat[, 1], dat[, 2], method = “spearman”) で:
タイのため正確な p 値を計算することができ

はいでてきt、あ、あれ?

調べてみるとcor.test関数では、ピアソンの積率相関の場合のみにしか信頼区間を出してくれないらしい。

http://www.inside-r.org/r-doc/stats/cor.test

次はこれを試してみた。corrgramパッケージのcorrgram関数。信頼区間が一気出しできるpanel.confオプションが便利。

https://cran.r-project.org/web/packages/corrgram/corrgram.pdf

だがここにも落とし穴。

結局は中でcor.testが動いているので、順位相関では信頼区間が出せないいうことだそうだ。

はてさて、困った。


【解決策1】

langtestを使う。スピアマンでもケンドールでも使える。一番簡単かつ手っ取り早い。

http://langtest.jp/shiny/cor/

【解決策2】

スピアマンの場合、DescToolsパッケージのSpearmanRho関数を使う。

https://cran.r-project.org/web/packages/DescTools/DescTools.pdf

1,2番目の引数には変数、3番めの引数では

> library(DescTools)
> SpearmanRho(dat[,1],dat[,2],conf.level=0.95)
rho lwr.ci ups.ci
0.6544704 0.2983596 0.8506335

この結果はlangtestの結果と一致する。

【解決策3】

これもスピアマンの場合。RVAideMemoireパッケージのspearman.ci関数を使う。

https://cran.r-project.org/web/packages/RVAideMemoire/RVAideMemoire.pdf

これは上の2つとは違い、スピアマン順位相関のブートストラップ信頼区間を出してくれる。

> library(RVAideMemoire)
*** Package RVAideMemoire v 0.9-52 ***

> spearman.ci(dat[,1], dat[,2], nrep=1000, conf.level=0.95)

Spearman’s rank correlation

data: dat[, 1] and dat[, 2]
1000 replicates

95 percent confidence interval:
0.2263722 0.9238737
sample estimates:
rho
0.6544704

【解決策4】

これはケンドールの場合のみ。NSM3パッケージのkendall.ci関数を使う。

https://cran.r-project.org/web/packages/NSM3/NSM3.pdf

どうもこの本の計算方法に基づいて信頼区間を算出するようだ。

> kendall.ci(dat[,1], dat[,2], alpha=0.05, bootstrap=F) #漸近解析を使う場合

1 – alpha = 0.95 two-sided CI for tau:
0.187, 0.867

> kendall.ci(dat[,1], dat[,2], alpha=0.05, bootstrap=T, B=1000) #ブートストラップを使う場合

1 – alpha = 0.95 two-sided CI for tau:
0.109, 0.838

ブートストラップを使用する場合は、Bの部分で抽出回数を指定する。

 

いろいろ種類があって、どれを使うのがいいかはよくわからないし、もう全部langtestでOKじゃなかろうかと思ったりもするが、手数は多いに越したことはないだろう。

【追記1】2016.03.13

このようなご指摘があったのでここで紹介させていただきます。

 

【追記2】2016.03.27

Nagoya.R #15にて、このブログの内容について発表しました。以下は発表スライドです。

【追記3】2016.03.27

スピアマンの順位相関係数の信頼区間について、以下のページをご紹介いただきました。

スピアマンの順位相関係数の信頼区間 – 裏 RjpWiki

cor.test関数とrank関数の組み合わせで算出した信頼区間と、ブートストラップで算出した信頼区間との間には大きな差はないようだ。

Nagoya.R #11,終わりました

こんばんは。

先日Nagoya.R #11が開催されました。

今回私は入門者講習を担当させていただき,なんとか無事(?)終えることができました。

拙い講習を優しく見守ってくださったオーディエンスの皆様ありがとうございました。

 

SlideShareに入門者講習にて使用したスライドを一部改変したものをアップしていますのでよろしければご覧ください。

このスライドの作成にあたって,天野修一先生,阪上辰也先生の以前の入門者講習の資料を参考とさせていただきました。この場をお借りして御礼申し上げます。

 

また,Ustreamにて入門者講習の中継(録画)が試聴できますので,こちらもよろしければご覧ください。
http://www.ustream.tv/recorded/41452159

 

これで今年(2013年)の発表が全て終了したことになります。

残すは来月上旬の修論の提出です。年末年始返上でがんばります。