星期日, 十一月 25, 2012

如何批量处理文本文件

最近数据堂为了弄数据挖掘比赛提供了一批用户行为日志数据。对于以前没玩过的数据,我是特别的好奇。处理这批文本文件确实花了不少时间。数据以不同的日期作文件夹分别存放,每个文件夹中又有近一千个文本文件,每个文件都是一个用户的行为日志。为了分析这些数据,首先需要将这两万个文本文件读入R中,再用字符串函数进行处理成结构化的数据。处理方法如下:
library(stringr)
setwd('D:\\kaggle\\tang\\data')
data <- read.table('data.csv',T,sep=',')
 
# 读入文档地址
path <- 'D:\\kaggle\\tang\\data\\behavior'
dir.name <- dir('D:\\kaggle\\tang\\data\\behavior')
doc.name <- list()
fre <- numeric()
for (i in 1:length(dir.name)) {
    doc.name[[i]]<- dir(paste(path,dir.name[i],sep='\\'))
    fre[i] <- length(doc.name[[i]])
}
dir <- rep(dir.name,fre)
doc.name <-unlist(doc.name)
file.name <- character()
for ( i in 1:length(dir)) {
    file.name[i] <-  paste(path,dir[i],doc.name[i],sep='\\')
}
 
# 建立抽取主函数,返回列表
data.get <- function(file.name) {
    #获取文本
    temp <- readLines(file.name,encoding='UTF-8')
    if (length(temp)<=2) return(NA)
    # 用户编号
    id <- str_match(file.name, "[A-Z0-9]{32}")
    # 调查日期
    day <- str_match(file.name, "\\d+-\\d+-\\d+")
    # 开机时点
    clock <-str_sub(str_match(file.name,'_\\d{2}-'),2,3)
    # 切分转换文本函数
        trans <- function(x){
            res <- unlist(str_split(x, "\\[=\\]|<=>"))
        #     res <- str_extract(x, "[^<=>]+\\.[a-z]+")
            return(res)
        }
    # 将文本切开转为列表
    result <- lapply(temp,trans)
 
    # 开机时长
    opentime <- as.numeric(result[[1]][2])
    # 先进行时间分析,由于有的信息不是按顺序排列,所以要按时点重排
    # 时点抽取
    time <- unlist(lapply(result[-c(1:2)], function(x) x[2]))
    time <- as.numeric(time)
    # 时点排序,然后重排result列表
    new.res <- result[-c(1:2)][order(time)]
 
    # 返回用户使用的程序向量
    prog <- unlist(lapply(new.res, function(x) x[4]))
    # 各程序使用时间
    time <- unlist(lapply(new.res, function(x) x[2]))
    time <- as.numeric(time)
    time[length(time)+1] <- opentime
    time <- diff(time)
 
    prog.time <- data.frame(prog=prog,time=time)
    progtime <- dcast(prog.time,prog~., sum,value.var='time')
    names(progtime) <- c('program','time')
 
    # 使用的软件个数
    numofsoft <- nrow(progtime)
    # 真实使用时长
    realtime <- sum(progtime$time,na.rm=T)
    return(list(id=as.character(id),day=as.character(day),
                clock = as.numeric(clock),opentime=opentime,
                numofsoft = numofsoft,
                realtime= realtime,progtime=progtime))
}
所有的文件名都已经存在file.name变量中,用上面建立好的函数data.get来提取第一份文件中的信息 
> data.get(file.name[[1]])
$id
[1] "0143692D264FD906F10B8ECAB0F139D1"
 
$day
[1] "2012-05-07"
 
$clock
[1] 12
 
$opentime
[1] 7771
 
$numofsoft
[1] 9
 
$realtime
[1] 7610
 
$progtime
           program time
1    360chrome.exe 1237
2 360leakfixer.exe    3
3      360Safe.exe   12
4        360sd.exe   20
5     explorer.exe  510
6     iexplore.exe 5473
7   liveupdate.exe    6
8     popup_QQ.exe   44
9           QQ.exe  305

12 条评论:

  1. 如果只是读取txt文件,能否用read.table一次性引入R?比如:路径是c:/RCODE,文件是file1.txt,file2.txt,......,file100.txt.

    回复删除
  2. 像这种大量却简单的数据清洗整合转换等 用几行awk就可以了 写起来简单 速度还快

    回复删除
  3. 肖兄,一定要把你这篇文章发到中统上去。

    回复删除
    回复
    1. 没问题啊,不过这只是搬运数据的粗活,呵呵

      删除
  4. 一批用户行为日志数据 在哪??????????

    ------------深圳 Rnord

    回复删除
    回复
    1. 数据堂提供的,如果需要可以给你玩玩

      删除
  5. 求数据,老师给发个数据看看cnzxcxt1@sina.com,我想试试

    回复删除
    回复
    1. 额,发现数据太大了,好几十M,邮箱没法发,你可以去数据堂看看有没下载的

      删除
  6. 感谢分享,我来汲取些营养XD

    回复删除