StatsBeginner: 初学者の統計学習ノート

統計学およびR、Pythonでのプログラミングの勉強の過程をメモっていくノート。たまにMacの話題。

Rでよく忘れる、よく間違える書き方(随時追記)

よく忘れることのメモです。

  • NAかどうかの判定にはx==NAとかではなくis.na(x)を使う
  • 要素に含まれるかどうかの判定は、%in%かis.element()を使う。これはデータ全体の中から何かを抽出するときの条件を複数条件にしたい場面でも使えるときがある。(たとえば簡単なところでは、subset()でデータフレームから条件付の抽出をするとき、&で条件を並べなくてもよくなったりとか)
> is.element(3, c(1,2,3))
[1] TRUE
> 3 %in% c(1,2,3)
[1] TRUE
  • {dplyr}でデータフレームを操作した後、as.data.frame()で標準のデータフレームに戻してからじゃないと、別の関数に与えたときにエラーが出る場合がある
  • {data.table}のfread()関数でcsvとかを読み込んだ場合も、それを標準のデータフレームにしてから使わないとエラーが出ることがある
  • factor型のデータをnumericに変えると、factorの中身ではなくレベル(水準)番号が数字になる。
> x <- as.factor(c(1,10,100,1,10,100))
> as.numeric(x)
[1] 1 2 3 1 2 3
  • リストに要素をアペンドするとき、c()関数でできるのだが、付け加える方にlist()をかけとかないといけない
> x1 <- c(1,2,3)
> x2 <- c('a','b','c')
> l1 <- list(x1, x2)
> print(X)
[[1]]
[1] 1 2 3

[[2]]
[1] "a" "b" "c"

[[3]]
[1] "あ"

[[4]]
[1] "い"

[[5]]
[1] "う"

> x3 <- c('あ','い','う')
> l2 <- c(l1, x3)  # これはダメ
> print(l2)
[[1]]
[1] 1 2 3

[[2]]
[1] "a" "b" "c"

[[3]]
[1] "あ"

[[4]]
[1] "い"

[[5]]
[1] "う"

> l3 <- c(l1, list(x3))  # こうする
> print(l3)
[[1]]
[1] 1 2 3

[[2]]
[1] "a" "b" "c"

[[3]]
[1] "あ" "い" "う"
  • パネルデータをロング型にしたりワイド型にしたりするのには{tidyr}を使う。ワイドをロングにするのはgather()関数で、ロングをワイドにするのはspread()関数で。
  • ||とか&&は、or/and条件を入れ子にするときに使う。
  • ベクトルの要素が「全て◯◯という値である」という条件を書くシンプルな方法はたぶんない?最大と最小が一致するみたいな書き方をいつもしているのだが。
  • データを「中心化」(平均ゼロにする)したいときは、center()じゃなくて、scale()関数のオプションでscale=Fに設定する。変な話だが。
  • apply()の第一引数は小文字のxではなく大文字のX。まあ、書かなければいいともいえるが、書くときによく間違える。
  • logicalのベクトルでTRUEの個数を数えるには、length(x[x==TRUE])とかsum(x==TRUE)で数えられる。
  • 欠損値のない行にしぼりたいときは、d[complete.cases(d),]でOK。
  • plotで散布図の記号を文字(国の名前とか人の名前とか)にしたいなら、散布図の方は色を"white"にして消して、text(x, y, labels=)とすればよい。
  • 離散変数の値ごとのヒストグラムを得たいとき、hist(x)としてしまうと、離散値に対応するバーが目盛りの左側に来てしまう。これを回避するには、barplot(table(x))とすればよい。
  • 回帰係数の信頼区間の出し方をいつも忘れるが、confint(model, level=0.95)
  • 主成分分析の結果は符号が想定とは逆になってることがあり、必要ならマイナスをかけて戻すのを忘れないように
  • applyでFUNに第二引数以降をわたしたいときは、FUNの後ろにそのまま続けていけばよい。
d <- data.frame(
  A = c(1,2,3,4,5),
  B = c(2,4,NA,8,10),
  C = c(1,3,5,7,9)
  )
apply(d, MARGIN=1, FUN=mean, na.rm=T)
  • dplyrでパイプライン%>%を使うとき、関数定義から埋め込みたい場合は、%>% (functon(p){hoge}) %>%と、()でかこむ。
  • 意外と検索しても見つからないのだが、ggplot2で凡例が小さすぎて点線とか意味わからないのは、theme(legend.key.width=unit(2,"cm"))として解決。
  • dplyrのmutateで、複数の列に一気に同じ処理をしたいときは、mutate_at(var(hoge), funs(f(.)))とし、hogeのところにはstart_withとかが使えるし、ある変数以外を指定したいなら-をつければよい。
  • たまにRでエクセルのファイルを読みたい時は、今なら、gdataパッケージがいいのではないかと思う。
library(gdata)
df <- read.xls('ファイル名')
  • dplyrのなかで差分を取りたいときは、diffじゃなくてlagをつかって、mutate(x = x - lag(x))とする。
  • 正規表現でエスケープするとき、バックスラッシュ\は2回重ねないといけない。
  • dplyrで、少なくともselect、lead、lagは毎回"dplyr::"つけたほうがいい。
  • 空のデータフレームをつくるとき、matrixをas.data.frame()するのがよいが、これに1行目のデータを与えるときにrbindをつかってしまうと列名称が変わってしまうので、インデックスを指定して与えるようにする必要がある。
as.data.frame(matrix(c(NA,NA),nrow=1))
  • read.csv()するとき、stringsAsFactors = Fオプションをとにかく付けるように習慣づけないと、おもわぬエラーが起きる。
  • データフレームにscale()を適用すると、各列を標準化してくれるが、返り値がmatrixになってしまうので、たとえばlm関数のdata欄に直接与えることができない。すこしめんどうだが、numeric型の列を抽出し標準化してデータフレームに直す必要があるので、以下のような感じになる。

lm(y~x, data=d %>% select_if(is.numeric) %>% scale() %>% as.data.frame())

  • RStudioでggplot2を使っている時に、
Error in grid.Call(C_convert, x, as.integer(whatfrom), as.integer(whatto),  : 
  Viewport has zero dimension(s)

というようなエラーがでるときがあるが、コードが間違っているのではなく、plotが出るペインの掃除ボタン(ほうきのマーク)を押すと解消したりする。

  • dplyrでcomplete.cases()をやりたいときは、filter(complete.cases(.))とする。
  • AとBに挟まれた部分を取る正規表現
"(?<=A)(.*)(?=B)"
  • warningを消したい時、単にinvisible()をかければいいのではなくて、以下のようにcapture.output()を入れ子にする。
invisible(capture.output())
  • ggplot2で"Error in .Call.graphics(C_palette2, .Call(C_palette2, NULL)) : invalid graphics state"などよくわからないエラーがでたときは、とりあえずRStudioのplot欄を掃除する(clear all plots)
  • 特定のオブジェクトだけ残して自作のオブジェクトを全部消したいときは、
rm(list=ls()[which(ls() != 'hogehoge')])
  • forループの進捗を表示させたいとき、以下のような感じにすればよい。(1000周ごとに表示)
 if(i %% 1000 == 0) {message('\r', paste(i, ' / ', length(xxx)), appendLF=FALSE)}
  • glmでたとえばロジスティック回帰をやったとき、予測値は0,1ではなく0-1の少数の形で以下のコードで得られる。typeのところはデフォルトでは'link'になるが、これは線形予測子を得るもの。type='response'にしておくと、リンク関数を経たものが得られる。
predict(model, type='response')
predict(model, type='response')
  • lmとかglmオブジェクトから、「投入したデータフレーム」は$modelで取り出せる。stepしている場合は、最終的に選択されたモデルのデータフレームが取り出せる。で、ポイントとしては、目的変数が必ず1列目に来るようになっていることと、NAはオミットされてcomplete.casesになっているということ。predict関数を使うときに(newdataに与えるので)覚えておくと便利。
  • 重み付き最小二乗法をやるときはlm(weights=)という引数をつけるが、predictで予測値を出すときは、predictの中にweightsとか書かなくてもよい。lmオブジェクトの$model内の最後に(weights)っていう列ができててそれが勝手に考慮される。predict内にweightsって書いても無視されてるっぽい(変な値を与えても影響がない)。
  • 自作関数の引数でデータフレームの列を指定したい場合に、関数内でデータフレームをattach()して以下のようにすればよいという意見をツイッターでみた。私は、変数名はdata[,'var']と文字列型で指定するようにしているが。
get_hist <- function(data, var) {
  attach(data)
  hist(var)
  detach(data)
}
  • 文字列のベクトルを連結して1つの文字列にしたいときは、sep=ではなくcollapse = を使う。そうしないと、ベクトルを与えると要素を別々に扱ってベクトルを返そうとする。
  • 行列やベクトルの掛け算をするとき、*を使うと、線形代数的な積ではなく、要素同士の掛け算になる。挙動は以下のとおり。
> # 2×6の行列の場合
> mt1 <- matrix(c(1,3,5,6,2,3), ncol=3, byrow=F)
> vec1 <- c(10,100)
> vec2 <- c(10,100,1000)
> 
> mt1*vec1     # vec1の次元がmt1の行数と一致するので各行をvec2の要素倍する
     [,1] [,2] [,3]
[1,]   10   50   20
[2,]  300  600  300
> mt1*vec2     # vec2の次元がmt1の列数と一致するので各列をvec2の要素倍する
     [,1] [,2] [,3]
[1,]   10 5000  200
[2,]  300   60 3000
> mt1 %*% vec2 # vec2は縦ベクトルとして扱われ、積を計算する
     [,1]
[1,] 2510
[2,] 3630
> mt1 %*% vec1 # vec1の次元がmt1の列数に一致しないので計算できない
Error in mt1 %*% vec1 : non-conformable arguments
> 
> # 3×3の正方行列の場合
> mt2 <- matrix(c(1,3,5,6,2,3,7,7,8), ncol=3, byrow=F)
> mt2*vec2     # 行数とも列数とも一致するが基本的に縦扱いなので、各行をvec2の要素倍する
     [,1] [,2] [,3]
[1,]   10   60   70
[2,]  300  200  700
[3,] 5000 3000 8000
> mt2*t(vec2)  # 転置しても各列を要素倍するようになってくれるわけではなくエラーに
Error in mt2 * t(vec2) : non-conformable arrays
> t(t(mt2)*vec2)  # こうすると各列を要素倍してくれたことになる
     [,1] [,2] [,3]
[1,]   10  600 7000
[2,]   30  200 7000
[3,]   50  300 8000
> 
> # 行列同士をかける場合
> mt3 <- matrix(c(1,3,5,6), ncol=2, byrow=F)
> mt4 <- matrix(c(3,7,7,8), ncol=2, byrow=F)
> 
> mt3*mt4   # これは各要素同士の積
     [,1] [,2]
[1,]    3   35
[2,]   21   48
> mt3%*%mt4  # これは行列の積
     [,1] [,2]
[1,]   38   47
[2,]   51   69
  • 「Error: vector memory exhausted (limit reached?)」というメモリが足りないエラーは、RStudioの設定が問題になっている可能性がある(参考リンク)(参考ついったー
  • たくさんのデータフレームをlistでつないであって、それを全部一気にrbindしたいときの方法がこのページに載っていて参考になる。以下のどちらの書き方でも速い。
single.df <- bind_rows(list.of.dfs)  # これはdplyrの関数
single.df <- do.call("rbind", list.of.dfs)
  • 1列しかないデータフレームについて、行番号で抽出を行うと、単なるベクトルになってしまう。
> d <- data.frame(Term=c('春','夏','秋','冬'))
> class(d)
[1] "data.frame"
> class(d[1:2,])
[1] "character"
  • dplyrでの昇順・降順のソートはまじでクソ覚えにくい。昇順ならarrange(col)で、降順の場合はarrange(desc(col))
  • dplyrで「行の合計」に基づいてフィルターしたい場合はrowSums(.)を使えば良い。
df <- data.frame(x1=c(1,2,3),x2=c(2,3,4),x3=c(1,2,4))
df %>% filter(rowSums(.)>=7)
df %>% filter(rowSums(.)==7)
  • dplyrのgroup_byで複数のカラムを設定し、summariseすると、以下のよう謎のメッセージが出るのだが、あまり気にしなくていいようだ。summariseすると「最後に設定したカラムでのグループ化」が解除されるという仕様になっている(参考1参考2)。この警告自体は、意図どおりに2つのカラムでグループ化&サマライズできなかったという意味ではなく、グループ化が1個解除されてこうなりましたという意味かな。
`summarise()` has grouped output by 'xxxxx'. You can override using the `.groups` argument.
  • 行列の列を-インデックスで除いた場合、除いた結果が1列になる場合は行列型ではなく単なるベクトルになり、結果が0列になる(全部消える)が場合は行列のままとなる。前者に注意が必要で、1列になることもある処理があるときに、行列に対するコードを適用してるとエラーになる。
y1 <- cbind(c(1,2,3,4,5), c(6,7,8,9,10))
y2 <- y1[,-2]
class(y2)
y3 <- y1[,-c(1,2)]
class(y3)
  • リストの要素にインデックスでアクセスするときはlist1iとやるわけだが、ここにベクトルを与えると、複数の要素を取ってくるのではなく、再帰的なアクセスになる。どういうことかというと、list1c(1,2)となっている場合、list1の1つ目と2つ目の要素を取るのではなく、「1つ目の要素の中の2つ目の要素」を取りに行く。仮にlist11が行列だった場合、2個目の値ということで、その行列の1列目の2行目の値を取りに行く。list1の1つ目の要素と2つ目の要素を取りたい場合は、[1:2]と一重カッコにする(ややこしい!)。そもそも、リストの要素にアクセスするときにiとしているのは、Rのリストは中身の要素がリスト型でくるまれている(だからc()で追加するときに追加する要素をlist()する)からで、[i]だと返り値はリストになる。list1[1][1]とかにしてもムダで、list1[1]とlist[1][1][1][1][1][1]は同じ結果になる。list11とすることにより、アクセスできる。
> list1 <- list(matrix(c(1,2,3,4), nrow=2, byrow=T), 
+               matrix(c(5,6,7,8), nrow=2, byrow=T))
> list1[[1]]
     [,1] [,2]
[1,]    1    2
[2,]    3    4
> list1[[2]]
     [,1] [,2]
[1,]    5    6
[2,]    7    8
> list1[[c(1,2)]]
[1] 3
> list1[[1:2]]
[1] 3
> list1[1:2]
[[1]]
     [,1] [,2]
[1,]    1    2
[2,]    3    4

[[2]]
     [,1] [,2]
[1,]    5    6
[2,]    7    8
  • 0を0で割るとNaNになり、0以外の数字を0で割るとInfか-Infになる。これを忘れてると、たとえば「0で割る」ことになってしまうことがあり得ることを想定して、該当箇所を何かでreplaceするという処理をするときに、NaNとInfを両方探さないといけないのを忘れることになる。
>   0/0
[1] NaN
>   1/0
[1] Inf
>   -1/0
[1] -Inf
  • csvの文字コードを変換したいとき、read.csvで読み込む際はファイルに合わせてfileEncoding='CP932'とか指定し、write.csvするときにエンコーディングを何も指定せずにやると、綺麗にUTF-8に変換される。
  • Rの正規表現でURLを抽出する方法は以下のとおり。perlをTRUEにするのを忘れないように。
grep('https?://[\\w!\\?/\\+\\-_~=;\\.,\\*&@#\\$%\\(\\)\'\\[\\]]+', x, perl=TRUE)
  • 正規表現で「AAAを含み、かつBBBを含み、かつCCCを含む」(AND条件)を表現する方法は以下の通り。肯定先読みを使う。
grep('^(?=.*AAA)(?=.*BBB)(?=.*CCC).*$', text_all, perl = T)
  • 正規表現で「AAAを含み、かつBBBを含まない」は否定先読みを使う。
grep('^(?=.*AAA)(?!=.*BBB).*$', text_all, perl = T)
  • whichをつかって「◯◯であるものを除く」という絞り込みをするとき、whichでヒットするものが1つもない場合、全部の要素が残ってくれるのではなく、全部消えてしまう。なので、1つもない可能性が少しでもあるなら、「◯◯でないものを残す」ように書かないとダメ。
> x <- c('あ','い','う')
> x[which(x != '')]
[1] "あ" "い" "う"
> x[-which(x == '')]
character(0)

[メモ]Mac版のRでパッケージのインストールに失敗(X Codeのアプデが必要だった)

さっきハマったエラーを解決したので、備忘のためのメモです。
RStudioとRの両方で試したのですが、{panelvar}というパッケージをインストールしようとしたら、依存パッケージのコンパイルのエラーがでて進めなくなりました。
最初、Rの古いバージョンでやってたら{progress}というパッケージで躓いたんですが、Rを最新版にアプデしてからやると今度は{vctrs}というパッケージがインストールできてませんでした。
{vctrs}だけをインストールしようとしてもエラーが出る。

ERROR: compilation failed for package ‘vctrs’
* removing ‘/Library/Frameworks/R.framework/Versions/3.6/Resources/library/vctrs’
Warning in install.packages :
  installation of package ‘vctrs’ had non-zero exit status

The downloaded source packages are in
	‘/private/var/folders/7y/j9v534hs3hb971070xnz91l80000gp/T/Rtmp9EalBG/downloaded_packages’
Error: package or namespace load failed for ‘panelvar’:
 .onLoad failed in loadNamespace() for 'pillar', details:
  call: utils::packageVersion("vctrs")
  error: there is no package called ‘vctrs’
* installing *source* package ‘vctrs’ ...
** package ‘vctrs’ successfully unpacked and MD5 sums checked
** using staged installation
** libs
clang -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG   -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -I/usr/local/include  -fPIC  -Wall -g -O2  -c arg-counter.c -o arg-counter.o
clang: warning: no such sysroot directory: '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk' [-Wmissing-sysroot]
In file included from arg-counter.c:1:
In file included from ./vctrs.h:2:
/Library/Frameworks/R.framework/Resources/include/R.h:55:11: fatal error: 'stdlib.h' file not found
# include <stdlib.h> /* Not used by R itself, but widely assumed in packages */
          ^~~~~~~~~~
1 error generated.
make: *** [arg-counter.o] Error 1
ERROR: compilation failed for package ‘vctrs’
* removing ‘/Library/Frameworks/R.framework/Versions/3.6/Resources/library/vctrs’
Warning in install.packages :
  installation of package ‘vctrs’ had non-zero exit status

The downloaded source packages are in
	‘/private/var/folders/7y/j9v534hs3hb971070xnz91l80000gp/T/Rtmp9EalBG/downloaded_packages’


これは、こないだのMac OSのアプデ時に、X Code最新化(コマンドラインツールのインストール)しておくべきだったのが原因のようです。
下記のサイトで2段階の解決方法が紹介されてますが、私は1段階目の"xcode-select"で治りました。
_cgo_export.c:3:10: fatal error: &#39;stdlib.h&#39; file not found の解決方法 - Qiita

Macで画像ファイルをまとめてPDF化する(ただし名前順にソート)

Macで画像ファイルをまとめてPDFにしたいとき、従来はAutomatorを使ってワークフローを組んでいました。
ところが、いつからか知らないですが、OSに標準でそういう機能が付けられていたようです。
ついさっき、ある人から、とある論文のPDF入手を頼まれたのですが、諸事情により画像ファイルでしか閲覧できないので、これをPDF化しようとしていて気づきました。


f:id:midnightseminar:20191119120648p:plain


上のように、ファインダーで複数の画像を選択すると、右下のところに(これはサービスというやつですが)「PDFを作成」というボタンがあって、これを押すと選択した画像をまとめたPDFがそのフォルダに作成されます。


これは神!と思ったのですが、どうも、ファインダーで選択した順番にPDFに入っていくようです。
個人的には、どちらかといえば「選択したやつ全部を名前の順にソートしてPDF化」あるいは「フォルダ内の画像を名前順にまとめてPDF化」したい場合が多いので、やっぱりAutomatorで組んでおくことにしました。
作業としては2分ぐらいで終わります。


まずAutomatorを開いて新規作成で「クイックアクション」を選択。これはOS内で「サービス」と呼ばれる機能を提供するものです。


f:id:midnightseminar:20191119121220p:plain


次に、ワークフローの画面の一番上にあるところは(右の上)では、「ワークフローが受け取る現在の項目」は「ファイルまたはフォルダ」にしておき、「検索対象」は「Finder.app」を選んでおきます。
その上で、左の処理一覧から、処理したい項目を次のように選びます(右のワークフロー欄にドラッグする)。

  1. 「ファイルとフォルダ」から「選択されたFinder項目を取得」を選択
  2. 「ファイルとフォルダ」から「Finder項目にフィルタを適用」を選択し、「種類」が「イメージ」であるという条件を設定
  3. 「ファイルとフォルダ」から「Finder項目を並べ替える」を選択し、「名前」の「昇順」でソートするようにしておく
  4. 「PDF」から「イメージから新規PDFを作成」」を選択し、保存先は適当に決めておいて、出力するときの名前も決める。サイズは「ページをサイズに合わせる」にしておけば、勝手に画像が圧縮されたりしなくていいと思います。


f:id:midnightseminar:20191119121922p:plain


これだけやって保存しておけば、ファインダーで画像を選択したときに、さきほどの「PDFを作成」の隣にある「その他」の中にメニューが出てきますし、あるいは画像を選択した状態で右クリックして「サービス」から選択することもできます。


f:id:midnightseminar:20191119122405p:plain
f:id:midnightseminar:20191119122423p:plain


なお、サービスに追加したワークフローは、"~/Library/Services"という場所に入っていて、名前を変えたいときはここでファイル名を変えればいいようです。
また、フォルダを選択してフォルダ内の画像をまとめたい場合は、ワークフローのパーツとして「フォルダの内容を取得」ってのを使えばいいです。

言語学への関心は衰退している?

とある雑誌の連載記事に、

言葉というものは曖昧かつ不安定で捉えにくい対象であることもあって、とりわけ現代思想ブームが終焉し実証的社会科学が隆盛を極めているここ三十年ほどの間は、言語理論への関心は総じて低調であったと言える。「言語論的転回」は今や、むしろ逆転の渦中にあるとみたほうがよいのかも知れない。


というようなことをあまりよく考えずにさらっと書いてしまったのですが、本当に低調であると言えるのかどうか不安になったので、Google Ngram Viewer(特定のキーワードが19世紀以降の英語の書籍にどれぐらい頻繁に登場してるかを教えてくれるやつ)で確認してみました。


【言語学】
f:id:midnightseminar:20191006190050p:plain


30年というよりは40年ぐらいかけて下落していっていますが、日本における現代思想ブームは欧米から10年ぐらい遅れていたイメージがあるので、大きく間違ってはいなかったと安心することにしました。
構造主義〜ポスト構造主義(ポストモダニズム)の時代は、人文学全般が非常に盛んで、あの時代が終わると「哲学」や「思想」とかいうもの全般に対する関心が薄れていきましたよね。まぁ私は80年代生まれなのでリアルタイムでは知りませんが。
関連しそうな用語も調べてみました。(なお、言語学や心理学の盛衰に関しては、現代思想ブームと並行して起こった、50-70年代のいわゆる「認知革命」というムーブメントも関係してると思います。)


【意味論】
f:id:midnightseminar:20191006190841p:plain


【記号論】
f:id:midnightseminar:20191006190856p:plain


【哲学】
f:id:midnightseminar:20191006190911p:plain


哲学(philosophy)はとくに人文学の議論でなくても用いられる用語なので、あまり現代思想ブームとは関係なかったかもしれません。


【人文学】
f:id:midnightseminar:20191006191153p:plain


「人文学」は90年代ごろから下落が始まるようです。


【構造主義】
f:id:midnightseminar:20191006191253p:plain


「構造主義」も意外とピークは90年代だったようです。


【人類学】
f:id:midnightseminar:20191006191237p:plain


【心理学】
f:id:midnightseminar:20191006191342p:plain


「心理学」は、ずいぶん昔にも山がありますが、これは行動主義の趨勢に引っ張られてるんですかね?
30年代ごろはパブロフとワトソン、50年ごろはスキナーの時代という感じですね。
「行動主義」も検索してみました。


【行動主義】
f:id:midnightseminar:20191006191915p:plain


【社会学】
f:id:midnightseminar:20191006191937p:plain


社会学は、ルーマンやパーソンズのような大物理論化がいた時代にピークがありますね。


人文学とは言わないと思いますが(19世紀には人文学と社会科学の区別がなかったので両者は似たようなものだったわけですが)、政治学と経済学も見てみました。


【経済学】
f:id:midnightseminar:20191006192201p:plain


【政治学】
f:id:midnightseminar:20191006192319p:plain


なんとなく、文系全体が衰退してるような感じがしますねw


しかし途中で気づいたのですが、「数学」とか「物理学」とか「統計学」とかを入力しても90年代から2000年代にかけて衰退しているので、アカデミックなワード自体が割合としては減っていくような、サンプルの性質が何かあるのかもですね。(もちろん、たとえばstatisticsなんかはとくに、アカデミックな話で使われるとも限りませんが。)


【数学】
f:id:midnightseminar:20191006192953p:plain


【物理学】
f:id:midnightseminar:20191006193010p:plain


【統計学】
f:id:midnightseminar:20191006193124p:plain

メモ:Rのts型のインデックス(年・四半期・月情報)を文字列として取り出す

Rのts型(時系列型)のデータについているインデックス("1980 Q1"みたいな)を、文字列情報として取り出す方法が、ぱっとググって分からなかったのですが、とりあえず以下のようにしたらできました。

> library(vars)
> data(Canada)
> 
> t <- as.yearqtr(index(Canada))
> head(t)
[1] "1980 Q1" "1980 Q2" "1980 Q3"
[4] "1980 Q4" "1981 Q1" "1981 Q2"
> class(t)
[1] "yearqtr"
> 
> t <- as.character(t)
> head(t)
[1] "1980 Q1" "1980 Q2" "1980 Q3"
[4] "1980 Q4" "1981 Q1" "1981 Q2"
> class(t)
[1] "character"


たぶん、元データが四半期ではなく月単位のデータだったら、yearqtrの部分をyearmonにするのだと思います。

なぜ「p < .05」で「統計的に有意」なのか?――5%基準の由来について

 以前も書いたんですが、p値が0.05を下回るかどうかにとらわれる慣習を問題視する人が最近は増えてきていて、たしかにその理由はよく理解できる一方で、p値が過剰にバッシングされている気もします。しかしそんなことより、個人的には、なぜ統計的有意性の判定基準が多くの分野で慣例的に0.05(5%)になっているのかという、その由来のほうが気になります。


 帰無仮説が正しいときにそれを棄却してしまう(第一種の過誤と呼ばれる)危険率が5%未満であれば「統計的に有意」と言われるわけですけど、この5%という閾値に客観的な必然性がないことは誰でも分かりますね。しかし実際には様々な分野で、5%基準で検定結果を報告(あわせて1%基準や10%基準での有意性も報告されたりはする)している研究が多数存在するわけです。


 この5%という基準の由来について、フィッシャーが「20年に1回ぐらいは間違っても研究者として許されるだろ」と発言したのが始まりであるという説をよく聞きます。フィッシャーは植物学者なので実験を1年に1回というペースでしか行うことができず、「20回に1回(20年に1回)ぐらいは間違った結論を出しても許してほしいよな!」と言ったという話です。
 ただ、これは単なる都市伝説だったようです。


 「5%基準」の由来を調べた論文を以前読んだのですが、
 On the Origins of the .05 Level of Statistical Significance


 アブストラクトを適当に訳しておくと、

フィッシャーの『Statistical Methods for Research Workers』よりも昔の、統計や確率に関する文献を調査すると、確かに統計的有意性に関する"5%"基準を正式に唱えたのはフィッシャーが最初であることは確かなのだが、この考え方自体はもっと昔に遡ることが分かる。偶然性の仮説を棄却するための習慣的な基準は、世紀の変わり目ぐらいから徐々に形成されていった。統計的有意性に関する初期の言及は、「確率誤差」の観点から行われている。これら初期の習慣が、フィッシャーによって採用され言及されたのである。


 この論文によると、昔は統計的有意性の判断基準として「確率誤差(ここに解説があった。)3つ分」という基準がよく使われていたらしく、これは正規分布なら「標準偏差2つ分」ぐらいに相当し、だいたい95%ぐらいになる。これが「5%基準」の由来のようです。
 つまり、確率誤差3つ分(とか標準偏差2つ分)であれば計算しやすいというか、扱いやすいので、そのへんを基準にしてものを考える習慣が5%基準に転じたのであるということのようです。

Macでひらがな・カタカナの濁点・半濁点が分離してしまったのを元に戻すスクリプト

昨日のエントリで、テキストエディタの「CotEditor」のスクリプト機能の使い方を書きました。その機能をつかって、濁点・半濁点が分離してしまったテキストを元に戻すツールを作ります。


こういうやつをなんとかしたいわけです。
f:id:midnightseminar:20190816235923p:plain



原因がよくわからないし、悩まされているのは私だけなのかも知れないのですが、Macを使っていると、PDF上から文字をコピペしたときに、濁音・半濁音のひらがな・カタカナが、1文字ではなく清音+濁点or半濁点という2文字に分離してしまう現象があります。


たとえば、Wordで以下のように入力します。ここの「ぶ」は普通の「ぶ」1文字です。
f:id:midnightseminar:20190817000024p:plain


これを、PDFで保存して、PDF上の文字列をコピーします。
f:id:midnightseminar:20190817000103p:plain


そして、たとえばエクセルに貼り付けます。比較のために、Wordからコピーした分も貼り付けてあります。
f:id:midnightseminar:20190817000119p:plain


このように、「ぶ」が「ふ」と「゛」に分かれてしまいました。
これは困るので、テキストファイル上にペーストした上で、CotEditorのスクリプトで置換できるようにしておきます。


具体的には、スクリプトは以下のように書きました。
なんかもっと美しい書き方があるような気がしてならないのですが、私にはわからないので、濁音・半濁音を全部並べることにしました。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# %%%{CotEditorXInput=AllText}%%%
# %%%{CotEditorXOutput=ReplaceAllText}%%%

import sys
import re

kana_before = ["が","ぎ","ぐ","げ","ご","ざ","じ","ず","ぜ","ぞ","だ","ぢ","づ","で","ど","ば","び","ぶ","べ","ぼ","ぱ","ぴ","ぷ","ぺ","ぽ","ガ","ギ","グ","ゲ","ゴ","ザ","ジ","ズ","ゼ","ゾ","ダ","ヂ","ヅ","デ","ド","バ","ビ","ブ","ベ","ボ","パ","ピ","プ","ペ","ポ"]

kana_after = ["が","ぎ","ぐ","げ","ご","ざ","じ","ず","ぜ","ぞ","だ","ぢ","づ","で","ど","ば","び","ぶ","べ","ぼ","ぱ","ぴ","ぷ","ぺ","ぽ","ガ","ギ","グ","ゲ","ゴ","ザ","ジ","ズ","ゼ","ゾ","ダ","ヂ","ヅ","デ","ド","バ","ビ","ブ","ベ","ボ","パ","ピ","プ","ペ","ポ"]

# 標準入力でテキストをまるごと受け取る
all_text = sys.stdin.read()

# 1個1個置き換えていく
for i in range(len(kana_before)):
	all_text = re.sub(kana_before[i], kana_after[i], all_text)

sys.stdout.write(all_text)


スクリプトの冒頭ですが、1行目はPythonインタープリタの置き場。
2行目は文字コードの宣言で、これを書いてないとエラーが出ました。(私はテキストファイルは基本的にUTF-8でしか使わないので、utf-8と書いておいた。)
3行目は、テキストファイル内の文字を全部取るという意味です。これが標準入力経由でPythonに渡ります。
4行目は、テキストファイル内の文字を全部置換するという意味です。標準出力経由でPythonからCotEditorに渡される文字列に置き換わります。


今回はとくにショートカットは指定しないことにしました。つまりスクリプトは、単に「dakuten.py」という名前で、CotEditorのスクリプトフォルダに入れてあります。
するとこのように、ショートカットキー無しで、一覧から選択する形で実行できるようになります。
f:id:midnightseminar:20190816234554p:plain


実際やってみたら、無事置き換わってくれました。