# Rでのファイルの入出力 ---- # DS1-resume2020-02.R # 作成:2020年05月30日,改訂:2020年06月18日 # 説明:RStudioとRの基本的な操作をコメント文(行左端が#から始まる)とその関数の形で構成されています #    読めばわかるように書いていますので,説明を読みつつ,関数を実行して結果を確認していってください # ファイルのダウンロード ---- # インターネット上のファイルを直接ダウンロードして保存することができる # 既に説明抜きで使用して来た download.file() 関数を利用する # 以下のファイルは後の実習で利用するので,実際に関数を実行してダウンロードしてみる download.file("http://www.sip-ac.jp/sip/konan_text/batting-average.txt","batting-average.txt", mode="wb") download.file("http://www.sip-ac.jp/sip/konan_text/batting-average2.txt","batting-average2.txt", mode="wb") download.file("http://www.sip-ac.jp/sip/konan_text/batting-average.xls","batting-average.xls", mode="wb") # download.file() の引数の説明 # 1つ目の引数がダウンロードしたいファイルのURL, # 2つ目の引数が保存するファイル名, # 3つ目の mode は書き込み(w)か追加書き込み(a)かの別 # wb の b はバイナリでの転送.テキストだとなしでよいはずだが,windowsでCR+LFで改行コードが指定されていると無駄な改行が挿入されてしまうの防ぐため # なお mode="wb" の場合は,既にそのファイルがあった場合は上書きされる(元の内容はなくなる)ので注意 # データの入力 ---- # 一番基本的な入力方法 ---- # 変数にデータを入力する方法についての復習 # Console画面,あるいはRのソースファイルで = あるいは <- を使って代入 a = 10 # 右辺(10)が左辺の変数aに代入.逆はダメ 10 = a # エラーになる # ただし不等号を使う方式だとOK 10 -> a a <- 10 # 変数同士のときは注意が必要.結果を比較してみる a = 10; b = 5; a = b a; b a = 10; b = 5; b = a a; b # Console画面でキーボードから入力する方法 ---- # キーボードから入力するためには,関数 scan() を利用する # scan() はファイルからも入力可能,後で説明する # 値を打ち込んで Enter を押すの繰り返し.終了するときは値を入れずに Enter だけ押す a = scan() # 例えば,Console画面から 1 Enter 2 Enter 3 Enter Enter と入力 # これだと c() と違いがなくて,あんまり恩恵がない. # scan() が役に立つのは,例えばwebのページで表形式で公開されている数値や文字をコピペするとき # ブラウザで新しいタブかウインドウを作成して https://hanshintigers.jp/game/stats_team/bat27.html を開く(URLをコピペしてEnterキーを押せばよい) # 例えば,背番号の前あたりにマウスカーソルを移動させてから左ボタンを押して,そのままドラッグして大山の一番右端までが選択された状態にする(ハイライト状態) # そこで選択された部分をコピーする(ショートカットキーでもよいし,右ボタンをクリックしてポップアップアから選んでもよい) # ここまでの操作でパソコンのクリップボードにデータが保存されている # 次はファイルへの貼り付けを行う # RStudio CloudはLinuxというOS上で実行されている # Linuxでクリップボードから貼り付けるためのxclipなどが実装されていないようなので,通常のLinuxでの取り込み方法は現時点では利用できない. # そのため,まず何か適当なファイルにコピーして保存し,それをscan()で読み込めばよい # FileメニューからNew File→Text fileを選ぶと,新しいファイルがSource画面に作成される # FileメニューからSave Asを選ぶとSave Fileウインドウが表示されるので,clipboard001.txtと名前をつけてSaveを押す # そのclipboard001.txtにコピーした内容を貼り付ける(もしなくなっていたら,もう一度先ほどのウェブページに戻って選択してコピーする) # 保存した後で,次の関数を実行する scan("clipboard001.txt", sep = "\t", what = "") # RStudio.Cloud用 # 1つ目の引数は読み込むファイル名,引数sepはファイルのデータの区切り記号(\tは改行,タブを区切り記号に設定,引数whatば読み込む時の型(""は文字として,なんでも読み込める),省略すると数値型になるので注意) # キーボードからの入力は readline() も利用できる. b = readline("プロンプトに使う文字列:") # 123と半角で入力してEnterキーを押す # ただし文字列として格納されるため,数値として使いたい場合は取り込んだ後 as.numeric() などで変換する必要がある # 閑話休題:桁区切りのカンマが邪魔 ---- # 慣例的に桁数の多い数値で3桁ごとに桁区切りのカンマを入れる # 人間が見る分には便利かもしれないが,数値を扱う側からするとかなり邪魔 # 例えば 1,000 は数値でなくて扱い上は文字列になる a=1,000 # エラーになる # ネット上のデータを scan() で取り込む場合は gsub() を使って次のように置き換える gsub(",", "", "1,000") # 1つ目の引数:置換するパタン(文字列),2つ目の引数:置換後の結果(文字列),3つ目の引数:置換したい対象全体 # 例では,半角カンマ(パタン)を文字なし(結果)に置き換えて(取り除いて)いる # 数値として使う場合には,その後で as.numeric() などを使って数値に変換してやればよい as.numeric(gsub(",", "", "1,000")) # テキスト形式ファイルからの入力 ---- # 上で scan() を用いてファイルから入力する方法は紹介したが,別の関数を用いて読み込む方法も紹介する # Rを利用していないユーザとデータをやり取りするためによく使われるファイル形式がCSV形式 # csv形式のファイルは各行のデータが半角のカンマで区切られている # この場合,関数 read.csv() を利用するのが簡単.データフレームとして読み込まれる data1=read.csv(file="batting-average.txt", fileEncoding="utf8") # 引数 file に読み込むファイル名を指定 # 引数 fileEncoding="utf8" の部分は,読み込もうとするファイルの文字コードにより変更 # 注意:読み込むファイルの1行目は自動的にヘッダとして処理される # なお関数 read.table() でも同様の処理が可能 data2=read.table(file = "batting-average.txt", header = T, fileEncoding = "utf8", sep = ",") # ただしデータの区切りを明示的に sep="," として指定する必要があるのと,ヘッダの有無を header=T で指定する必要あり # データがカンマ以外,例えばタブで区切られている場合 # この場合は,関数 read.table() を使えばよい read.table(file = "batting-average2.txt", header = T, fileEncoding = "utf8") # read.table() の区切り文字の初期指定は sep="" なので,タブ,空白,改行が区切り文字であれば省略可 # なお自分のパソコン上に保存されているデータの場合は file.show() を使って区切り記号などを確認できる file.show("batting-average.txt") file.show("batting-average2.txt") # Excel形式のファイルの読み込み ---- # Rを利用していないユーザとのデータのやり取りの方法として直接表計算ソフトのExcelのファイルを読み込むことも可能 # readxlライブラリを利用するとよい # https://cran.r-project.org/web/packages/readxl/index.html # 標準ではライブラリが利用可能になっていないので,既にフォント関連で実習済みのライブラリのインストールを実行 install.packages("readxl") # Do you want to install from sources the package which needs compilation? y/n: # と表示されたら y を押して Enter # しばらく勝手に動くので待つ # 終了したら library("readxl") # 注意:library("readxl") はWorksheetを起動するたびに実行する必要がある # 忘れるとエラーが出る # 絶対忘れるという人や毎回実行するのが面倒だという人は既に実習済みの .Rprofile に書き加えることを強く勧める # 読み込みは read_excel() 関数を利用する # 引数として読み込みたいExcelファイルを指定 data3=read_excel("batting-average.xls") # なおブック形式(複数のシートがある場合)はシートを指定することで一部のシートだけを読み込むことも可能 read_excel("batting-average.xls", sheet=1) # sheet はシート名を文字列で与えてもよいし,上記の例のように先頭からの順番を数値で与えてもよい # 引数 range で指定して,一部のセルの範囲だけを読み込むことも可能 read_excel("batting-average.xls", range="a2:c5", col_names=F) # 重要:ただしセル範囲にヘッダが含まれないときは,ヘッダを含んでいないことを col_names=F で指定する必要がある # インターネット(HTMLファイル)の表データからの入力 ---- # XMLパッケージを使ったウェブに公開されている表の取り込み # 読み込みに利用する関数 readHTMLtable() を使用するためには,先ほどと同様追加でパッケージをインストールする必要 install.packages("XML") # インストール完了後にパッケージを読み込み library("XML") # 注意:library("XML") はRStudioを立ち上げるたび毎回実行する必要あり # 面倒なら .Rprofile に書き加えるとよい # これで使用する準備が完了 # # 例えば阪神タイガースのサイトから打撃成績を読み込んでみる # http://hanshintigers.jp/game/stats_team/bat27.html readHTMLTable("http://hanshintigers.jp/game/stats_team/bat27.html") # 重要:通信路での暗号化を行うSSLに対応したhttps://から始まるサイトについては,おそらく次のような # named list() # Warning message: # XML content does not seem to be XML: '' # というエラーメッセージが表示される. # その場合は,「警告メッセージが出てうまく読み込めないとき」の方法を利用するとよい # Tips: ちなみに,余計なことを考えずに「警告メッセージが出てうまく読み込めないとき」の方法を最初から利用した方が楽だと思う # ヘッダの細工(必要な場合のみ) ---- # 注意:readHTMLTableのバージョンアップでほぼ直っているようなので今は読み飛ばしてください # 将来もし遭遇した時に戻って読んでください # Webから読み込んだときにヘッダ部分が運悪く文字化けした場合の対処方法 # どうもtableタグでtheadタグを使って列見出しをマークアップすると,取り込みの時の文字コードの指定が有効にならずに,OSデフォルトのsjisで取り込んでしまっていた(readHTMLTableのバグで現在は直っているみたい) # この場合はひとまずヘッダ付きで読み込む # ヘッダはutf8でなくsjisで読み込まれているので,iconv()というコマンドで書き直してやる # 実際に文字化けしたら「取り込んだ表のデータフレーム」を取り込み使った変数名に置き換える # iconv() 関数の1つ目の引数は変数,2つ目は変換後の文字コード(この場合utf8),3つ目は変換前の文字コード(この場合はsjis) # colnames(取り込んだ表のデータフレーム)=iconv(colnames(取り込んだ表のデータフレーム), "utf8", "sjis") # ただしこの方法を使うときは必ず列名が表示されることを colnames() であらかじめ確認すること # caption付きの表の取り扱い ---- # captionタグで表にタイトルがついているときは,names 属性つきのlist型として取り込まれる(第1要素が取り込んだ表のデータフレーム)ので,オブジェクト名$タイトルがデータフレームとなる # 例えば http://www.sip-ac.jp/sip/konan_text/mis06-05.html の場合,マトリクス図法の一例というタイトルがついている data4a=readHTMLTable("http://www.sip-ac.jp/sip/konan_text/mis06-05.html", header = T, fileEncoding="utf8",colClasses = c(rep("character",4))) # data4a は list型になっている class(data4a) data4a$マトリクス図法の一例 class(data4a$マトリクス図法の一例) # 例えば守備のデータを利用しようとすると下記のように$を2つ使って指定しなければならないため煩瑣 data4a$マトリクス図法の一例$守備 # そのためデータフレーム部分をオブジェクトに再代入してやるとよい data4a = data4a$マトリクス図法の一例 class(data4a) # 警告メッセージが出てうまく読み込めないとき ---- # 上で例に用いたサイト https://hanshintigers.jp/game/stats_team/bat27.html は上で説明したやり方だとうまくいかない # 2019年度の前期は少なくとも読み込めた(サイト側の変更で読めなくなることもある) # このような場合は次のようなやり方で回避可能である # まず RCurl パッケージをインストールする install.packages("RCurl") # ネットの状況にもよるがしばらく時間がかかるのでいつも通り放置 # インストールが完了したら利用可能にする library("RCurl") # これは RCurl を利用する時に必ず必要(Worksheetを開いた時に必ず実行する必要あり) # getURL() を使ってコンテンツを取り込む.このとき .encoding に文字コードを指定しないと文字化けする # 今取り込もうとしているタイガースのサイトはUTF-8になる .encoding="UTF-8" # 最近はUTF-8が利用されることが多いが,サイトごとに異なるので確認する必要がある # データを取り込もうとしているWebページのソースを表示すれば,上の方に文字コードの指定がある # オブジェクト urldata に"https://hanshintigers.jp/game/stats_team/bat27.html"のコンテンツを代入している urldata = getURL("https://hanshintigers.jp/game/stats_team/bat27.html", .encoding="UTF-8") # そして先に説明した readHTMLTable() を次のように利用する # 1つ目の引数にはURLではなくgetURL()関数で取り込んだオブジェクトを指定 # RStudio.CloudやMacの場合はもともとUTF8なので header = T で読み込めば,1行目をヘッダとして取り込む data5 = readHTMLTable(urldata, fileEncoding="utf8", header = T, stringAsFactor=F, colClasses = c(rep("character",2),rep("numeric",19)), which = 1) # タイガースの打撃成績のページには表が3つあるので,which で1つ目の表を指定 which=1 # 上の例の fileEncoding="utf8" の部分は,読み込もうとするhtmlのソースファイルの文字コードに依存 # ソースを表示させて先頭の方に文字コードの指定があるのでそれにあわせればよい # データフレームの列の方を指定する colClasses は読み込むデータの列ごとの型を順に指定するための引数をベクトルで与える # 省略してもうまく読むことが多いが指定した方が確実 # "character"が文字,"numeric"が数値(整数,実数) # この例での colClass の指定は,1列目の背番号は文字型として取り込みたいので,2列目の選手名とともに文字型として指定 rep("character",2),それ以外の19列は数値型 rep("numeric",19) # rep() 関数を使うとスマートに書ける # 列のデータを利用する場合は data5[[5]] # [ が2重になるところに注意 # 5列1行目なら data5[[5]][1] # それでも警告メッセージが出てうまく読み込めないとき ---- # 次のサイト https://baseball.yahoo.co.jp/npb/stats/batter?gameKindId=1&type=avg は上で説明したやり方だと # 例えば次のような警告メッセージが出てうまく読み込めない # readHTMLTable("https://baseball.yahoo.co.jp/npb/stats/batter?gameKindId=1&type=avg") だと # named list() # Warning message: # XML content does not seem to be XML: ' ' # # readHTMLTable(getURL("https://baseball.yahoo.co.jp/npb/stats/batter?gameKindId=1&type=avg", .encoding = "UTF-8")) だと # データフレームとしては取り込めるものの日本語が文字化けで使い物にならない # # 取り込みにくくしている原因の1つには,最初の3列のヘッダー部分が統合されて,本来のヘッダーとしての意味をなしていないことがある # 本来的な意味では,1列目は「順位」,順に「選手名」,「チーム」となるべきである # いつ現在の情報かなどは,表の外に表示すべきである # # この場合は一旦読み込みたいページのソースファイルを自分のPCに保存する(htmlのソースファイルだけでよい) # その保存したファイルを読み込んでやればよい # ただしRStudio Cloudの場合は,ローカルのPCに保存してそれをアップロードする必要があるのでけっこう面倒 # # 別の方法は scan() を利用して,読み込むデータの型を適切にしてしてコピペするとデータフレームとして読み込める # 前準備としてデータフレームの列名が必要となるので別途整形しておく # この場合, # 順位,選手名,チーム,打率,試合,打席,打数,安打,二塁打,三塁打,本塁打,塁打,打点,得点,三振,四球,死球,犠打,犠飛,盗塁,併殺打,出塁率,長打率,OPS,得点圏,失策 # このうち,選手名とチームは文字列でその他は数値で読み込んでやればよい # 列のデータ型の指定は,例えば 選手名="" や 打率=numeric(0) としてやるとそれぞれ文字列,数値として認識してくれる # ポイント:文字型の場合は単に「列名=""」,数値型の場合は「列名=numeric(0)」 # これを並べるので list() を使って what=list( ) のように指定する # ポイント:what 引数を指定すると取り込む際の列名と型が指定可能 # このサイトの場合は,選手名とチームが文字型で,その他は数値型のため以下のような設定になる # what=list(順位=numeric(0),選手名="",チーム="",打率=numeric(0),試合=numeric(0),打席=numeric(0),打数=numeric(0),安打=numeric(0),二塁打=numeric(0),三塁打=numeric(0),本塁打=numeric(0),塁打=numeric(0),打点=numeric(0),得点=numeric(0),三振=numeric(0),四球=numeric(0),死球=numeric(0),犠打=numeric(0),犠飛=numeric(0),盗塁=numeric(0),併殺打=numeric(0),出塁率=numeric(0),長打率=numeric(0),OPS=numeric(0),得点圏=numeric(0),失策=numeric(0)) # まず表をヘッダを除いてデータのところだけ(1のところから表の下の列名の上のデータの部分だけ)選択してコピーしてから,ファイルに一旦保存してそれを読み込む方法を使う # # 重要:シーズン開幕当初は一部の列のデータが算出できないために,半角のマイナス(ハイフン)が使われている場合がある # 例えば得点圏は該当することが多い # そのときは,その行(選手)を含まない範囲を選択してコピーしないとエラーとなるので注意すること # # ここでは先ほど同じファイルclipboard001.txtにコピー(ただし先に保存されている内容はコピー前に削除する) data5a=scan("clipboard001.txt", sep = "\t", what=list(順位=numeric(0),選手名="",チーム="",打率=numeric(0),試合=numeric(0),打席=numeric(0),打数=numeric(0),安打=numeric(0),二塁打=numeric(0),三塁打=numeric(0),本塁打=numeric(0),塁打=numeric(0),打点=numeric(0),得点=numeric(0),三振=numeric(0),四球=numeric(0),死球=numeric(0),犠打=numeric(0),犠飛=numeric(0),盗塁=numeric(0),盗塁死=numeric(0),併殺打=numeric(0),出塁率=numeric(0),長打率=numeric(0),OPS=numeric(0),得点圏=numeric(0),失策=numeric(0))) # 上記のやり方でよいように思えるが,実際に実行するとエラーを起こす # これは1列目の順位の後ろにタブが入った上に改行コードが入っているため,空欄の行が存在するため # 手で改行かあるいはタブを取り除くこともできるが,ここではダミー(列名:空欄1)を使って読み込む方が楽 data5a=scan("clipboard001.txt", sep = "\t", what=list(順位=numeric(0),空欄1="",選手名="",チーム="",打率=numeric(0),試合=numeric(0),打席=numeric(0),打数=numeric(0),安打=numeric(0),二塁打=numeric(0),三塁打=numeric(0),本塁打=numeric(0),塁打=numeric(0),打点=numeric(0),得点=numeric(0),三振=numeric(0),四球=numeric(0),死球=numeric(0),犠打=numeric(0),犠飛=numeric(0),盗塁=numeric(0),盗塁死=numeric(0),併殺打=numeric(0),出塁率=numeric(0),長打率=numeric(0),OPS=numeric(0),得点圏=numeric(0),失策=numeric(0))) # ここでは,インターネット上のデータを読み込む際にはいろいろと食う付する必要があることを感じてもらえばよい # なお,この方法でデータを読み込んだ場合,データフレームではなくリストとして取り込まれる. # オブジェクトの型を調べるためには class() コマンドを利用すればよい(既出) class(data5a) # そのため,次のコマンドでデータフレームに変換しておいた方が使い勝手がよい data5a = data.frame(data5a) # あるいは data5a = as.data.frame(data5a) class(data5a) # ファイルの出力 ---- # Rのデータフレームをファイルに出力するときには write.csv や write.table を利用する # file で出力ファイル名を指定する(省略不可) # append =T の指定がなければ,既にファイルが存在しているときは上書き保存される(省略時は append = T) write.csv(data2,file = "ba.txt", quote = F, row.names = F, fileEncoding = "utf8") write.table(data2,file = "ba2.txt", quote = F, row.names = F, fileEncoding = "utf8") # なお write.csv の区切り記号は半角のカンマ,write.table の区切り記号はタブになる # 変更したい場合は sep = "\t" のように指定すればよい # 出力ファイルの拡張子は"ba.csv"のように csv でも可 # オブジェクトの保存と読込 ---- # 単独のデータフレームだけでなく,複数のオブジェクトを保存することもできる. # 作業を中断して,後日再開する場合などに便利 # このときは save() を利用するとよい # file = で保存するファイル名を指定する # file より前に保存したいオブジェクトを半角カンマで区切って列挙 save(data2, file = "my1.RData") rm(data2) # 試しに一旦 data2 を削除 data2 # 保存したオブジェクトを読み込むときは load() を利用する # 引数には保存した RData ファイル名を書く load("my1.RData") data2 # 一部のオブジェクトだけでなくすべてのオブジェクトを保存する場合には save.image() を利用する save.image() # save.image() で引数を指定しない場合は .RData というファイルに保存されるが,自分で名前を付けて保存したい場合には file で指定する save.image(file = "my2.RData") # rm() の引数として list = ls() とすると全オブジェクトを消去できる rm(list = ls()) # save.image() は引数を指定していない場合は自動的に .RData というファイル名で保存しているので,それを load() で読み込む load(".RData") # なお名前を自分で付けた場合は名前を指定する必要がある load("my2.RData")