ML for hackers 第一章笔记

本书的第一章并不像其他书的第一章,仅仅是简单的介绍本书,很多代码需要细细推敲。

  • 1.读入文件
    数据文件是制表符分割文件(.tsv),因此用read.delim()读取。
    每行的数据类型都是strings,没有表头。数据中有许多空元素,将它设置为NA
ufo <- read.delim("E:/ML/ufo_awesome.tsv",
                  sep = "\t",
                  stringsAsFactors = FALSE,
                  header = FALSE,
                  na.strings = "")
head(ufo)
# 数据框赋列名
names(ufo) <- c("DateOccurred","DateReported",
                "Location","ShortDescription",
                "Duration","LongDescription")
na.strings=""  --表示将空元素赋值为NA,注意引号中没有空格
  • 2.处理畸形格式的数据
    本数据集中的日期格式YYYYMMDD,所以日期型应该是8个字符串,因此需要移除不是8个字符的日期型观测。
# 先查看错误行
head(ufo[which(nchar(ufo$DateOccurred)!=8|nchar(ufo$DateReported)!=8),1])
# 向量化操作,移除畸变数据
good.rows <- ifelse(nchar(ufo$DateOccurred) != 8 |
                    nchar(ufo$DateReported) != 8,
                    FALSE,
                    TRUE)
length(which(!good.rows))
ufo <- ufo[good.rows,] 
# 修改日期格式
ufo$DateOccurred <- as.Date(ufo$DateOccurred,format = "%Y%m%d")
ufo$DateReported <- as.Date(ufo$DateReported,format = "%Y%m%d")
  • 3.逗号分隔符的清洗与处理
    地点数据的形式是“City,State”,要将它拆分成两列,并识别出不规范的数据行(挑出属于美国的数据)

    定义输入字符串的函数,执行数据清洗工作

get.location <- function(l){
  split.location <- tryCatch(strsplit(l,",")[[1]],
                             error = function(e) return(c(NA,NA)))
  clean.location <- gsub("^ ","",split.location)
  if(length(clean.location) > 2){
    return(c(NA,NA))
  }
  else {
    return(clean.location)
  }
}

strsplit()只要遇到字符串就自动处理,不会报错;只有input不是字符串时就才会出现异常,此时tryCatch()函数就会处理异常,返回两个NA;
当遇到有多个逗号的字符串,在检查向量的长度时,依然返回两个NA。
即tryCatch()函数处理输入的是非字符串,长度检验处理的是input带多个逗号的情况,还有一种情况,input没有逗号,此时只返回它本身,即只有一个元素,若把此结果放到矩阵中,就会报错(矩阵的元素不能为empty)

gsub() :R的正则表达式相关函数之一
^:匹配输入字符串开始的位置,程序中因为要删除第一个位置的空格所以要写成”^ “,注意要加空格。

lapply()对每个输入的字符串应用我们定义的函数,返回列表
city.state <- lapply(ufo$Location,get.location)
head(city.state)

思考?
city.state1 <- sapply(ufo$Location,get.location,simplify = “matrix”)
若用sapply()函数simplify成矩阵,会产生错误,见上分析。

这时已经有了一个列表city.state,每个子表的元素是 城市,州
将此列表并入原始数据框中,首先用do.call()函数,转换为矩阵,再加入到数据框中。

# 将较长的列表转换为一个两列的矩阵
location.matrix <- do.call(rbind,city.state)
# 将矩阵并入数据框
ufo <- transform(ufo,USCity = location.matrix[,1],
                 USState = tolower(location.matrix[,2]),
                 stringsAsFactors = FALSE)

tolower()把所有的州的名字的缩写都变成小写形式
transform(_data,…) …参数要被处理成数据框中的对象,即给数据框添加新列

下面再识别非美国的数据
处理非美国境内的数据,形式上符合”city.state”,但实际上并不在美国境内的数据

# 构造一个美国各州缩写的向量,用数据框中USState列数据来匹配这个向量,将匹配上的保留下来,从而识别出非美国地名

us.states <- c("ak","al","ar","az","ca","co","ct","de","fl","ga","hi","ia","in",
               "ks","ky","la","ma","md","me","mi","mn","mo","ms","mt","nc","nd",
               "ne","nh","nj","nm","nv","ny","oh","ok","or","pa","ri","sc","sd",
               "tn","tx","ut","va","vt","wa","wi","wv","wy")

ufo$USState <- us.states[match(ufo$USState,us.states)]
ufo.us <- subset(ufo,!is.na(USState))
head(ufo.us)

match()返回第一个参数在第二个参数中第一次匹配成功的位置,
返回值的长度与第一个参数的长度相同,如果没有匹配成功则返回NA。

  • 4.数据框的维度压缩和缺失值补齐
    前面我们关注的是空间维度,这一节我们关注时间维度
    要判断美国UFO记录的周期性规律,将数据按year-month的方式聚合
# 按year-month的聚合方式来显示出周期的变化(数据框添加新列)
ufo.us$YearMonth <- strftime(ufo.us$DateOccurred,
                            format = "%Y-%m")
library(plyr)
# 统计美国的各个州在每个年-月期间目击UFO的次数
sightings.counts <- ddply(.data = ufo.us,
                          .variables = .(USState,YearMonth),.fun = nrow)
head(sightings.counts)

ddplyr()函数将数据按照一定的方式分组统计,在这里按州名和年-月来给数据分组。

sightings是一个数据框,记录了分组统计的结果,此结果中有一些缺失值,缺少了某些月份的统计情况。

下面进行补齐

阿拉斯加州1990年的2月和4月并没有记录,估计在这期间并没有目击记录,因此需要把这些时间记录加上,并设为0
# 创建UFO目击事件的日期序列
date.range <- seq.Date(from = as.Date(min(ufo.us$DateOccurred)),
                       to = as.Date(max(ufo.us$DateOccurred)),
                       by = "month")
# 然后把格式设定为数据框中的日期格式
date.strings <- strftime(date.range,"%Y-%m")

# 创建一个包含所有年-月和州的数据框
# lapply()函数增加列
states.dates <- lapply(us.states,function(s)
                      cbind(s,date.strings))
# do.call()函数将列表转换为矩阵,然后再转换为数据框
states.dates <- data.frame(do.call(rbind,states.dates),
                       stringsAsFactors = FALSE)
head(states.dates)

现在states.dates包含了每一年,每月,各个州的组合,下面给缺失的值补0
merge()函数将这个新数据框与原来的数据框(sightings.count)合并

all.sightings <- merge(states.dates,sightings.counts,
                       by.x = c("s","date.strings"),
                       by.y=c("USState","YearMonth"),
                       all = TRUE)
head(all.sightings)

merge()函数纵向合并两个数据框,通过一个或多个共有变量进行联结的(inner join)
merge(x,y,by,by.x,by.y,all,…)
x,y是要合并的数据框对像,默认情况通过两个数据框共有的列名进行合并
by.x,b.y分别指定两个数据框的列名,即确定观测所需要的标识符;根据指定的列,提取行观测,并连接起来
all设置为TRUE,告诉函数要把没有匹配上的数据也包含进来并填充为NA

接下来将all.sightings数据框的列名改成有意义的名称,NA值改为0

names(all.sightings) <- c("States","YearMonth","Sightings")

all.sightings$Sightings[is.na(all.sightings$Sightings)] <- 0

all.sightings$YearMonth <-as.Date(rep(date.range,length(us.states)))

all.sightings$States <- as.factor(toupper(all.sightings$States))

日期保存成Date对象而不是字符串,因为Date对象易于比较;
州名缩写最好用分类变量表示,而不用字符串,因此可以将其转换为factor类型;
toupper()函数将小写改成大写。

你可能感兴趣的:(R,programing)