处理杂乱的日子
我希望你们不要以为我是在寻求关系方面的build议。
我不得不提供调查回复者指定事件发生时间的能力。 什么结果是一个可怕的混乱的string,我真的不知道该怎么办。 除了手工录制之外。
这是一个简短的样本,数千:
c(“5月2日/ 12日”,“早上9:45”,“11:00 AM AST”,“4月27日/ 12:00 AST”, “上午11:40 AST”,“2011年4月25日”,“2011年4月12日/ 8:44”,“2011年4月12日/上午8:36”, “2011年4月12日/ 8:30”,“2011年4月12日/ 8:18”,“2011年4月12日/上午8:12”, “2011年4月11日/下午5:57”,“2011年4月11日/下午5:49”,“2011年4月11日/下午5:42”, “2011年4月11日/下午5:36”,“2011年4月11日/ 5:27”,“4月5日上午11:26”, “8:50”,“4月4日12:45”,“4月4日上午10时”,“4月4日10时左右”, “2011年3月18日上午9时33分”,“2011年3月18日上午9时27分”,“DF”,“Fg”,“12:16”, “9:50”,“2011年2月8日/ 12点20分”,“2011年2月4日上午8点34分”,“2011年1月31日下午2点50分”, “2011年1月31日下午2点45分”,“2011年1月31日下午2点38分”,“2011年1月31日下午2点26分”, “11h09”,“11:00 am”,“1h02 pm”,“10h03”,“2h10”,“2011年1月13日上午9:50范”, “2011年1月12日”,“2011年1月12日下午3:59”,“Jan 12 14:19 PM”, “2011年1月12日下午1时35分”,“2011年1月12日下午1时28分”,“1h36”,“9h15”, “9h09”,“8h51”,“8h45”,“8h35”,“1h12 pm”,“12h59”,“11h52 am”, “10h45”,“15h55”,“Dec 31,10 11:11 am”,“Dec 31,10 10:15 am”, “2010年12月30日下午12点32分”,“2010年12月30日下午12点18分”,“上午9点16分”,“上午11点16分”, “11h12”,“9h29 am”,“11h38”,“2010年12月16日”,“2010年12月16日” “2010年12月16日”,“2010年12月15日”,“2010年12月14日”,“12月14日11:38”, “12月14日11:35”,“12月14日11:25”,“2010年12月13日”,“12月10日下午1时38分”, “12月10日下午1点26分”,“12月10日下午1点20分”,“12月10日下午1点12分”,“2010年12月9日” “上午11点10分”,“上午10点59分”,“上午10点50分”,“12月7日星期二9:45乘车时间”, “2010年12月3日下午12时30分”,“2010年12月3日下午12时20分”,“2010年12月3日下午12时10分”, “2010年11月30日4.02pm”,“2010年11月30日”,“11月29日120pm” “2010年11月29日11:27”,“2010年11月29日10时12分”,“11月26日10时18分18秒”, “10:56 am”,“Nov 24”,“nov 24 / 4:20 PM AST”,“Nov 24/4:00 PM AST”, “11月24日10时2分10时”,“11月24日10时11分”,“12时05分MST”, “下午3时05分”,“11月17日10时12分45分”,“11月16日10时中午12时”,“11月16日10日11时50分” “nov 16/10 11:30 am”,“2010年11月12日下午12:23”,“2010年11月11日下午2:20”, “2010年11月11日下午2点15分”,“11月11日下午2点”,“11月10日上午22点”, “8月10日下午3点19分”,“11月8日10日下午50点”,“11月8日10日... 12日中午” “11月8日10点10分:上午”,“2010年11月5日下午1点10分”,“上午11点32分”, “Nov 4 11:10”,“nov 3 10am”,“9:30 am”,“11/02/2010 1:50 PM”, “Oct 29/10 2:50 PM”,“Oct 28 @ 11:20 am”,“27Oct10 10:40 am”,“10/26/2010 11:18”, “10月26日10时11分”,“10月26日10时10分”,“10月26日10时50分”,“2010年10月25日13:50”, “2010/10/22 10:15”,“2010年10月22日上午10点”,“2010年10月21日下午3点”, “2010年10月21日2:59”,“2010/10/21 11:50”,“10/21/2010 11:45”, “2010/10/21 11:40”,“2010/10/21 11:30”,“11:30”,“10月20日下午1点” “Oct 10/10 4:50 PM”,“13:48”,“13:45”,“2010年10月20日上午11:45”, “10月19日下午3点05分”,“2010年10月18日下午2点15分”,“10月18日10时3分10秒”, “上午10点30分”,“10月15日上午11点50分”,“10月14日上午11点05分”,“10月14日/ 11点06分”, “大西洋四时四十四分,大西洋四时十四分四十五分”,“大西洋十一时十五分十五分”, “Oct 13 / 10:37”,“OCT 12 3:33”,“Oct 10,2010 1:10 pm”,“Oct 12 / 11:45”, “10月12日/ 9:45”,“2010年10月8日/ 2:00”,“10月8日10时至11时45分”,“2010年9月2日下午3.5时25分”, “2010年9月2日上午10点01分”,“2010年9月1日下午2时05分”,“2010年9月1日”,“2010年8月31日上午11时52分”, “2010年8月31日上午10点40分”,“2010年8月31日上午10点”)
一般而言,这些事件发生在应答者填写调查的date附近,但并不总是如此。 调查date自动logging并以一致的格式logging,并且可以使用as.Date
轻松转换为POSIX,因此只包含时间的元素可以忽略,并与填写调查date合并。
你的想法非常感谢。
注1:你们中的一些人可能会说,你应该在validation答案方面做了X,Y或Z. 对我来说,下次我会说 – 是的。 我没有devise它! 我只需要处理它。
有几个事实可以帮助解决方法:
- 时间将永远是营业时间,上午9时至下午6时(因此上午/下午无所谓)
- 年纪不重要,因为我可以把他们从另一个领域(它永远只会是2011/2010,这是幸运的在任何符号可能的时间范围之外)
- 我不在乎时区,因为我有他们的地理位置
到目前为止我所做的是:
mos <- strsplit(' jan feb mar apr may jun jul aug sep oct nov dec january february march april may june july august september october november december ', '\n')[[1]][-1] days <- strsplit(' mon tue wed thu fri sat sun monday tuesday wednesday thursday friday saturday sunday ', '\n')[[1]][-1] ## Messy Date Wrangling x <- ## that hot ghetto mess above # minimize x <- tolower(x) # remove unnecessary crap x <- sub("2011"," ",x) x <- sub("2010"," ",x) x <- sub("am"," ",x) x <- sub("pm"," ",x) x <- sub("[p][.][m]"," ",x) x <- sub("[a][.][m]"," ",x) x <- sub("[.]{3}"," ",x) x <- str_trim(x, side="both") # divide x <- strsplit(x,c(" ")) # conquer? lapply(x, function(x) pmatch(x,mos)) lapply(x, function(x) pmatch(x,days))
我的同情,你的date没有像预期的那样漂亮。 😉
我已经根据@Rguybuild议的方法构build了一个(仍然是部分的)解决scheme。
(请注意,这段代码仍然存在一个错误:并不总是返回正确的时间,由于某些原因,并不总是对冒号前的数字进行贪婪的匹配,因此有时在返回1时返回是十一点。)
首先,构build一个围绕gsub
和grep
的辅助函数。 该函数将字符向量作为其参数之一,并将其折叠为由|分隔的单个string。 这样做的效果是让你可以很容易地传递多个模式来匹配正则expression式:
find.pattern <- function(x, pattern_list){ pattern <- paste(pattern_list, collapse="|") ret <- gsub(paste("^.*(", pattern, ").*", sep=""), "\\1", x, ignore.case=TRUE) ret[ret==x] <- NA ret2 <- grepl(paste("^(", pattern, ")$", sep=""), x, ignore.case=TRUE) ret[ret2] <- x[ret2] ret }
接下来,使用一些内置的variables名称来构build一个月份和缩写的向量:
all.month <- c(month.name, month.abb)
最后,用不同的摘录构build一个dataframe:
ret <- data.frame( data = dat, date1 = find.pattern(dat, "\\d+/\\d+/\\d+"), date2 = find.pattern(dat, paste(all.month, "\\s*\\d+[(th)|,]*\\s{0,3}[(2010)|(2011)]*", collapse="|", sep="")), year = find.pattern(dat, c(2010, 2011)), month = find.pattern(dat, month.abb), #Use base R variable called month.abb for month names hour = find.pattern(dat, c("\\d+[\\.:h]\\d+", "12 noon")), ampm = find.pattern(dat, c("am", "pm")) )
结果:
head(ret, 50) data date1 date2 year month hour ampm 20 April 4th around 10am <NA> April 4th <NA> Apr <NA> am 21 April 4th around 10am <NA> April 4th <NA> Apr <NA> am 22 Mar 18, 2011 9:33am <NA> Mar 18, 2011 2011 Mar 9:33 am 23 Mar 18, 2011 9:27am <NA> Mar 18, 2011 2011 Mar 9:27 am 24 df <NA> <NA> <NA> <NA> <NA> <NA> 25 fg <NA> <NA> <NA> <NA> <NA> <NA> 26 12:16 <NA> <NA> <NA> <NA> 12:16 <NA> 27 9:50 <NA> <NA> <NA> <NA> 9:50 <NA> 28 Feb 8, 2011 / 12:20pm <NA> Feb 8, 2011 2011 Feb 2:20 pm 29 8:34 am 2/4/11 2/4/11 <NA> <NA> <NA> 8:34 am 30 Jan 31, 2011 2:50pm <NA> Jan 31, 2011 2011 Jan 2:50 pm 31 Jan 31, 2011 2:45pm <NA> Jan 31, 2011 2011 Jan 2:45 pm 32 Jan 31, 2011 2:38pm <NA> Jan 31, 2011 2011 Jan 2:38 pm 33 Jan 31, 2011 2:26pm <NA> Jan 31, 2011 2011 Jan 2:26 pm 34 11h09 <NA> <NA> <NA> <NA> 11h09 <NA> 35 11:00 am <NA> <NA> <NA> <NA> 1:00 am 36 1h02 pm <NA> <NA> <NA> <NA> 1h02 pm 37 10h03 <NA> <NA> <NA> <NA> 10h03 <NA> 38 2h10 <NA> <NA> <NA> <NA> 2h10 <NA> 39 Jan 13, 2011 9:50am Van <NA> Jan 13, 2011 2011 Jan 9:50 am 40 Jan 12, 2011 <NA> Jan 12, 2011 2011 Jan <NA> <NA>
这可能是R以外的其他工具最好使用的less数情况之一。 我知道有一些Perl模块已经被开发来parsing凌乱的date,模块DateTime :: Format :: Natural :: Lang :: EN可以parsingstring,如:“11月2日星期二”。 我似乎还记得另一个可以理解“二月份第一个星期一后的第二个星期二”的模块。
http://www.datasciencetoolkit.org/上还有一个工具,用于获取文本中的date,并将其转换为标准格式。;
我现在不打算写这个函数,但是我有一个想法可以工作。
search每个string的4位数字来调用年份。
使用grep
search每个string,查找月份缩写的前3个字母。 看起来几乎所有的数据(至less在上面)都有一个这样的标识符。 我将存储在“月”向量中find的值,并在没有find值的地方放置空格。 这是一个非常丑陋的代码版本(我会在今后提高效率,并在月份没有大写的情况下添加)
mos <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec") blah <- lapply(1:12, function(i) grepl(mos[i], test)) lapply(blah, function(i) which(i)) months <- 0*(1:length(test)) for (i in 1:12) { months[blah[[i]]] <- i } months [1] 5 0 0 4 0 4 4 4 4 4 4 4 4 4 4 4 4 0 4 4 4 3 3 0 0 0 0 2 0 1 [31] 1 1 1 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 12 12 12 12 0 [61] 0 0 0 0 12 12 12 12 0 12 12 12 12 12 12 12 12 12 0 0 0 12 12 12 12 11 11 0 11 11 [91] 11 0 11 0 11 0 11 0 0 11 11 11 0 11 0 11 11 11 0 11 11 11 11 0 11 0 0 0 10 10 [121] 10 0 10 10 10 0 0 10 10 10 0 0 0 0 0 10 10 0 0 10 10 10 10 0 10 0 10 0 0 0 [151] 10 0 10 10 10 10 10 9 9 9 9 8 0 0
“一天”最常见的是紧随当月使用的这个词。 所以如果月份之后有一个或两个数字(即字符),提取这个数字并称之为一天。
时代最常见的是“:”或“。” 在他们的符号,所以search每个string的那个字符。 如果在一个string中find,创build一个“时间”向量与该字符之前和之后的所有数字(理论上,包括前2和后2应该不会导致问题)。 当符号不存在时放置空白。 如果所有的数据都被限制在<12小时的时间内,那就太好了,因为那样你就不用担心上午和下午了。 如果不是,也许searchstring“AM”和“PM”以及。
然后,尝试将以上全部四个string转换为POSIXct。 那些不转换的,当然你必须手动input。 我认为需要几个小时才能完成上述function的编码,根据数据集的可变性和大小,这可能会也可能不值得。 另外,错误输出有一定的风险,因此增加一个可接受的时间范围将有助于避免这种情况。
总之,这听起来像是你将不得不编写一个有很多例外的函数,然后最终手工编码很多时候。 我希望有人能为你提供更好的解决scheme。
祝你好运!
狼阿尔法http://www.wolframalpha.com/绝对是一个伟大的工具来做这个工作。;
至less,它成功地解释了您的数据中的一些混乱的input。 这是值得尝试的。
我不确定该网站是否适合超大型数据集,但是如果数据不是那么大,这将会很有用。
编写一个发送查询,获取数据和parsing它的自动化脚本并不难,尽pipe我不确定该站点是否允许这样使用。
其他人已经提出了标准方法和包装。 我会采取不同的观点。 使用正则expression式和固定格式将使您获得最大的方式。 对于其余的问题,我只是简单地介绍一下,因为在“模式匹配”中有任何问题:统计方法或机器学习。 您已经指定了date和时间范围,并且日志的时间戳也是信息性的。 通过提取大量的文本特征(这是正则expression式将certificate有用的地方),然后您可以尝试映射到感兴趣的时间。
只有三件事情可以做到这一点:
- 特征提取
- 训练集生成
- 构build和部署模型
build立和部署模型? 让我把你介绍给我的朋友R和机器学习任务视图 。 :)探索的基本模型包括多项模型(看看glmnet
),决策树和支持向量机。 您可以使用决策树和SVM作为多项模型的input(并且可能不需要SVM)。 说实话,这个部分是模糊的:可以把这个build模作为断开连接的date组件,或者作为一个改进的过程,例如获得年份,如果可能的话,然后是分钟(因为范围远远大于几个小时,几天,几个月),然后是一个月中的某一天,最后是几个小时和几个月。 本质上,我的目标是试图识别数字/string组件的“部分时间”(类似于词类)。
特征提取:我会尝试用冒号,逗号,斜线,破折号,句点等进行分割。不是数值的任何东西。 然后,我将根据这些特征以任何顺序(即所看到的特征的指标值,忽略位置)创build数据集。
培训资料:亚马逊的Mechanical Turk。
或者,你知道什么,只是忽略所有的编程和统计的庞然大物,把所有的东西都发给Mechanical Turk。 🙂