Chapter 9 寫一段下載數據集的耙蟲
9.1 續
作者小編在旭、續、序這麼說過,
運氣不錯,R確實收集了一個名為「Boston」的數據集。
這是作者小編幾年來,講授統計程式語言R的經驗值。既然是個人的經驗值,表示「一定有盲點」。為了確認這個盲點有多大,作者小編請「Google Search」幫忙,在輸入框給了以下這一句英文
what packages have BOSTON dataset in r
Google Search接到這一段「英文字」之後,會進行「搜尋」,跟「what packages have BOSTON dataset in r
」「最吻合」的十個頁面摘要會出現在第一頁。經過作者小編耐心、細心、順心看過一輪之後,發現幾個套件收錄了「波士頓數據集」:
那怎麼樣才能「拿到」波士頓數據集呢?
9.3 載入R的波士頓數據集
在剛剛搜尋結果的前十名網頁裡,有一頁是
How do i load data set part of the MASS library in R?
這是STACK OVERFLOW的「問答頁」,作者小編的經驗值(依舊可能有盲點、可能有其他更好的問答頁),點進去,如果發現有「綠色勾勾」,表示「有經過問者或是網友、訪者驗證過的答案」,對一般剛入門R的讀者諸君絕對值得把答案的參考碼帶走,帶回自己的環境驗證一下「合不合用」:
library(MASS)
data(Boston)
head(Boston)
## crim zn indus chas nox rm age dis rad tax ptratio black lstat
## 1 0.00632 18 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98
## 2 0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14
## 3 0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03
## 4 0.03237 0 2.18 0 0.458 6.998 45.8 6.0622 3 222 18.7 394.63 2.94
## 5 0.06905 0 2.18 0 0.458 7.147 54.2 6.0622 3 222 18.7 396.90 5.33
## 6 0.02985 0 2.18 0 0.458 6.430 58.7 6.0622 3 222 18.7 394.12 5.21
## medv
## 1 24.0
## 2 21.6
## 3 34.7
## 4 33.4
## 5 36.2
## 6 28.7
看到上面這一張表,表示我們成功了,成功載入計算環境,讓環境擁有「Boston
」這個數據集。但是,這三句話到底是什麼意思呢?經過作者小編再一次徵詢Google Search,以下問題
- what is library in r
- what is data in r
- what is head in r
得知,發現
- 「
library
」可以「Loading/Attaching And Listing Of Packages」。 - 「
data
」可以「Loads specified data sets, or list the available data sets.」。 - 「
head
」可以「Return The First Or Last Part Of An Object」。
意思是說:
第二句話「
data(Boston)
」,讓我們請R載入「Boston
」這個名字的數據集。
第三句話「
head(Boston)
」,讓我們顯示「Boston
」這個數據集的前六筆觀察值。
9.4 直接從網際網路抓到波士頓數據集
在第二個套件mlbench提供的文件裡,我們發現有一節叫做「Source
」,記載著波士頓數據集的網路位置:
The original data have been taken from the UCI Repository Of Machine Learning Databases at
the corrected data have been taken from Statlib at
Both were converted to R format by
Friedrich.Leisch@ci.tuwien.ac.at
.
當作者小編試著點出第一個網址,
失敗!
再點第二個網址,進入
::include_url("http://lib.stat.cmu.edu/datasets/") knitr
…
這是一個「數據集封存(資料)庫(Datasets Archive)」,它的名字叫做「StatLib」。這一個資料庫的維護人,是一位卡內基梅隆大學統計系的研究員,「Pantelis Vlachos」。「Pantelis Vlachos」在1998年(作者小編拿到博士學位的西元年)接手「Mike Meyer」在1989年創立的「StatLib」。接下來,讀者諸君、作者小編不是「用眼睛」往下慢慢找,要不然就是用「control + F
」喚出「Google Chrome」搜尋框,然後輸入「boston」,就會找到波士頓數據集的link
「http://lib.stat.cmu.edu/datasets/boston」以及一段簡介
The Boston house-price data of Harrison, D. and Rubinfeld, D.L. ‘Hedonic prices and the demand for clean air’, J. Environ. Economics & Management, vol.5, 81-102, 1978. Used in Belsley, Kuh & Welsch, ‘Regression diagnostics …’, Wiley, 1980. (51256 bytes)
9.4.1 找到波士頓數據集所在的網頁
拷貝上面的網址(link)到下面這一句話的「小括號」內,就可以在作者小編的網頁「刊入」他人、網友允許「被刊入」的網頁。
::include_url("http://lib.stat.cmu.edu/datasets/boston") knitr
…
接下來,
怎麼讀取
http://lib.stat.cmu.edu/datasets/boston
的網路檔案,並且取得數據呢?
同樣的,沒辦法就上Google Search找辦法。作者小編在搜尋框輸入
how to read online data in r
跟之前的經驗一模一樣,Google Search給十個參考網頁,說實在的,作者小編「線外努力」一陣子之後,發現第十個頁面提供的答案對初學R的讀者諸君最容易,
# Reading Data From TXT|CSV Files: R Base Functions
::include_url("http://www.sthda.com/english/wiki/reading-data-from-txt-csv-files-r-base-functions") knitr
…
因為對方拒絕連線,請讀者諸君點開這裏,往下看會看到這一段「Reading a file from internet」。
…
9.4.2 引用read.delim
讀取網路上的波士頓數據集
拷貝STHDA在「Reading a file from internet」提供的參考碼:
<- read.delim("http://www.sthda.com/upload/boxplot_format.txt")
my_data head(my_data)
改成
<- read.delim("http://lib.stat.cmu.edu/datasets/boston")
x head(x)
## The.Boston.house.price.data.of.Harrison..D..and.Rubinfeld..D.L...Hedonic
## 1 prices and the demand for clean air', J. Environ. Economics & Management,
## 2 vol.5, 81-102, 1978. Used in Belsley, Kuh & Welsch, 'Regression diagnostics
## 3 ...', Wiley, 1980. N.B. Various transformations are used in the table on
## 4 pages 244-261 of the latter.
## 5 Variables in order:
## 6 CRIM per capita crime rate by town
觀察上述畫面,發現什麼呢?
程式「read.delim
」把網頁前頭的數據集說明也一起讀進來了,再看一次波士頓數據集所在的原始頁面:
::include_url("http://lib.stat.cmu.edu/datasets/boston") knitr
作者小編認真地「數」過一次,發現該網頁的第二十一列(由左往右算,但不含空白列)才開始有數字,而且似乎「每一筆都被切成兩列」。於是乎,作者小編試試以下的程式碼:
# 因為有一行被放在表頭的欄位名稱那裡,所以只要減去19行。
<- x[-(1:19),,drop = FALSE]
x rownames(x) <- 1:dim(x)[1]
colnames(x) <- "Boston"
head(x, 3)
## Boston
## 1 0.00632 18.00 2.310 0 0.5380 6.5750 65.20 4.0900 1 296.0 15.30
## 2 396.90 4.98 24.00
## 3 0.02731 0.00 7.070 0 0.4690 6.4210 78.90 4.9671 2 242.0 17.80
檢查網頁上的第一個數字確實是0.00632
。再數一數第一列跟第二列總共有幾個數字?我們會發現確實是14個,所以作者小編到目前為止提供的程式碼,並無法如套件MASS
那樣,把14個數字放在14的欄位裡,而是這14個數字被切成「11 + 3
」放在一個欄位裡。好消息是作者小編把說明文字的「欄位名稱」換成「Boston
」。一大堆數字被放在一個「格子(一列加一欄)」裡,看似數字,所以作者小編檢查一下
class(x[,"Boston"])
## [1] "character"
對初學者而言,character是需要一點時間才能理出頭緒來的,請讀者諸君如果願意,先前進factor參考到底什麼是「character」?
一格一堆數字,絕對不是「數字」,那就只好是「文字」了!
"Boston"] <- as.character(x[,"Boston"])
x[,class(x[,"Boston"])
## [1] "character"
head(x, 3)
## Boston
## 1 0.00632 18.00 2.310 0 0.5380 6.5750 65.20 4.0900 1 296.0 15.30
## 2 396.90 4.98 24.00
## 3 0.02731 0.00 7.070 0 0.4690 6.4210 78.90 4.9671 2 242.0 17.80
上下兩張表,看起來一模一樣,這就是「factor
」的魅力所在。讀者諸君一定要前進factor,關注、欣賞「factor
」的魅力到底在哪裡?看過「表頭(head
)」接下來,看一下「表尾(tail
)」,
tail(x, 3)
## Boston
## 1010 393.45 6.48 22.00
## 1011 0.04741 0.00 11.930 0 0.5730 6.0300 80.80 2.5050 1 273.0 21.00
## 1012 396.90 7.88 11.90
發現「read.delim
」確實抓到「1012/2 = 506
」筆觀察值。為了得到14個欄位,我們得先把分成兩列的文字「接」成一列:
paste(x[1,1], x[2,1])
## [1] " 0.00632 18.00 2.310 0 0.5380 6.5750 65.20 4.0900 1 296.0 15.30 396.90 4.98 24.00"
9.4.3 把一串文字內的全部數字通通抓來
現在全部14數字被擺在「一串文字」內,假如我們有辦法通通把它們抓出來、分開來,我們就又接近MASS
的Boston
一步了。為此,我們需要以下這支小程式:
<- function(string){
Numextract unlist(regmatches(string,
gregexpr("[[:digit:]]+\\.*[[:digit:]]*",
string)
)
) }
作者小編暫時「不解釋」這支程式,請讀者諸君繼續看作者小編怎麼用?
Numextract(paste(x[1,1], x[2,1]))
## [1] "0.00632" "18.00" "2.310" "0" "0.5380" "6.5750" "65.20"
## [8] "4.0900" "1" "296.0" "15.30" "396.90" "4.98" "24.00"
as.numeric(Numextract(paste(x[1,1], x[2,1])))
## [1] 0.00632 18.00000 2.31000 0.00000 0.53800 6.57500 65.20000
## [8] 4.09000 1.00000 296.00000 15.30000 396.90000 4.98000 24.00000
就三個動作:
- 接起來,「
paste
」。 - 抓出來,「
Numextract
」。 - 變回來,「
as.numeric
」。
所以重複同樣的動作506次,就可以抓到整個「Boston Housing Price」數據集!
9.4.4 如何重複某一組動作很多遍呢?
一開始,paste(x[1,1], x[2,1])
,「1
」在前、「2
」在後。那如果可以「配對」,以下這兩句話可以產生一連串、連續的奇數跟偶數,
seq(1,dim(x)[1],2)
## [1] 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29
## [16] 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59
## [31] 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89
## [46] 91 93 95 97 99 101 103 105 107 109 111 113 115 117 119
## [61] 121 123 125 127 129 131 133 135 137 139 141 143 145 147 149
## [76] 151 153 155 157 159 161 163 165 167 169 171 173 175 177 179
## [91] 181 183 185 187 189 191 193 195 197 199 201 203 205 207 209
## [106] 211 213 215 217 219 221 223 225 227 229 231 233 235 237 239
## [121] 241 243 245 247 249 251 253 255 257 259 261 263 265 267 269
## [136] 271 273 275 277 279 281 283 285 287 289 291 293 295 297 299
## [151] 301 303 305 307 309 311 313 315 317 319 321 323 325 327 329
## [166] 331 333 335 337 339 341 343 345 347 349 351 353 355 357 359
## [181] 361 363 365 367 369 371 373 375 377 379 381 383 385 387 389
## [196] 391 393 395 397 399 401 403 405 407 409 411 413 415 417 419
## [211] 421 423 425 427 429 431 433 435 437 439 441 443 445 447 449
## [226] 451 453 455 457 459 461 463 465 467 469 471 473 475 477 479
## [241] 481 483 485 487 489 491 493 495 497 499 501 503 505 507 509
## [256] 511 513 515 517 519 521 523 525 527 529 531 533 535 537 539
## [271] 541 543 545 547 549 551 553 555 557 559 561 563 565 567 569
## [286] 571 573 575 577 579 581 583 585 587 589 591 593 595 597 599
## [301] 601 603 605 607 609 611 613 615 617 619 621 623 625 627 629
## [316] 631 633 635 637 639 641 643 645 647 649 651 653 655 657 659
## [331] 661 663 665 667 669 671 673 675 677 679 681 683 685 687 689
## [346] 691 693 695 697 699 701 703 705 707 709 711 713 715 717 719
## [361] 721 723 725 727 729 731 733 735 737 739 741 743 745 747 749
## [376] 751 753 755 757 759 761 763 765 767 769 771 773 775 777 779
## [391] 781 783 785 787 789 791 793 795 797 799 801 803 805 807 809
## [406] 811 813 815 817 819 821 823 825 827 829 831 833 835 837 839
## [421] 841 843 845 847 849 851 853 855 857 859 861 863 865 867 869
## [436] 871 873 875 877 879 881 883 885 887 889 891 893 895 897 899
## [451] 901 903 905 907 909 911 913 915 917 919 921 923 925 927 929
## [466] 931 933 935 937 939 941 943 945 947 949 951 953 955 957 959
## [481] 961 963 965 967 969 971 973 975 977 979 981 983 985 987 989
## [496] 991 993 995 997 999 1001 1003 1005 1007 1009 1011
seq(2,dim(x)[1],2)
## [1] 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
## [16] 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60
## [31] 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90
## [46] 92 94 96 98 100 102 104 106 108 110 112 114 116 118 120
## [61] 122 124 126 128 130 132 134 136 138 140 142 144 146 148 150
## [76] 152 154 156 158 160 162 164 166 168 170 172 174 176 178 180
## [91] 182 184 186 188 190 192 194 196 198 200 202 204 206 208 210
## [106] 212 214 216 218 220 222 224 226 228 230 232 234 236 238 240
## [121] 242 244 246 248 250 252 254 256 258 260 262 264 266 268 270
## [136] 272 274 276 278 280 282 284 286 288 290 292 294 296 298 300
## [151] 302 304 306 308 310 312 314 316 318 320 322 324 326 328 330
## [166] 332 334 336 338 340 342 344 346 348 350 352 354 356 358 360
## [181] 362 364 366 368 370 372 374 376 378 380 382 384 386 388 390
## [196] 392 394 396 398 400 402 404 406 408 410 412 414 416 418 420
## [211] 422 424 426 428 430 432 434 436 438 440 442 444 446 448 450
## [226] 452 454 456 458 460 462 464 466 468 470 472 474 476 478 480
## [241] 482 484 486 488 490 492 494 496 498 500 502 504 506 508 510
## [256] 512 514 516 518 520 522 524 526 528 530 532 534 536 538 540
## [271] 542 544 546 548 550 552 554 556 558 560 562 564 566 568 570
## [286] 572 574 576 578 580 582 584 586 588 590 592 594 596 598 600
## [301] 602 604 606 608 610 612 614 616 618 620 622 624 626 628 630
## [316] 632 634 636 638 640 642 644 646 648 650 652 654 656 658 660
## [331] 662 664 666 668 670 672 674 676 678 680 682 684 686 688 690
## [346] 692 694 696 698 700 702 704 706 708 710 712 714 716 718 720
## [361] 722 724 726 728 730 732 734 736 738 740 742 744 746 748 750
## [376] 752 754 756 758 760 762 764 766 768 770 772 774 776 778 780
## [391] 782 784 786 788 790 792 794 796 798 800 802 804 806 808 810
## [406] 812 814 816 818 820 822 824 826 828 830 832 834 836 838 840
## [421] 842 844 846 848 850 852 854 856 858 860 862 864 866 868 870
## [436] 872 874 876 878 880 882 884 886 888 890 892 894 896 898 900
## [451] 902 904 906 908 910 912 914 916 918 920 922 924 926 928 930
## [466] 932 934 936 938 940 942 944 946 948 950 952 954 956 958 960
## [481] 962 964 966 968 970 972 974 976 978 980 982 984 986 988 990
## [496] 992 994 996 998 1000 1002 1004 1006 1008 1010 1012
上下對過之後,會發現確實「配對成功」。這樣擺更容易看,即便只看表頭的六組:
head(data.frame(前 = seq(1,dim(x)[1],2), 後 = seq(2,dim(x)[1],2)))
## 前 後
## 1 1 2
## 2 3 4
## 3 5 6
## 4 7 8
## 5 9 10
## 6 11 12
有了這樣的「配對關係」,R就可以幫我們這一組動作許多次了:
- 接起來,「
paste
」。 - 抓出來,「
Numextract
」。 - 變回來,「
as.numeric
」。
<- as.numeric(
x Numextract(
paste(x[seq(1,dim(x)[1],2),1], x[seq(2,dim(x)[1],2),1])
)
)head(x, 14)
## [1] 0.00632 18.00000 2.31000 0.00000 0.53800 6.57500 65.20000
## [8] 4.09000 1.00000 296.00000 15.30000 396.90000 4.98000 24.00000
tail(x, 14)
## [1] 0.04741 0.00000 11.93000 0.00000 0.57300 6.03000 80.80000
## [8] 2.50500 1.00000 273.00000 21.00000 396.90000 7.88000 11.90000
9.4.5 把全部數字放在矩陣裡
我們有了全部的數字,觀察上述R的「輸出」之後,也發現每一筆觀察值的14個數字依序出現、擺放,加上我們知道波士頓數據集收錄了14個欄位,所以根據矩陣的原理跟原則以及R對矩陣的支持、支援,以下的第一句話可以把「x
」內的全部數字依序從左而右擺成一張「506 x 14
」的矩陣:
<- matrix(x, ncol = 14, byrow = TRUE)
boston head(boston, 3)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
## [1,] 0.00632 18 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90
## [2,] 0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90
## [3,] 0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83
## [,13] [,14]
## [1,] 4.98 24.0
## [2,] 9.14 21.6
## [3,] 4.03 34.7
再一次呼叫原始網頁,讓我們再一次核對彼此的數字與出現順序:
::include_url("http://lib.stat.cmu.edu/datasets/boston") knitr
…
9.4.6 抓取波士頓數據集的欄位名稱
再抓一次原始檔案,並且觀察欄位相關資訊在哪裏?
<- read.delim("http://lib.stat.cmu.edu/datasets/boston")
x head(x, 21)
## The.Boston.house.price.data.of.Harrison..D..and.Rubinfeld..D.L...Hedonic
## 1 prices and the demand for clean air', J. Environ. Economics & Management,
## 2 vol.5, 81-102, 1978. Used in Belsley, Kuh & Welsch, 'Regression diagnostics
## 3 ...', Wiley, 1980. N.B. Various transformations are used in the table on
## 4 pages 244-261 of the latter.
## 5 Variables in order:
## 6 CRIM per capita crime rate by town
## 7 ZN proportion of residential land zoned for lots over 25,000 sq.ft.
## 8 INDUS proportion of non-retail business acres per town
## 9 CHAS Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)
## 10 NOX nitric oxides concentration (parts per 10 million)
## 11 RM average number of rooms per dwelling
## 12 AGE proportion of owner-occupied units built prior to 1940
## 13 DIS weighted distances to five Boston employment centres
## 14 RAD index of accessibility to radial highways
## 15 TAX full-value property-tax rate per $10,000
## 16 PTRATIO pupil-teacher ratio by town
## 17 B 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
## 18 LSTAT % lower status of the population
## 19 MEDV Median value of owner-occupied homes in $1000's
## 20 0.00632 18.00 2.310 0 0.5380 6.5750 65.20 4.0900 1 296.0 15.30
## 21 396.90 4.98 24.00
請讀者諸君現在跟畫面互動、互動,數一數欄位名稱位於哪幾列?加上我們已經知道「read.delim
」會給我們「factor
」的「x
」,所以照例
- 取出「
x
」的那一段(各位剛剛數出來的結果)、 - 強迫變成「文字(
as.character
)」、 - 把結果丟給(
<-
)「colsBoston
」,「colsBoston
」自取,但是讀者諸君在關鍵時刻要取對、取好「名字
」,除了練習取名字,也學英文,也學溝通,請讀者諸君慎思!
<- as.character(x[6:19,])
colsBoston colsBoston
## [1] " CRIM per capita crime rate by town"
## [2] " ZN proportion of residential land zoned for lots over 25,000 sq.ft."
## [3] " INDUS proportion of non-retail business acres per town"
## [4] " CHAS Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)"
## [5] " NOX nitric oxides concentration (parts per 10 million)"
## [6] " RM average number of rooms per dwelling"
## [7] " AGE proportion of owner-occupied units built prior to 1940"
## [8] " DIS weighted distances to five Boston employment centres"
## [9] " RAD index of accessibility to radial highways"
## [10] " TAX full-value property-tax rate per $10,000"
## [11] " PTRATIO pupil-teacher ratio by town"
## [12] " B 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town"
## [13] " LSTAT % lower status of the population"
## [14] " MEDV Median value of owner-occupied homes in $1000's"
<- colsBoston # 留個備份,方便師長後續講解。 colsBostonFull
抓一個來好好瞧瞧,
1] colsBoston[
## [1] " CRIM per capita crime rate by town"
一開始是「CRIM
」,接下來「一段空白」,再來是「一句英文」,
per capita crime rate by town
應該是「波士頓數據集的主人、擁有者或是編輯者」試著解釋什麼是「CRIM
」,一般我們會說是「欄位說明」,而「CRIM
」是「欄位名稱」,其中「欄位」是統計學的「變數
」,所以「欄位名稱」是「變數名稱
」。回憶一下,之前我們
- 接起來,「
paste
」。 - 抓出來,「
Numextract
」。 - 變回來,「
as.numeric
」。
一樣是「一串文字」,但是現在「不是數字問題」,純粹是「文字問題」。如果我們可以「抓到CRIM
」,再重複14次,我們就成功了!先「拆字」,
strsplit(colsBoston[1], " ")
## [[1]]
## [1] "" "CRIM" "" "" "" "" "per" "capita"
## [9] "crime" "rate" "by" "town"
再看第二條「文字串」,
strsplit(colsBoston[2], " ")
## [[1]]
## [1] "" "ZN" "" "" ""
## [6] "" "" "" "proportion" "of"
## [11] "residential" "land" "zoned" "for" "lots"
## [16] "over" "25,000" "sq.ft."
為了強化猜測與信心,我們再看第三條「文字串」,
strsplit(colsBoston[3], " ")
## [[1]]
## [1] "" "INDUS" "" "" ""
## [6] "proportion" "of" "non-retail" "business" "acres"
## [11] "per" "town"
「觀察」過後,我們發現「欄位名稱」,也就是「變數名稱」,出現在
[[1]]
""
之後。
怎麼「抓到它呢?」
strsplit(colsBoston[1], " ")
## [[1]]
## [1] "" "CRIM" "" "" "" "" "per" "capita"
## [9] "crime" "rate" "by" "town"
strsplit(colsBoston[1], " ")[[1]]
## [1] "" "CRIM" "" "" "" "" "per" "capita"
## [9] "crime" "rate" "by" "town"
strsplit(colsBoston[1], " ")[[1]][2]
## [1] "CRIM"
接下來,「重複」這些動作14次:
- 拆字,「
strsplit
」、 - 抓全部,「
[[1]]
」、 - 抓到它,「
[2]
」。
請看R的表演,用「迴圈」(sapply
)抓全部欄位名稱。
<- sapply(colsBoston, function(w){
colsBoston strsplit(w, " ")[[1]][2]
}) colsBoston
## CRIM per capita crime rate by town
## "CRIM"
## ZN proportion of residential land zoned for lots over 25,000 sq.ft.
## "ZN"
## INDUS proportion of non-retail business acres per town
## "INDUS"
## CHAS Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)
## "CHAS"
## NOX nitric oxides concentration (parts per 10 million)
## "NOX"
## RM average number of rooms per dwelling
## "RM"
## AGE proportion of owner-occupied units built prior to 1940
## "AGE"
## DIS weighted distances to five Boston employment centres
## "DIS"
## RAD index of accessibility to radial highways
## "RAD"
## TAX full-value property-tax rate per $10,000
## "TAX"
## PTRATIO pupil-teacher ratio by town
## "PTRATIO"
## B 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
## "B"
## LSTAT % lower status of the population
## "LSTAT"
## MEDV Median value of owner-occupied homes in $1000's
## "MEDV"
<- unname(colsBoston) # 無名化。
colsBoston colsBoston
## [1] "CRIM" "ZN" "INDUS" "CHAS" "NOX" "RM" "AGE"
## [8] "DIS" "RAD" "TAX" "PTRATIO" "B" "LSTAT" "MEDV"
大成功!
「sapply
」非常好用。如果讀者諸君想進一步「升級」,請參考以下的官方使用手冊:
::include_url("https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/lapply") knitr
…
9.4.7 把boston
變成data.frame
回顧到目前為止,「我們的boston
」長什麼樣子?
class(boston)
## [1] "matrix" "array"
也檢查「MASS
的Boston
」長什麼樣子?
class(MASS::Boston)
## [1] "data.frame"
把「我們的boston
」的樣子變成「MASS
的Boston
」的樣子:
<- as.data.frame(boston)
boston class(boston)
## [1] "data.frame"
繼續揭露「我們的boston
」跟「MASS
的Boston
」之間的「同」與「異」:
sum(dim(boston) == dim(MASS::Boston))
## [1] 2
sum(rownames(boston) == rownames(MASS::Boston))
## [1] 506
sum(colnames(boston) == colnames(MASS::Boston))
## [1] 0
最後的答案「0
」,意味著
「我們的
boston
」的「變數名稱」跟「MASS
的Boston
」的「變數名稱」,完全不一樣!
colnames(boston) # 這是R的傑作!
## [1] "V1" "V2" "V3" "V4" "V5" "V6" "V7" "V8" "V9" "V10" "V11" "V12"
## [13] "V13" "V14"
colnames(MASS::Boston) # 不再是大寫,而是小寫的變數名稱。
## [1] "crim" "zn" "indus" "chas" "nox" "rm" "age"
## [8] "dis" "rad" "tax" "ptratio" "black" "lstat" "medv"
我們這麼改:
colnames(boston) <- tolower(colsBoston)
head(boston, 3)
## crim zn indus chas nox rm age dis rad tax ptratio b lstat
## 1 0.00632 18 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98
## 2 0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14
## 3 0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03
## medv
## 1 24.0
## 2 21.6
## 3 34.7
head(MASS::Boston, 3)
## crim zn indus chas nox rm age dis rad tax ptratio black lstat
## 1 0.00632 18 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98
## 2 0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14
## 3 0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03
## medv
## 1 24.0
## 2 21.6
## 3 34.7
tail(boston, 3)
## crim zn indus chas nox rm age dis rad tax ptratio b lstat
## 504 0.06076 0 11.93 0 0.573 6.976 91.0 2.1675 1 273 21 396.90 5.64
## 505 0.10959 0 11.93 0 0.573 6.794 89.3 2.3889 1 273 21 393.45 6.48
## 506 0.04741 0 11.93 0 0.573 6.030 80.8 2.5050 1 273 21 396.90 7.88
## medv
## 504 23.9
## 505 22.0
## 506 11.9
tail(MASS::Boston, 3)
## crim zn indus chas nox rm age dis rad tax ptratio black lstat
## 504 0.06076 0 11.93 0 0.573 6.976 91.0 2.1675 1 273 21 396.90 5.64
## 505 0.10959 0 11.93 0 0.573 6.794 89.3 2.3889 1 273 21 393.45 6.48
## 506 0.04741 0 11.93 0 0.573 6.030 80.8 2.5050 1 273 21 396.90 7.88
## medv
## 504 23.9
## 505 22.0
## 506 11.9
請讀者諸君確認成果!
…
「差一點」一模一樣!
colnames(boston)[12] <- "black"
sum(colnames(boston) == colnames(MASS::Boston))
## [1] 14
最後再檢查一件事:
sapply(boston, class)
## crim zn indus chas nox rm age dis
## "numeric" "numeric" "numeric" "numeric" "numeric" "numeric" "numeric" "numeric"
## rad tax ptratio black lstat medv
## "numeric" "numeric" "numeric" "numeric" "numeric" "numeric"
sapply(MASS::Boston, class)
## crim zn indus chas nox rm age dis
## "numeric" "numeric" "numeric" "integer" "numeric" "numeric" "numeric" "numeric"
## rad tax ptratio black lstat medv
## "integer" "numeric" "numeric" "numeric" "numeric" "numeric"
再一次確認一件事,
「我們的
boston
」的「變數屬性(class
)」跟「MASS
的Boston
」的「變數屬性(class
)」,也「差兩點」完全一樣,不是「numeric
(實數型)」的變數,就是「integer
(整數型)」的變數!
"chas"] <- as.integer(boston[,"chas"])
boston[,"rad"] <- as.integer(boston[,"rad"])
boston[,sum(sapply(boston, class) == sapply(MASS::Boston, class))
## [1] 14
9.4.8 課堂練習
- 整理上述作者小編提供的程式碼,前進並且用R下載boston_corrected提供的數據集。這是波士頓數據集的完整版。
- 檢查前一題的成果,看是否跟套件「
spData
」(spData)抓到的「一模一樣」?
9.4.9 小結語
總整理整個「耙蟲」過程的程式碼,請注意「#
」之後的「註解」:
# 大步一:下載。
<- "http://lib.stat.cmu.edu/datasets/boston"
URL <- read.delim(URL)
x # 大步二:抓變數名稱。
<- as.character(x[6:19,])
colsBoston <- sapply(colsBoston, function(w){
colsBoston strsplit(w, " ")[[1]][2]
})<- unname(colsBoston)
colsBoston # 大步三:抓數字。
<- x[-(1:19),,drop = FALSE]
x rownames(x) <- 1:dim(x)[1]
colnames(x) <- "Boston"
### 當然我們需要先告訴R,如何從文字串取出眾多數字。
<- as.numeric(
x Numextract(
paste(x[seq(1,dim(x)[1],2),"Boston"], x[seq(2,dim(x)[1],2),"Boston"])
)
)<- matrix(x, ncol = 14, byrow = TRUE)
boston <- as.data.frame(boston)
boston ### 根據「MASS::Boston」的規則改變boston的變數名稱。
colnames(boston) <- tolower(colsBoston)
colnames(boston)[12] <- "black"
"chas"] <- as.integer(boston[,"chas"])
boston[,"rad"] <- as.integer(boston[,"rad"]) boston[,
最後,一定要,檢查成果:
sum(dim(boston) == dim(MASS::Boston))
## [1] 2
sum(rownames(boston) == rownames(MASS::Boston))
## [1] 506
sum(colnames(boston) == colnames(MASS::Boston))
## [1] 14
sum(sapply(boston, class) == sapply(MASS::Boston, class))
## [1] 14
sum(boston == MASS::Boston) == 14*506 # 一定要是「14 x 506」
## [1] TRUE
挑戰成功!
9.5 學期小專題
9.5.1 開啟專案暨引進專案管理
開啟:
FMsources
FMfinal
FMfun
等三個專案,其中「FMsources
」專職保留原始數據;「FMfinal
」專職個人期末報告;「FMfun
」專職任何學生個人有興趣的題目。以上這三個專案都是多變量分析這一門課的專案,為了可以跟其他課程區隔開來,通常我們會給多變量分析一個專用的檔案夾,所以在開啟上述三個專案之前,請先開啟
MVA
這一個檔案夾。然後,在這一個檔案夾底下開啟上述三個專案。一般而言,不管是哪一種企圖的專案,除非有更好的理由,作者小編都會開啟「Shiny Web Application」專案,因為
…
接下來,建置數個各司其職的檔案夾:
- data:放數據集。
- Rscript:放程式碼。
- output:
- output/data:放表、報表。
- output/figures:放圖。
- doc:放文件。
- www:放參考資料,諸如PDF檔案。
- UFO:這是垃圾桶。
我們可以手動完成以上全部「開啟」的動作,也可以在程式的協助下完成整個開啟任務。請參考以下作者小編的作法:
- 由於作者小編依靠一部「shiny server」開發各種程式,所以先手動在「ShinyApps」下手動開啟「MVA」檔案夾。
- 手動在「MVA」檔案夾之下,開啟第一個「Shiny Web Application」專案,「
FMsources
」。 - 手動在「MVA」檔案夾之下,開啟第二個「Shiny Web Application」專案,「
FMfinal
」。 - 手動在「MVA」檔案夾之下,開啟第三個「Shiny Web Application」專案,「
FMfun
」。 - 設定工作檔案夾。注意,必須根據個人現況或是個人習慣改掉「
~/ShinyApps
」。還有,不一樣的作業系統(OS,諸如,Windows 10, MacOS X, Linux, …),路徑寫法不盡相同。
setwd("~/ShinyApps/MVA")
- 開啟空白「
R Script
」,並且命名為「佈局MVA學生版.R
」。 - 然後,適當改寫以下程式碼,讓程式幫你完成剩下來的工作:
<- list.files("~/ShinyApps/MVA")
projects <- projects[-grep("佈局MVA學生版.R", projects)]
projects
for (i in 1:length(projects)) {
<- paste0("/home/fcu/ShinyApps/MVA",
DIR "/",
projects[i],"/",
"data")
if(!dir.exists(DIR)){
dir.create(DIR)
dir.create(sub("data", "Rscript", DIR))
dir.create(sub("data", "output", DIR))
dir.create(sub("data", "output/data", DIR))
dir.create(sub("data", "output/figures", DIR))
dir.create(sub("data", "doc", DIR))
dir.create(sub("data", "UFO", DIR))
dir.create(sub("data", "www", DIR))
<- sub("data", "app.R", DIR)
from <- sub("data", "UFO/app.R", DIR)
to file.copy(from = from, to = to)
file.remove(from)
}
}
- 順利成功之後,開啟、前進「
FMfinal
」專案。