【问题标题】:From Python to R - DataFrame from string从 Python 到 R - 来自字符串的 DataFrame
【发布时间】:2018-08-28 09:47:39
【问题描述】:

我在Python 中有以下工作示例,它接受一个字符串,对其使用字典理解和正则表达式,最后从中生成一个数据框:

import re, pandas as pd

junk = """total=7871MB;free=5711MB;used=2159MB;shared=0MB;buffers=304MB;cached=1059MB;
free=71MB;total=5751MB;shared=3159MB;used=5MB;buffers=30MB;cached=1059MB;
cached=1059MB;total=5751MB;shared=3159MB;used=5MB;buffers=30MB;free=109MB;"""

rx = re.compile(r'(?P<key>\w+)=(?P<value>[^;]+)')
records = [{m.group('key'): m.group('value') 
            for m in rx.finditer(line)} 
            for line in junk.split("\n")]
df = pd.DataFrame(records)
print(df)

这会产生

  buffers  cached    free  shared   total    used
0   304MB  1059MB  5711MB     0MB  7871MB  2159MB
1    30MB  1059MB    71MB  3159MB  5751MB     5MB
2    30MB  1059MB   109MB  3159MB  5751MB     5MB


现在如何......我可以在R 中做同样的事情吗?
我搞砸了lapplyregmatches,但无济于事。此外,我将如何处理缺失值?

【问题讨论】:

    标签: python r regex


    【解决方案1】:

    咕噜声选项:

    library(purrr)
    
    'total=7871MB;free=5711MB;used=2159MB;shared=0MB;buffers=304MB;cached=1059MB;
    free=71MB;total=5751MB;shared=3159MB;used=5MB;buffers=30MB;cached=1059MB;
    cached=1059MB;total=5751MB;shared=3159MB;used=5MB;buffers=30MB;free=109MB;' %>% 
        strsplit('\n') %>% .[[1]] %>%    # separate lines into character vector
        strsplit(';') %>%     # separate each line into a list of key-value pairs
        map(strsplit, '=') %>%    # split key-value pairs into length-2 sublists
        map(transpose) %>%    # flip list of key-value pairs to list of keys and values
        map_dfr(~set_names(.x[[2]], .x[[1]]))    # set names of values to keys and simplify to data frame
    #> # A tibble: 3 x 6
    #>   total  free   used   shared buffers cached
    #>   <chr>  <chr>  <chr>  <chr>  <chr>   <chr> 
    #> 1 7871MB 5711MB 2159MB 0MB    304MB   1059MB
    #> 2 5751MB 71MB   5MB    3159MB 30MB    1059MB
    #> 3 5751MB 109MB  5MB    3159MB 30MB    1059MB
    

    或更以数据框为中心的选项:

    library(tidyverse)
    
    # put text in data frame
    data_frame(text = 'total=7871MB;free=5711MB;used=2159MB;shared=0MB;buffers=304MB;cached=1059MB;
    free=71MB;total=5751MB;shared=3159MB;used=5MB;buffers=30MB;cached=1059MB;
    cached=1059MB;total=5751MB;shared=3159MB;used=5MB;buffers=30MB;free=109MB;') %>% 
        separate_rows(text, sep = '\n') %>%    # separate lines into separate rows
        rowid_to_column('line') %>%    # add index for each line to help spreading later
        separate_rows(text, sep = ';') %>%    # separate each line into key-value pairs
        filter(text != '') %>%    # drop extra entries from superfluous semicolons
        separate(text, c('key', 'value')) %>%    # separate keys and values into columns
        spread(key, value) %>%    # reshape to wide form
        select(-line)    # drop line index column
    #> # A tibble: 3 x 6
    #>   buffers cached free   shared total  used  
    #>   <chr>   <chr>  <chr>  <chr>  <chr>  <chr> 
    #> 1 304MB   1059MB 5711MB 0MB    7871MB 2159MB
    #> 2 30MB    1059MB 71MB   3159MB 5751MB 5MB   
    #> 3 30MB    1059MB 109MB  3159MB 5751MB 5MB
    

    如果你想避免包,你可以通过read.dcf 破解它,它读取 Debian 控制格式(如 R 包说明文件),它只是键值对。 DCF 使用: 而不是=\n 而不是;,所以你需要先做一点gsubing:

    junk <- 'total=7871MB;free=5711MB;used=2159MB;shared=0MB;buffers=304MB;cached=1059MB;
    free=71MB;total=5751MB;shared=3159MB;used=5MB;buffers=30MB;cached=1059MB;
    cached=1059MB;total=5751MB;shared=3159MB;used=5MB;buffers=30MB;free=109MB;'
    
    junk <- gsub('=', ':', junk) 
    junk <- gsub(';', '\n', junk)
    mat <- read.dcf(textConnection(junk))
    mat
    #>      total    free     used     shared   buffers cached  
    #> [1,] "7871MB" "5711MB" "2159MB" "0MB"    "304MB" "1059MB"
    #> [2,] "5751MB" "71MB"   "5MB"    "3159MB" "30MB"  "1059MB"
    #> [3,] "5751MB" "109MB"  "5MB"    "3159MB" "30MB"  "1059MB"
    

    它返回一个矩阵,但它的格式很好,很容易转换为适当的数据帧:

    df <- as.data.frame(mat, stringsAsFactors = FALSE)
    df
    #>    total   free   used shared buffers cached
    #> 1 7871MB 5711MB 2159MB    0MB   304MB 1059MB
    #> 2 5751MB   71MB    5MB 3159MB    30MB 1059MB
    #> 3 5751MB  109MB    5MB 3159MB    30MB 1059MB
    

    【讨论】:

    • 我看到它正在工作,但你能在答案中给出一些解释吗?
    • 添加了很多 cmets。如果你跑过每条管道,你也可以很容易地看到中间产品。
    【解决方案2】:

    工作示例:

    junk <- "total=7871MB;free=5711MB;used=2159MB;shared=0MB;buffers=304MB;cached=1059MB;
    free=71MB;total=5751MB;shared=3159MB;used=5MB;buffers=30MB;cached=1059MB;
    cached=1059MB;total=5751MB;shared=3159MB;used=5MB;buffers=30MB;free=109MB;"
    
    names <- unique(strsplit(gsub("[(?\\n=\\d+MB;)]", " ", a, perl=TRUE), "(\\s+)")[[1]])
    
    dataset <- read.table(text=gsub("[^(\\d+)]", " ", a, perl=TRUE), header = FALSE, col.names=names)
    

    【讨论】:

    • 这是如何工作的?你想补充一些解释吗?
    • 如果列的顺序一致,此方法将有效。但是,由于它们不是,它是按位置而不是标签读取数据,这会导致交换值,例如在freetotal 的第一行和第二行之间。
    猜你喜欢
    • 2018-03-30
    • 2020-02-29
    • 2018-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多