タグ別アーカイブ: 分析

Rmarkdownからファイル生成するときに日付を入れたい

はじめに

タイトルのとおりです。Rmarkdownをknitしたとき,ファイル名に日付を入れたい場合にどうするかというお話。自分用メモです。

関連した話

ファイルの中身の日付は,YAMLヘッダーをいじることで対応可能です。

参考:自動で日付を変更する R markdown tips https://qiita.com/masato-terai/items/50afd48ad741aa8b7bb6

今回は,knitした際に生成されたWordやHTMLのファイルに日付をいれたいので,上記の話とはちょっと違います。

方法

私が調べた感じだと,YAMLヘッダーの指定でファイル名に日付をいれるのは無理そうでした(ChatGPTはいけるって感じで説明してきましたが,そのやり方でやってもだめでした)。そこで,rmarkdown::render関数の中のoutput_fileの引数で明示的に日付を指定してあげるという方法をとります。下記のような感じです。

指定するのは,

  • レンダリングするRmdファイル
  • アウトプットされるファイル名にいれる文字列
  • 拡張子

の3つのみです。2つ目のファイル名の部分に,”Sys.Date()”をいれて,paste0()でくっつけることで,最終的なファイルが上の例だと”Experiment1_2024-04-26.html”のようになります。knitボタンを使う代わりに上のコードを実行すると,ファイルが生成されます。

もちろん,YAMLヘッダー上で,”output:html”の指定は必要ですし,wordにするならwordにしないといけません。その部分の指定と,ファイル名の拡張子の指定が一致していないとおかしなことになると思います。

ちなみに,上のコード部分のRコードチャンクに”include=F, eval=F”等の指定をしてあげないと,最終的に出力されるファイルのなかにコードが残るので注意が必要です。

おわりに

Rmarkdownからknitすると,基本的にファイル名=Rmarkdownのファイル名で,生成されたファイルのファイル名を自分で変えないと,基本的には上書きされてしまいます。よって,ログを残す意味でも日付を入れたいよねというのが動機でした。もちろん,同日内で何度もレンダリングすれば同じ日付で上書きされてしまいますので,その場合はSys.Date()ではなくSys.time()にする必要はあります。

以上,メモでした。

なにをゆう たむらゆう。

おしまい。

[R] 1列だけの選択ならselect関数よりpull関数を使う

はじめに

dplyr使いの方で,select関数を使って特定の1列に対して何かしらの処理をするということをしたいときにエラーが出る人はpull関数を使いましょうという話です。ちなみに,$使えば問題は解決です。今回は,それ以外の方法で,というお話。

具体的になにをしようとしたか

私がどんな処理をしようとしたかについて少し触れておきます。ここはスキップしてもらっても構いません。

ある列の単語(1単語または2単語の英単語が入っている)の文字数をカウントするということをやろうとしていました。ピリオドが含まれていたり(e.g., “dogs.”),2語の場合は間に空白もあるので(e.g., “beautiful lake”,それらを除去して文字数を数える必要があります。そのためには,str_extract,str_replace, str_lengthなどの文字列処理関数を使う必要があります。しかし,これらの関数はベクトルを受け取って処理をするので,データフレームを渡してもエラーが出てしまうという問題に直面しました。

select関数の挙動

データフレームからある特定の列を引っ張ってくるというとき,もちろん$を使って,dat$wordのようにするのが一番簡単なのでそれでもいいのですけども,dplyr使いの方はselect関数を使っている方も多いのではと思います。ただし,select関数はデータフレームの中から特定の列を引っ張ってくると,それがたとえ1列であってもdata.frame型になります。

よって,処理に使う関数がベクトル型を要求するものだとエラーが発生することになるわけです。しかもやっかいなのは,「じゃあas.vector()関数」を噛ませればいいやんとやってみてもそれでは解決しないからです。理由はよくわかりません。

  dat %>% 
  select(word) %>% #wordという列に文字数カウントしたい文字列があるとする
  as.vector() %>%
  is.vector() #このコードではFALSEとなります

pull関数がすること

pull関数は,要するにdat$x1のように$を使って,またはdat[, x1]のように[,]を使ってデータフレームの中の特定の列を指定するのと同じ挙動をするということです(参考)。よって,pull関数の出力はベクトル型になります。

  dat %>% 
  pull(word) %>%
  is.vector() #このコードではTRUEとなります

というわけで,1列だけ持ってくるときに関数を使う場合はpull()関数を使いましょうというのが結論です。私は結局こういう感じで文字数カウントをしました。

  dat %>% 
  pull(word) %>%
  str_extract(.,"[^\\.]+") %>% #ピリオドを除去
  str_replace(.,pattern = "\\s",replacement = "") %>% #半角スペースを除去
  str_length()->rt_dat$length #文字数をカウント

$を使うと次のようになります。

  str_extract(dat$word,"[^\\.]+") %>% #ピリオドを除去
  str_replace(.,pattern = "\\s",replacement = "") %>% #半角スペースを除去
  str_length()-> dat$length #文字数をカウントしてlengthという列に入れる

$を使ったほうが行数が少なくなるので,そっちのほうがいいような気もしますが,工程の見やすさでいうとpull関数を使うほうが上かなという感じがします。

おわりに

もともと文字数はカウントしてあったのですが,ちょっと査読者の指摘でフィラー項目も入れて分析をやり直さないといけなくなってこういった処理が必要になりました。データ型って基本といえば基本なのですが,以外に気づかずにエラーで困ることもあるので,select関数の挙動について勉強になるいい機会でした。

ということで,pull関数とselect関数,場合によって使い分けましょう。

なにをゆう たむらゆう。

おしまい。

vlookup関数で参照先が複数ある時

春学期の成績つける際に書いてあって放置してあった完全に自分用メモです。

成績をつける際に,vlookup関数で名前やIDを参照するというのはよくある作業だと思います。vlookup関数の引数の基本は以下の通り。

vlookup(参照元,範囲,引っ張ってくる列,参照方法)

で,名前の列が1列ならこれだけでいいのですが,スピーキング授業の話の記事で紹介したようにペアでスピーキングテストなんかをやると,得点の列は1列で,名前の列が2列になります。最終的な成績が入るExcelシートでは名前は1列で,vlookup関数は指定範囲の1列目から名前を探してくることになりますから,2列目にある名前は参照されません。そして,誰が1列目で誰が2列目かはわからない状態なので,人によって参照範囲を変えることもできません。そこで使うのがIFERROR関数です。

IFERROR関数は,1つ目の引数でエラーが出た場合に2つ目の引数を実行するという関数です。つまり,この関数の1つ目でペアの1列目から始まる範囲を指定し,2つ目の関数でペアの2列目から始まる範囲を指定すれば解決するというわけです。意外に簡単でした。つまり,

IFERROR(VLOOKUP(名前セル, 参照先1, 引っ張ってくる列, 参照方法), VLOOKUP(名前セル, 参照先2, 引っ張ってくる列, 参照方法))

とすれば良いことになります。参照先1では2列あるペア列の1列目が先頭列になるように指定し,参照先2では2列目が先頭列になるように1列参照列を右側にずらします。そして,引っ張ってくる列も1列ずらして指定します。こうすることで,1列目の中から名前を探して点数を引っ張ってきて,もしここでエラーが出る(つまり1列目に名前がない)場合には2列目の中から名前を探して対応する点数を引っ張ってくることになります。このやり方を応用すれば,ペアだけではなく3人や4人といったグループの場合でも同じことができます。もちろん,Rとかで縦横変換して名前の列はすべて1列にまとめるようなことをしても最終的に名前が1列,点数で1列という形のデータを得ることはできるのですが。今回はEXCEL上で完結させる場合の話でした。

なにをゆう たむらゆう。

おしまい。

 

Slackを用いた授業外ライティング活動の便利ワザ[Google Spreadsheet編③]

はじめに

下記の2つの記事の続きで,おまけ的なものですが自分の備忘録のためにも残しておきます(R編がなかなかスタートしないw)。

Slackを用いた授業外ライティング活動の便利ワザ [Google Spreadsheet編①]

Slackを用いた授業外ライティング活動の便利ワザ[Google Spreadsheet編②]

簡単に何をやっているのかをまとめます。Slack上で授業外ライティング活動をさせ,そこで書かれたものをGoogle Apps Scriptを使ってGoogle Spreadsheetに記録し,そこで個人の1週間あたりの産出語数を学生と共有するということをやっています。大まかな枠組みについては,上記の記事でカバーされていますが,今回は,「ちょっとかゆいところに手が届くといいな」くらいのお話です。

問題の所在

https://twitter.com/tam07pb915/status/1118157873219948545

学生の書いたものを読んでいると,カンマやピリオドの後に半角スペースを入れないで書いているものが頻繁にありました。

Yesterday,I went to the zoo with my family.After that,we went to an Italian restaurant.It was delicious.

みたいな感じのものを想像していただければいいかなと思います。見る人が見たら気持ち悪くてたまらないと思うのですが,おそらくデジタル環境で英語を書くという経験の少なさからこのような英文になってしまうのだと思います。もちろん,タイポのようなことはありうるのですが,それでも一つの投稿で頻発していたり,ある特定の学習者が連続して誤りを犯しているとどうもこれは半角スペースを入れることを知らないのではないか?と考えるようになりました。

手書きでスペースをあける行為と,キーボードやスマートフォン上でスペースバーを押したり,フリック入力時に「空白」と書かれた部分をタップしたりという行為が関連付けられていないのかもしれません。また,日本語では句読点の後にスペースを入れるというルールはありません。

だからといって,彼らの今後の英語使用場面として手書き以外で英語を書くことがないと想定することはできませんし、スペース入れるということも身につけて欲しい(そうじゃない文見たときの気持ち悪さもわかって欲しい)ことではあるのでしつこく言っていかないといけない気がしています。もちろん,気づいたときにはメインのチャンネルにも共有する形でスペースを入れるようにコメントを出してもいます。ただ,そういうことよりもむしろ「リアルなコミュニケーション」の道具として英語を使って教員ともやりとりしてほしいというところもありますので,あまり半角スペース警察にはなりたくありません。

また,授業運営上でも問題はあります。それは,語数のカウントです。語数のカウントは,1語ずつを単語だと認識して数え上げているわけではなく,単語と単語の間に生まれるスペースを基準にして数えています(詳細は上記の過去記事か,「エクセル 単語数える」とかでググって見てください)。つまり,”Yesterday, I”は2語と認識されても,”Yesterday,I”は1語になってしまうというわけです。ピリオドのあとに半角スペースがなく次の文が始まる場合も同様です。私は,「1週間で○○語を書き込むこと」を課題としていますので,あまりにもこのミスが多いと語数のカウントが通常より少なく計算されてしまいます。

解決方法

私が考えつく解決方法は以下のとおりです。一番土方っぽいものから順に,

  1. Googlespreadsheetの書き込みを1セルずつ確認して,ピリオドやカンマのあとにスペースがなければ手作業で足す
  2. Googlespreadsheetの「検索と置換」でピリオドやカンマを探し,ヒットしたものを目視で確認して半角スペースがなければ足す
  3. Googlespreadsheetの「検索と置換」で正規表現を使ってピリオドやカンマのあとにスペースがないものを一括で修正する
  4. Googlespreadsheetでsubstitute関数を使って置換する

1や2はありえないとして,3も問題があります。それは定期的に作業をしないといけないという点です。Googlespreadsheetを使う利点は,一度作業をしたらしばらくの間は放置しておいても勝手に語数が記録されて学生が確認できるという点です。したがって,できれば4で考えたいところです。しかしながら問題は,substitute関数では置換したい対象をうまく持ってこれないという点です。もしも,「すべてのカンマまたはピリオドについて,ピリオドまたはカンマと半角スペースに入れ替える」とすると,正しく使われているところに余計にスペースを入れてしまうことになります。そうなると,スペースの数を基準とする語数カウントがうまくいきません。そこで,正規表現を使う必要が出てきます。なんと,Googlespraedsheetには正規表現が使える次のような関数があります。

  • REGEXEXTRACT(正規表現で一致する文字列を抽出)
  • REGEXMATCH(正規表現で一致する文字列があるか検索して真偽値を返す)
  • REGEXREPLACE(正規表現で一致する文字列を別の文字列に置き換える)

今回の場合は,置き換えが必要なので3番目のREGEXREPLACE関数を使います。正規表現についての詳しい説明はウェブ上にごろごろ転がっているので,以下では詳しい説明はしませんのでご了承ください(注1)。REGEXREPLACE関数は,REGEXREPLACE(検索対象テキスト, 正規表現, 置換)という引数を取ります。最初の検索対象は学生が書き込んだテキストの入っているセルをしていすることになります。では,正規表現の部分はどうすればよいでしょうか。置換したい対象の文字列は,「ピリオドまたはカンマのあとに単語列が続くもの」でした。これを正規表現で表すと次のようにできます。

“(\.|\,)(\w+)”

ここで,カッコでくくってグループ化しているのは,置換するときに元の文字列を使いたいからです。置換は,ピリオドとカンマ,その後に続く単語列はそのままで間にスペースを挟むので,

“$1 $2”

$1は最初にグループ化したものなので,ピリオドまたはカンマ,$2は次にグループ化したものなので,任意の単語列になります。その間に半角スペースが入っています。つまり,次のような関数が完成形になります。

=regexreplace(テキストのあるセル, “(\.|\,)(\w+)”, “$1 $2”)

これで,ピリオドまたはカンマのあとに単語列が続くときは半角スペースを挟む」という作業ができるようになりました。あとは,この関数のセルに対して語数カウントをする数式を適用すればよいわけです。

新たな問題

さて,うまくいったかのようにみえたのですが,実は先程の例を使うと別の問題が発生することに気づきました。それは,半角スペースはあるけれど,それがピリオドやカンマの前にあるという場合でした。例えば,下記のようなものです。

Yesterday ,I went to the zoo with my family .After that ,we went to an Italian restaurant .It was delicious.

このような用例に対して先程のREGEXREPLACE関数を適用してしまうと,新しく得られるものは次のようになります。

Yesterday , I went to the zoo with my family . After that, we went to an Italian restaurant . It was delicious.

これでは,カンマやピリオドが1つの単語として認識されてしまい,語数のカウントが逆に多くなってしまいます。これを避けるには,「文字列の直後にあるカンマやピリオドの場合には」という条件を加えれば良さそうです(注2)。ということで,改良版は次のようなものです。

=regrexreplace(テキストのあるセル, “(\w+)(\.|\,)(\w+)”, “$1$2 $3”

Googlespreadsheet上で見ると下記画像のようになります。

置換前と置換後のテキストと,それぞれの語数カウントの比較

 

おまけ(絵文字タグの削除)

slackといえば,絵文字も使えます。絵文字も文字コミュニケーションにおいては重要だという部分もありますし,一切絵文字は使うなというのもおかしな話です。slackから書き出される絵文字は,半角のコロン(:)に挟まれたタグになってテキスト化されます。”:heart:”や”rolling_on_the_floor_laughing”と言った感じです。これが文字列にくっついている場合は特に問題ありません(注3)。しかし,文字列から独立した状態で使われると,絵文字1つが1単語と認識されてしまいます。このことに気づくと,すべての文に絵文字をつけたり,あるいは半角スペースを挟んで絵文字を連続させたりという学生が現れます。昨年度は口頭注意でそれなりにケアしていましたが,どうせREGEXREPLACE関数を使うのだから,絵文字タグも取ってしまえばいいということに気づきました。下記のようにしてあげると,絵文字タグが取れます(注4)。

=regexreplace(テキストのあるセル,“\:.*?\:”,“”)

実際にGooglespreadsheet上で使うときには,スペースが入っていないことで生じる問題を解決する関数を使った上で,その結果の出力に対してさらに別の列で絵文字タグを取る関数を使うのもありです。むしろ,プログラミング的には良いのだと思います。なぜなら,なにか問題があったときにその問題の原因を探りやすいからです。ただ,入れ子にすれば1列で済みます。

=regexreplace(regexreplace(テキストのあるセル,“\:.*?\:”,“”),“(\w+)(\.|\,)(\w+)”,“$1$2 $3”)

さらに,語数をカウントする数式にこのREGEXREPLACE関数も入れ込むと…

=(LEN(regexreplace(regexreplace(テキストのあるセル,“\:.*?\:”,“”),“(\w+)(\.|\,)(\w+)”,“$1$2 $3”))LEN(SUBSTITUTE(regexreplace(regexreplace(テキストのあるセル,“\:.*?\:”,“”),“(\w+)(\.|\,)(\w+)”,“$1$2 $3”),” “,“”)))+1

もうなんだかわけがわからなくなってきましたが,この最後の数式を使えば,新しく列を増やしたりすることなしに語数カウントができるようになっています。

おわりに

この記事では,Googlespreadsheetで正規表現を使って学習者が犯すパンクチュエーションの誤りを直すということの例を示しました。他の媒体(R,Python,サクラエディタ)等で正規表現を使った経験があるのでなんとかなりました。一応ざっと確認して特に問題ないとは思っていますが,正規表現にはあまり自信がないので間違いを見つけた方はどうかコメント欄等でご指摘ください。

なにをゆう たむらゆう。

おしまい。

注1: 記号類をそのまま使うときになんでもかんでもエスケープ記号つけるのは私の癖です(そして一貫性もないですたまに忘れるので)

注2: この方法の一つの問題は,”I ate lunch ,and took a nap.”のようなものが残ってしまうという点です。「半角スペースの直後にピリオドやカンマがあり,その直後に文字列が続く場合には,半角スペースを消して文字列とピリオドやカンマの後に挿入する」のようにすれば解決されます。ただし,関数の入れ子が複雑になる上に単語数カウントには関係ないので今回は無視しています。REGEXREPLACE関数でやるとすれば,次のようなものになるかなと思います。

=regexreplace(対象文字列のセル,“\s(\.|\,)(\w+)”,“$1 $2”)

注3: もしも,単語リストを作ったり,コロケーションを見たりのようにテキスト分析にいこうとすると,この絵文字タグは外してあげないと絵文字タグと隣接する文字列が認識されなくなってしまいます。

注4: 17:10:29のように時間をコロン区切りで書き込むような例があると,これも引っかかってしまうのですが,まあほとんどないと言っていいと思うので木にしていません。

Slackを用いた授業外ライティング活動の便利ワザ[Google Spreadsheet編②]

はじめに

下記の前回の記事の続きです。

Slackを用いた授業外ライティング活動の便利ワザ [Google Spreadsheet編①]

前回の記事では,Google Apps Script (GAS)を利用して,Slackに書き込まれた内容をGoogle Spreadsheetに記録し,その記録をもとに語数を数えるという話でした。この記事では,それをもう少し便利にするために,「ある特定の期間で区切って語数をカウントする」というお話です。例えば,1日ごと,1週間ごとみたいな。月ごとの場合は,前回の記事で紹介した方法は月ごとに新しいspreadsheetのファイルができるので楽なんですが,「同じファイル内のシートの中で一定の期間の間ごとに区切りたい」となると,少しだけ工夫がいります。といっても,spreadsheet内で関数を書くだけなのでそんなに大変なことではありません。一度雛形ができればあとはコピペして少し書き換えるだけですみます。

前回のおさらい

少しだけ前回の記事に書いた内容に触れておきます。GASを使ってspreadsheetに取り込まれた状態は,下記画像のようになっています。

Screen Shot 2018-09-24 at 22.50.58

A列が日付,B列が名前,C列が書き込まれたテキスト,D列がもとのJSON形式の情報です。このシートが,チャンネルの数だけ一つのファイルにある状態です。前回は,GASで更新されるこのシートの情報を以下のような手順に沿って使いました。

  1. importrange関数を使って別のファイルにエクスポート
  2. そのシートに語数をカウントするE列を挿入
  3. sumproduct関数で名前列を参照してE列の合計を求める

すると,下記画像のようなまとめシートができます。

sumproduct-example

今回は,そこに「日付の情報も参照する」という情報も付け加えていくことになります。

同じ月内で1週間ごとに語数を数える

では,実際に私がやっている実践に即して,1週間ごとに語数を数えるという作業をやる方法です。先程説明したように,前提は一ヶ月で一つのファイルができ,そのファイルの中にチャンネルの数だけシートがあるという状態です。同じ月内であれば一つのシートの情報で,以下のような作業をspreadsheetにやってもらいます(注1)。

  1. まとめシートのA列にあるセルの名前に当てはまるものだけをフィルタリング
  2. 参照元シートのB列にある日付の情報を参照し,指定した1週間のものだけをフィルタリング
  3. 1と2で絞り込まれたデータのE列の語数を合計して計算する

注意点は,参照するデータのシートでは名前がB列,日付がA列なのに,まとめシートでは名前はA列になっているという点です。どの列にどのデータがあり,どこの列を参照するのかを考えないと混乱するかもしれません。さて,前回はsumproduct関数使ったんですが,今回使うsumifs関数でも同じことが可能だと思うので,全部sumifs関数でやってもいいかもしれません。

先にあとで説明する作業が完了した状態のシートの画像を見てください。1つ前の画像の状態から,下記の画像の状態にすることが今回の目標です(注2)。

Screen Shot 2018-10-12 at 14.12.11

私がこのSlackライティング活動を採用しているのは金曜日の授業で,金曜日から次の週の木曜日までを1週間としています。日付で区切っていて時間で区切っているわけではないので,今回は日付で絞り込みにしています(午後5時までとかそういう切り方だと時間も指定する必要があります)。

では,上の画像のB2の列にはどのような式が入力されているのか見てみましょう。

Screen Shot 2018-10-12 at 14.12.38

画像中の式で最後に”-5″しているのは,最初は必ず”@XXX has joined the channel. “という5語の文が記録されているので,それを排除するためです。

sumifs関数の基本的な引数はsumifs(合計範囲, 条件範囲1, 条件1, 条件範囲2, 条件2, …)のようになっています。合計範囲とは,合計を計算したい範囲のことですので,今回の場合はE列の語数の列を選択します。”Friday2_201809″というのが,金曜2限クラスの9月分のデータがエクスポートされたシートになります。このまとめシートはimportrangeで自動的にデータがエクスポートされるように設定しているspreadsheetファイルの中に作っているので,”Friday2_201809!$E$1:$E$1000″で,「9月分のデータのE列(語数列)」を合計範囲として指定していることになります。コピーしたときに範囲が変わることを防ぐために,絶対参照にしています。

2つ目の引数は,同じ”Friday2_201809″のA列を1つ目の条件範囲にしています。A列は日付の入っている列ですから,日付列を条件範囲としていることになります。そして,3つめの引数で日付の条件指定を行います。最初の1週間は,もともとデータ記録の一番最初(2018年9月21日)が1週間の1日目でしたので,7日目(終わりの日)だけを指定しています。これには等号・不等号の使い方でいろいろなやり方が考えられますので,この例は一例です。

“<“&”2018-09-28”

等号・不等号は必ずそれのみをクォーテーションマークでくくり,クォーテーションマークでくくった日付と&でつなぐようにします。上の式が意味しているのは,「2018年9月28日より前(つまり27日以前)」です。これで,9月28日0時00分以降の書き込みが排除されます。

4つ目の引数は条件範囲2です。”Friday2_201809″のB列を参照しています。B列は名前の入った列ですので,名前の絞り込みをしようというわけです。最後の引数は$A2です。「条件範囲2(元データの名前列)の中で,まとめシートのA2セルの名前に当てはまるものだけをフィルタリングしてね」ということです。指定する順番自体は前後していますが,上にも挙げた以下の3つの作業が1つの関数で実現されたことになります。

  1. まとめシートのA列にあるセルの名前に当てはまるものだけをフィルタリング
  2. 元ファイルのB列にある日付の情報を参照し,指定した1週間のものだけをフィルタリング
  3. 1と2で絞り込まれたデータのE列の語数を合計して計算する

これであとは,列を横に足して,別の日付指定をすれば,あとはその条件に当てはまるものだけが自動的に記録されていくことになります。合計範囲指定は固定ですが、条件範囲と条件の指定は名前が先で日付が後でも構いません。

1週間のはじめとおわりを指定する場合

さて,上のやり方は,1週間の終わりだけの指定でしたが,それが使えるのは最初の1度だけで,次からは1週間のはじめの日も指定する必要があります。「○月○日から○月○日まで」としたいわけです。これをやるには,sumifs関数の条件範囲と条件を1つずつ追加すればいいだけです。画像上では順番が前後しますが,下の画像のD列(10/5-10/11)の1週間を指定した場合を見てみましょう。

Screen Shot 2018-10-12 at 14.13.34

1つ目の引数は同じですが,2番目と3番目の引数で始まりの日付の指定,4番目と5番目の引数で終わりの日付の範囲の指定を行っています。

“>=”&”2018-10-05”

という指定は,「2018年10月5日以降」という指定になります。1週間の始まりですね。

“>”&”2018-10-04”

としても同じです。続いて,終わりの日付は,同じように日付列を条件範囲とし,

“<“&”2018-10-12”

を条件にしています。つまり,「2018年10月12日より前」ですので,2018年10月11日の23時59分までのデータが条件に当てはまることになります。

“<=”&”2018-10-11”

でも同じです(むしろこっちのほうがわかりやすいかも)。これで,始まりの日付から終わりの日付までの間の合計語数が計算されます。ここを任意の幅に設定すれば,1週間ではなくとも3日でも4日でも10日でも同じようにできます。

月をまたいだ1週間の語数

同じ月内でのやり方は上の2つのやり方の組み合わせで対応できます。では,月をまたいでしまうときはどうすればよいでしょう。上述したように,月ごとにシートが異なるわけなので,別々のシートに記録された情報を統合する必要が出てきます。ただ,難しいことはなく単純に足し算すればよいだけです。

Screen Shot 2018-10-12 at 14.13.15

この例では,Friday2_201809というシートに9月分,Friday2_201810というシートに,importrange関数でデータを同期させています。9月分のデータで,9月の終わりの数日間(この例では9月28日~9月30日),10月のデータで10月1日からの数日間(この例では10月1日~10月4日)の語数を計算し,合算するという作業です。

つまり,それぞれの月でsumifs関数を使った式を作り,2つのsumifs関数式を+記号でつないであげれば,月をまたいだ場合の語数が計算できます。不等号のみと,不等号+等号の意味の違いは,上で説明したとおりです。

おわりに

ということで,前回の記事で紹介したGASでデータを引っ張る作業,importrange関数でデータを別ファイルにエクスポートする作業と,今回の記事で紹介したsumifs関数で日付指定する3つのパターンを使えば,一定期間の間の語数記録は簡単にできてしまいます。

エクセルが得意な方はすでにお気づきかもしれませんが,実は,1行目に指定する日付を終わりの日付にし,そのセルを日付の範囲指定に利用することもできます。つまり,上の画像で言えば,B1セルに”2018-09-27″,C1セルに”2018-10-04″,D1セルに”2018-10-11″のようにするということです。ただ,見たときに1週間の範囲がわかるほうがいいかなという理由で,そういうやり方はしていません。

ということで,下処理問題は解決されていませんが,だいたいの語数を記録して,学生がいつでも見れるようにするということについては,前回と今回の記事の内容でだいたいカバーできるのではないかなと思います。今の所第三段は予定していませんが,今後もしも「こういう事が必要だなぁ」という事が出てきたら更新するかもしれません。

なにをゆう たむらゆう。

おしまい。

注1. おそらくExcelのピボットテーブルなら,同じ列に当てはまる複数の条件でのフィルタリング可能だと思うので,Excelならピボットテーブルだけでいけると思います。

注2. 画像で一目瞭然ですが,毎週書き続けられている学生と,すでに脱落してしまっている学生が分かれてしまっているのは問題で,これについては何かしらの介入が必要だと思っています。

Slackを用いた授業外ライティング活動の便利ワザ [Google Spreadsheet編①]

はじめに

便利ワザと言えるのかわかりませんが,とりあえず自分はこんな感じでやっていますというお話です。以下の話の発展です。

授業外でライティングする機会を確保するためのSlack

前提として,どのようにSlackを利用しているのかというお話です。google spreadsheetに書き出したデータの扱いについてにご興味がおありの方はこのセクションは飛ばしていただいてかまいません。私がslackを使おうと思ったのは以下のような考えからです。

授業外で,英語ライティングする機会を与えたい。できるだけ自由に書き込みができ,教員もそれを監視・管理しやすい。

やろうやろうと思っていたのですが,なかなかSlackの使い方もよくわかっていませんでした。共同研究の話等でもSlackを使い始めるようになり(サイボウズのサービス終了のため),自分もSlackに慣れてきたのでこの秋学期から導入することにしました。ここでも何回か記事を書いている外国語学部1回生向けのライティングの授業でのことです。

授業外でのライティングは,前記はLMSにある掲示板機能を使い,そこに私が毎週話題をポストしてそれについて各自意見を書き,お互いにコメントし合うというものでした。以下のリンクでそのことにも触れています。

https://tam07pb915.wordpress.com/2018/04/26/writing-class/

後期は,slackをclosed SNSのようにして使い,自由に英語でやりとりをするということを掲示板でのフォーラムライティングの代わりにすることにしました。前期のフォーラムライティングでは,「1人必ず○人にコメント」などとしたりして交流が生まれるようにしてみましたが,コメントが「テンプレ」化してしまったりしていたので,より自由にライティングのコミュニケーションができていったらいいなと思っています。

使い方のルールとしては以下のようにしています。

  • 一般的なルール
    • 自分のスマートフォンに必ずslackアプリをインストールすること
    • 書き込む情報については,既存のSNSに関するルールと同様,誹謗中傷や公序良俗に反する書き込み以外であれば,何について書き込んでも構わない(写真の投稿も可能)
    • 日本語での書き込みは一切禁止
    • 使い方等についての質問がある場合は,#generalに英語で書き込むこと
    • 他のクラスの人にも話題を共有したい場合には#randomに書き込むこと
    • 誰かの書き込みに返信(いわゆるリプ)をしたい場合は,”Start a thread”を使うこと
    • “Start a thread”機能を使うときは,”Also send to #channel-name”にチェックを入れること(こうすることで,メインのタイムラインでも返信が見れます)
    • 誰かに直接話しかけたいときは,@をつけること
    • 成績に算入するのは,自分のクラスのチャンネルに書き込んだもののみ(#generalや#randomや他のクラスのチャンネルに書き込んだものは語数に数えない)

評価方法は,毎週300語を学期の最終授業日まで続け,平均達成度(%)×5点を最終的な評定に加えるというものです。共通シラバスのため,授業外の課題に割ける評価の割合がもともと15点くらいしかないのでこのようにしています。そのために300語って結構えげつないなと思われる方もいるかもしれませんが,私もそう思っています。今学期の様子をとりあえず見てみて,ハードルが高すぎるために「コスパが悪い」と思われて取り組みが悪くなるということがあれば今後語数の基準を下げるかもしれません。

Slackデータのエクスポート

さて,上述のような形でslackを運用しているわけですが,私の扱い方だと「毎週300語」という設定にしているので,学生の立場からすれば「自分が今何語書き込んでいるのか」がいつでもわかるようになっていてほしいというのは当然でしょう。そのために教員がわざわざデータをチェックしてそれぞれの学生の書き込んだ語数を分析してまとめて報告するというのは無理でしょう。というかやってられません。そこで,エクスポート->語数の記録->まとめ,という一連の作業を自動化して,いつでも学生が見れるようにする必要があります。そこで,上に上げたスライドで浦野先生が紹介しているGoogle Apps Scriptを使うというわけです。浦野先生も紹介していますが,SlackのログをGoogle Spreadsheetに保存するという作業自体は以下の記事を参考にすればすぐにできます。

Slack のログを自動で Google Spreadsheet に保存する

問題は,その先で,語数の記録とそのまとめという部分になります。私自身がGoogle Apps Scriptをいじれないので,とりあえずは上記のリンクを参考にGoogle Spreadsheetにログを保存し,そのあとにGoogle Spreadsheetで頑張るということになります。Rでもログを取ってきてまとめて可視化みたいなことはできますが,自動化の部分が少し難ありです。Rのコードもそのうちここに投稿しようと思います。

Google SpreadsheetでSlackのログをいじる

Google Apps Script(GAS)は,自分で決めたトリガーで定期的に更新できるので,その頻度を好みに設定しておくだけで,定期的にデータを最新のものにするという作業はできます。最初は,ログのspreadsheetファイルにある各チャンネルのシートに列を追加して各行の書き込みの語数を記録し,それを別ファイルにピポットテーブルで吐き出すということを考えました。ちなみに,ログのデータは下の画像のような感じでチャンネルごとにシート1枚で記録されます。

A列が日付,B列が名前,C列が書き込まれた内容,D列はもとのJSON形式のデータです(注1)。最初は,このシートのE列に語数カウントの関数を入れていたわけです(excelで語数のカウント方法についてはググればすぐに見つかります)。ただ,それだとシートが更新されるとうまくいきませんでした。このチャンネルのシートをそのまま別シートで参照し,その参照したコピーのデータを使って…ということもやりましたがこれもうまくいかず。ということで,GASが作るスプレッドシートとは別のスプレッドシートファイルを作り,そこからもともとのスプレッドシートの中の特定のシートの情報を参照するという方法を取ることにしました。で,これexcelにもある関数のなのかは知らないんですが,Googleスプレッドシートには,importrangeという関数があり,これを使うことで別ファイルから参照ができます。以下のサイトなどが参考になりました。

【超便利】スプレッドシートで別シートから参照したり集計したりする方法まとめ

引数の基本は,importrange(“参照元ファイルURL”, “参照元シート名!特定セルor範囲)で,このimportrange関数は特定のセルのみを参照する場合と,範囲を指定する場合があるのですが,私は上の画像でいうA〜D列まですべてもってきたいので,範囲を指定することになります。とりあえず,1000行までを1シートに出すという設定だったような気がするので,A1:D1000を指定します。friday2というのは,金曜2限のチャンネルで,後ろのぼかしはslack上のチャンネルIDです。

このimportrange関数をA1セルに入力すると,シートにAからD列までのデータが取得され,参照元のシートがGASによって更新されれば,こちらのシートも更新されます。E列は手動で以下の画像のような関数を入れると,C列のセルの語数がE列のセルに記録されます。あとは,このE列の語数をB列の名前ごとに合計してくれれば,目的達成です。私は金曜の1限と2限に同じライティング科目の別クラスを持っているので,このログシートが2枚あり,そのまとめのシートも2枚あります。

まとめのシートで合計語数の表示

上画像のシート上でやってもいいんですが,見栄えもあるので別シートにまとめだけを作ります。これは,sumproduct関数をつかいます。sumproduct関数は,sumproduct(参照列=名前, 合計を数える列)のような形で使います。下記画像は,”Friday1_import”というシートに,importrange関数で参照元ファイルのデータをインポートしている場合の例です。A列に名前の一覧(注2),B2にこのsumproduct関数をいれます。あとはB2を下にコピーすれば,人数分の合計語数が表示されるというわけです。”Friday1_import”のシートには自動的にデータが追加されていくので,とりあえず1000行を超えないデータであればこれでなんとかなります。

棒グラフでも出したいということなら,範囲選択して棒グラフ挿入でOKです。あとは,このスプレッドシートのファイルを「閲覧可」の権限で共有してSlackに貼り付ければ,学生は自分の好きなタイミングで語数を確認できることになります。私の場合は「毎週300語」という課題なので,週ごとにデータを扱える必要があります。これはもう少し別の手続きが必要になるので,また次回ということに。今日はここまで。

なにをゆう たむらゆう。

おしまい。

注1: そもそも,ちゃんとした「下処理」をしないと,「@XXXXX has joined the channel」とかも記録されますし,絵文字1つが1語みたいになるので,ここでの語数は「アバウトな」語数ということになります。

注2: 私は試行錯誤しているときにピポットテーブルを使ったので名前の一覧はコピペでしたが,そうでない方はログデータの”@XXXX has joined the channel”の列だけソートして名前の一覧をゲットするなどの方法が必要です。

[R] sjPlotパッケージのバージョンアップ

Rで回帰モデルの図示をするときに私が使うパッケージは主に2つあって,1つはeffectsパッケージ,もう一つはsjPlotパッケージです。前者については,以前NagoyRで発表したことがあります。

effectsパッケージを用いた一般化線形モデルの可視化

後者は,lm, glm, lmer, glmerなどの関数で作った回帰モデルの結果が入ったオブジェクトを渡すと,その結果をggplot2に渡して可視化してくれます(その他にもいろんな可視化が可能ですが,私が使うのは主に回帰モデルの可視化です)。昔(数年前)までは,sjp.lm,sjp.glm,sjp.lmer,sjp.glmerなど,もとの回帰モデルに合わせて図示する際の関数を選ぶ仕様になっていました。そして,交互作用図を描きたいときは,sjp.int関数を使うというような。それが,最新版のsjPlotパッケージでは,これらの関数がなくなりすべてplot_modelという関数に統一されているようです(下記のサイトによると2017年10月にこの変更があったようです)。使用例は以下のサイトが参考になります。

„One function to rule them all“ – visualization of regression models in #rstats w/ #sjPlot

交互作用図は,type引数でintにするか,またはtypeをpredにして,termsで交互作用を指定するようです。

plot_model(fit, type=”int”)

or

plot_model(fit, type =”pred”, terms =c (“test”, “group”))

みたいな感じです。これについては,下記のページが参考になります。

 

Plotting Interaction Effects of Regression Models

より詳細な引数の説明などは以下のページに書いてあります(RDocumentationのページ)。

plot_model function | R Documentation

D院生のときに書いたスクリプトではGLMMの結果の可視化にsjp.glmerとかsjp.intを使っていたので,それらが動かなくなっていました。調べたらこういう仕様の変更があったと。一つの関数で,引数の組み合わせで色々な図が描けるというのは便利でいいですね。ただ,テーブル形式(HTML)で回帰モデルの結果を出力するsjt.lm系の関数は,lm, glmなどと組み合わせて,sjt.lm, sjt.glm, sjt.glmer, sjt.lmerなどのままのようです。

それから,最近lme4のモデル式の書き方でstanを使ったベイズ推定ができるbrmsというパッケージを知った(遅い)のですが,plot_model()はbrmsパッケージのモデルにも対応しているようです。まだ試してはいないので,いつかまたブログに書こうかなと思います。

では。

なにをゆう たむらゆう。

おしまい。

Visual World Paradigmの分析

だいぶ前に書きかけで放置していた記事の更新です。

7月1日,2日で言語科学会に行ってきました。心理言語系の発表が多く,講演やシンポジウムでの発表も含めて,Visual World Paradigm(以下,VWP)という手法を用いた研究が結構ありました。このVWPは,ざっくりいうと主に音声で言語刺激を与え,それを処理している最中の実験参与者の視線を計測するという手法です。このとき,参与者は主に視覚提示されたいくつかの絵や写真を見ています。そこで,どこをどれくらい見ているか,あるいはどのタイミングでどこに目線がいきやすくなるのかを観察することで,人間の言語処理の仕組みを明らかにしようとするわけです。

で,そこですごく気になったのが分析方法。普通の文処理中の視線計測実験では,文のどこ(どの単語,句)をどれくらい見ているかなどを分析しますが,VWPでは音声データが流れていく時間の経過とともに変化する視線の動きを追っているわけで,時系列データになります。文であれば,画面上に1行で提示できるほどの長さが限界ですので,多くとも10-15語程度,その中で,分析の対象となる区域は2-3程度だと思います(注1 )。

ところが,VWPの人たちってまずこの区切り方がめちゃっくちゃ恣意的だったりします。それでもって,25msとか50msごとにグラフに点を売ったりしているわけです(eg., Ito et al., 2017, BLC)。え?待って?てことは50msごとにモデル作ってそれぞれで「検定」っぽいことしているわけ?LME(GLMM)使ってるからどうのこうのとか言う問題じゃなく,その分析の仕方っておかしくないですか?要するにt検定を数十回繰り返しているのと同じわけで,そんなことしたら第1種の過誤が飛躍的に上昇してしまうはずですよね(注2)?

たまたまBLCで見つけたので他意はまったくないのですが,Ito et al. (2017)ではその部分に対して以下のような記述があります。

This way of analysing the time-course increases the likelihood of Type I errors, but we note that the differences reported below show consistently reliable effects over multiple bins.

確かに論文中の図をみると,条件ごとの傾向がかなりはっきり出ているわけですが,だからといってそんな50msごとに「有意!有意!」みたいなことやるのは正当化されないでしょう。だって,繰り返しが多いので有意水準をめちゃくちゃ保守的にしますなんてことはやってなくて,t値が2超えたら有意ってことでいくんでよろしくとかやってるのですから。

VWPは手法としてはすごく面白いのだけれど,分析の手法が全然追いついていないのではないかというような印象です。このパラダイムで分析をしていくためにはもともとの注視時間のデータを割合にする(つまりある単位で区切ったときに,その単位時間のなかでどの領域をどれほどの割合で注視しているかというデータにしている)ということがおそらく不可欠だからかもしれません。そうではないと,視線計測の時系列データから興味関心のあるデータをうまく取り出すことができないからです。もっといい方法ないのかなと思うのですが…

もし仮に単位時間を恣意的に設定して「観測点」のように捉えることは出発点としてOKだとしても,それはやっぱり時系列データ分析の手法を持ってくるほうがいいように思います。以下の記事のような考え方です。

二つの時系列データの間に「差」があるか判断するには

自分でこの時系列のデータ分析を実装する技術を持ち合わせているわけではないのですが(そもそも視線計測のデータセットを見たことがないのであまりイメージも浮かばない),誤差による上下動があるなかでの特定の条件での「変化点」を検知したり,あるいは区域ごとではなく「全体として」プロセスが異なることを分析するような考え方ができたらいいのではと思います。区域ごとに区切って分析するとはいえ,前の状態の影響を一切受けずに次の状態が決まるわけではなく,前の状態があるから次の状態に移行するわけで。たぶんこれって視線計測装置とか文処理にかぎらず,時系列になっている(観測点が時系列上に複数並ぶ)データに対してはすべて当てはまると思うんですよね。longitudinal studyとかも含めて。

私も結局はエンドユーザーなので,自分がそういうデータセットを前にしたときにうまく分析して解釈できる自信があるというわけではないのですが,なんかもやもやするなぁと思いながらずっと発表を聞いていたのでした。

なにをゆう たむらゆう。

おしまい。

 

注1. もっと解像度の低い視線計測装置だとヒートマップみたいなもので視覚的にどの辺を多く見ていたかとかやることもあるかと思います。パッセージ読んでるときの視線とか。

注2. これはもちろん自己ペース読み課題の分析にも当てはまるのでブーメランです。

[R] データフレームの中の英文の語数を数える

以前,エクセルで英文の中の特定の単語までの語数を数えるという記事を書きました。今回はそれよりもっと単純で,Rのデータフレームの中の1部に英文が入っていて,その英文の語数を数えてデータフレームに付け足したいなっていう作業です。

%e3%83%96%e3%83%ad%e3%82%b0%e8%a8%98%e4%ba%8b%e7%94%a8_20170218

こんな感じでロング型のデータがdatという変数にあるとします。このデータフレームのなかの,sentenceという列には英文が入っていますが,それぞれ長さが違います。文が長いほうが反応時間も長くなっちゃいますから,そのために英文に含まれる語数を数えてそれも分析に使いましょうということです。僕がやっているような反応時間を扱う実験ではよくありがちな手続きです。本来なら刺激文作るときにそれもちゃんと数えておいて(エクセルで語数数えるのは簡単です。前掲の記事の一部がそれです),結果が出力される際にちゃんと語数の情報も含めておけばいいんですけど,まぁ今回はそれ忘れちゃったんでRの中でやってしまおうという事後的な対処法です。

さてさて前置きが長くなりました。Rでの文字列処理の基本は「分ける」・「数える」だと思います。僕はそんなにRで文字列処理しないんですが,今回の場合で言うと,データフレームの要素に含まれる英文をスペースで区切り,区切ったときにいくつかに分けられた要素の数を数えることで語数をカウントするという手続きになります。

今回使う関数は次の4つです。

  • (as.character関数)
  • strsplit関数
  • length関数
  • sapply関数

順番に説明していきます。strsplit関数は

strsplit(分けたいもの,区切り文字)

という感じで使います。今回の場合,分けたいのはdatの中のsentenceという列(dat$sentence)で,スペースで区切りますから,

strsplit(dat$sentence, ” “)

とすれば,

%e3%83%96%e3%83%ad%e3%82%b0%e8%a8%98%e4%ba%8b%e7%94%a8_20170218_2

こんな感じで単語ごとに区切ってくれます。この出力は1文ずつのリスト形式になっていて,そのリストの要素が英文を構成する単語になっています。もしも,このstrsplit関数がうまくいかなければ,

is.character(dat$sentence)

として,データフレーム中の英文が文字列形式で格納されているかどうか確かめてみてください。因子型(factorial)になっていると,strsplit関数は適用されません。これを変えるのが,as.character関数です。

strsplit(as.character(dat$sentence))

または,

dat$sentence<-as.character(dat$sentence)
strsplit(dat$sentence, ” “)

としてみてください。

さて,これでひとまず「区切る」作業はできましたが,まだ「数える」にはいたっていませんよね。数えるためによく使われるのが要素の数を数えるlength関数です。ただし,例えば

length(strsplit(as.character(dat$sentence)))

としてもうまくいきません。これでは出力されたリストの要素を数えるので,元のデータフレームの行数が表示されるはずです。ここでは,「リストのそれぞれの要素に対してlength関数を適用したい」わけなので,もうひと工夫必要です。そこで使うのがapply系列のsapply関数です。この関数は,

sapply(リスト,関数)

という形で引数を与えてあげると,リストの各要素に関数を適用してくれます。これと同じことができるのがlapply関数です。lapply関数を使うと,結果の出力もリスト形式で返されます。ただ,ここでは語数が並んだベクトル形式のものを手に入れて,それをもとのデータフレーム(dat)に追加したいわけなので,sapply関数のほうがベターです。lapply関数にすると,そのあとリストをベクトルに直すunlist関数を使う必要があって二度手間になってしまうので。というわけで,

sapply(strsplit(as.character(dat$sentence), ” “), length)

こうしてあげれば「スペースで区切る-> 語数を数える -> ベクトル形式で結果をゲット」という作業が完了します。あとは,

dat$num.words<-sapply(strsplit(as.character(dat$sentence), ” “), length)

としてあげれば,datに新しくnum.wordsという列が追加され,そこにはsentenceの列に入っている英文の語数が格納されることになります。めでたしめでたし。といきたいところなのですが,最後におまけでもうひとつ。

上の書き方だと,いくつもの関数が入れ子状態になっていて,一見して作業がわかりにくいですよね?そこでパイプ演算子を使って同じことをもう少しわかりやすく書き直してあげます。

dat$sentence%>% #datの中のsentenceという列を取ってくる
as.character%>% #文字列型に変換
strsplit(. , ” “)%>% #スペースで区切る
sapply(., length) -> dat$num.words #リストの要素ごとに語数を数えてdatというデータフレームのnum.wordsという列にいれる

こうやって書くと,作業の過程が見えてわかりやすいですよね。ちなみにこのパイプ演算子はパッケージ依存です。dplyrやtidyrを使うときに使うやつですね。たぶんこれらのパッケージを読み込んでいればパイプ演算子も使えるようになっているはずです。もともとはmagrittrというパッケージに入っているのがパイプ演算子が%>%なんですよね(たしか)?

というわけでlapplyの出力をunlistしてできたできたと思っていたらsapply関数の存在に気づいてなんだよ二度手間じゃんかよって思ったのでブログ記事にしました。

なにをゆう たむらゆう。

おしまい。

 

 

 

[R] 欠損値を1つでも含む行を抽出

ものすごい初歩的なことだったのに,調べてもなかなかヒットせずに格闘したのでメモ。

RでNAを処理する方法はたくさんあって,ある特定の列にNAが含まれる行だけ引っ張ってくるなどは結構簡単だったりする

subset(dat, is.na(dat$A))

とかでいい。ただし,データフレームにある複数の変数の中で1つでもNAが入っているかどうかとなるとちょっとどうしたらいいんだこれは,となる。

na.omit(dat)としてNAが含まれている行を全削除すればいいのでは?となるかもしれないが,実は今扱っているデータがlong型のうえにかなり複雑なデータフレームになっていて,同じidが複数行にまたがってしまっているという状態。実験のデザインがかなり複雑なのでこれはこれで仕方がない。

つまり,複数行のうち1行でもNAがあるidは,NAが含まれない行でも削除しないといけない。そのためには,NAが含まれる行のidを特定する必要があるわけだ。そこで,欠損値を含む行を抽出し,その中からid列だけを取ってくるという手続きを取る必要がでてきた。こうすれば,あとはdplyrのfilter関数なり,subset関数なりでそのidが含まれる行をすべて抜いて新しいデータセットを作ればよい。

それで,この,NA行の特定をベクトル形式で返してくれる関数が,complete.casesという関数。is.na関数にデータフレームを渡すと,その結果は行列(matrix)形式になる。これはこれで,どの行のどの列にNAがあるかを確かめるのにいいのだけれど,こちらが欲しいのは,「何行目」にNAが含まれるのかという情報だけ。そこで,complete.cases関数を以下のような感じで使う。

subset(dat, complete.cases(dat)==F)

あるいは,

dat%>%
filter(complete.cases(dat)==F)%>%
select(id)

上の方法だと,結果はデータフレームだけど,下の方法だとid列を引っ張ってくるところまでやるので,これをなにか別の変数(ここではmissIDにしてみる)にいれてあげて,

subset(dat,id != missID)

とかやれば,id列でmissIDに該当しない行だけを抽出してくれる。下書き状態で放置されていたからとりあえず最後まで書いたけど,自分がなんのデータに対してこの手続をしていたのかはもう思い出せないw

データ分析業務ばかりやってるのは楽しいからいいんですけどね。

なにをゆう たむらゆう。

おしまい。

※追記(2017.03.11)

subset(dat,id != missID)

とやってもうまくいかないことがあるようです,というか多分うまくいきません(自分でやってみてダメだったので)。多分ですが原因の1つはmissIDがデータフレーム形式になっている場合。ベクトルになおしてください。もう1つの原因は,subsetなりdplyrのfilterなりで複数の条件を設定する場合に,参照先がベクトル形式の場合には通常の論理演算記号が機能しないことです。多分こちらのほうが大問題。時間が経ってから書いたからかこのことをすっかり忘れていましたすみません。正しくは%in%を使って,

subset(dat, !id %in% missID)

とします。この場合,データフレームの中の参照先の列名の前に!をつけます。これをつけないと「当てはまるもの」を取り出すことになります。