如何从相同的行中提取变量名和变量数据来构建数据框?

时间:2016-10-18 00:16:03

标签: r regex text dataframe

我有一系列看起来像这样的文本文件:

USABILITY DATA
Level Name: LVL_Introduction
    Time Spent: 323.233307
    Times Teleported: 6
    NumDeaths: 0

Level Name: LVL_1-1
    Time Spent: 36.760727
    Times Teleported: 1
    NumDeaths: 0

Level Name: LVL_1-2
    Time Spent: 45.953598
    Times Teleported: 1
    NumDeaths: 0

Level Name: LVL_1-3
    Time Spent: 176.440704
    Times Teleported: 0
    NumDeaths: 0

Level Name: LVL_1-4
    Time Spent: 281.797485
    Times Teleported: 0
    NumDeaths: 0

每个文本文件代表一个玩家来自益智游戏中从一个级别到另一个级别的游戏会话的数据。有些玩家达到的程度与其他玩家不同。

我想把这种文本文件刮到一个数据框中,这个数据框会给我一个带有Level Name的表(例如:“LVL_1-3”)作为列标题和“Time Spent”,“Times Teleported” “和”NumDeaths“作为行标题。

                    LVL_Introduction    Lvl_1-1    etc...
Time Spent:         323.233307          36.760727
Times Teleported:   6                   1 
NumDeath:           0                   0

理想情况下,无论涉及哪个用户(或级别名称),脚本都足够强大。我已经看到了几个相关问题的不同解决方案,一些使用正则表达式,一些只是拆分字符串。我不确定在一个跨多个文件的脚本中使用单行来生成标题和数据值的最佳过程。

谢谢, 米切尔

2 个答案:

答案 0 :(得分:0)

这是我的建议,虽然它与您要求的不完全相符,但我认为您会发现它以非常整洁(阅读:有用)的方式为您提供数据:

library( readr ) 
library( plyr )

import <- function( datafile.name ) {

    new <- read_delim( datafile.name,
                       col_names = c( "category", "data" ), 
                       delim = ":",
                       trim_ws = TRUE )
    new <- new[ !is.na( new$data ), ]

    output <- data.frame(
        new[ new$category == "Level Name", "data" ],
        new[ new$category == "Time Spent", "data" ],
        new[ new$category == "Times Teleported", "data" ],
        new[ new$category == "NumDeaths", "data" ],
        stringsAsFactors = FALSE
    )
    names( output ) <- c( "level.name", "time.spent", "times.teleported", "num.deaths" )

    # get the username from the file name
    output$user <- datafile.name
    return( output )
}

# get a list of files
setwd( [where your files are located] )
filelist <- list.files()

# and apply the function above to all those files to create one big dataframe
df <- ldply( .data = filelist,
             .fun = import )

注意,我假设您的文件名不直接代表用户名,因此您需要进行转换。像gsub(".txt","",datafile.name)这样简单的东西就足够了。

如果要导入大量文件,您可能还希望多线程处理该进程。这里有4个核心:

library( doMC )
registerDoMC( cores = 4 )
df <- ldply( .data = filelist,
             .fun = import,
             .parallel = TRUE )

答案 1 :(得分:0)

readr有一个很好的分块读取功能,如果你有分块的格式化数据,它可能会有所帮助。

在这里,我创建了一个处理块的函数 - 它使用read.delim来读取variable: value数据,然后使用tidyr::spread转换它

library(tidyr)
library(readr)

f <- function(x, pos) {
  dat <- read.delim(text = x, sep = ":", header = FALSE, stringsAsFactors = FALSE)
  return(spread(dat, V1, V2))
}

使用DataFrameCallback阅读包含data.frame

rbind个结果
rawData <- read_lines_chunked(file = "gamedata.txt",
                              skip = 1,
                              chunk_size = 5, 
                              callback = DataFrameCallback$new(f))

然后,只需将此格式重新格式化为您要求的内容(使用4列ID不健全,但这是一个干净的示例)

gameData <- setNames(data.frame(t(rawData[, -4])), rawData[, 4])[c(2,3,1), ]
gameData
#>                       LVL_Introduction    LVL_1-1    LVL_1-2     LVL_1-3
#>     Time Spent              323.233307  36.760727  45.953598  176.440704
#>     Times Teleported                 6          1          1           0
#>     NumDeaths                        0          0          0           0
#>                          LVL_1-4
#>     Time Spent        281.797485
#>     Times Teleported           0
#>     NumDeaths                  0