【问题标题】:Remove spaces and convert values to as numeric when only numbers in R当 R 中只有数字时,删除空格并将值转换为数字
【发布时间】:2020-05-17 21:15:29
【问题描述】:

我一直在网上寻找这个问题

与通常的发现不同的是,我的列中有数字和其他不同于普通数字的值。

比如说:

df <- data.frame('Col1' = c('421', ' 0.52', '-0.88 ', '1.2 (ref)', ' 97  '),
                 'Col2' = c('0.0', '0.27,0.91', '3.0', ' 10242.3', '  94.5'))

我想从仅由数字组成的单元格中删除空格。不确定,例如0.52,那个dot 字符是否仍然被视为数字。同样在-0.88 - 字符中。

到目前为止我会使用

library(stringr)
# Remove spaces
df$Col1 <- str_replace_all(df$Col1, "\\s+", "")

library(dplyr)
# Convert to as.numeric
df %>%
mutate_all(funs(as.numeric(as.character(.)))   

但我不想只替换每个空格,例如值1.2 (ref),我想保留那个空格。另外,不要将每个值都更改为 as.numeric,仅在纯数字或\d+\.\d+\-\d+\.\d+(正则表达式)的情况下进行

此外,如果我尝试转换为 as.numeric,数值会以某种方式发生巨大变化,我知道这是因为值中存在空格。

提前致谢

【问题讨论】:

  • 除了空格之外,还有其他字符,例如(ref),它们不是数字
  • 如果你想保留1.2 (ref)之类的值,那么列中的所有值将被强制转换为character,无论它们看起来如何“数字” -一列只能有一个单个类。无论如何,对于一般的前导/尾随空格,请参阅read.table 中的strip.white 参数。
  • 您的意思是说您要从-0.88 中删除空格,而不是从'1.2 (ref)' 中删除空格?

标签: r dplyr number-formatting


【解决方案1】:

akrunHenrik 指出您有几个问题:由于数据框中的列只能属于同一类,1.2(ref) 值会强制该列属于 character 类。此外,在Col2 中有这个条目:0.27,0.91。这看起来像两个值,您需要决定如何处理它。

建议:将Col1 分成两列。一列保存数值,另一列保存值refNA。这可以是字符或因子列。至于 double 数值:分成两列或决定要保留哪个值。

在这些假设下,您的代码可能是这样的(使用tidyverse 方法):

library(dplyr)
library(tidyr)
library(stringr)

df <- data.frame('Col1' = c('421', ' 0.52', '-0.88 ', '1.2 (ref)', ' 97  '),
                 'Col2' = c('0.0', '0.27,0.91', '3.0', ' 10242.3', '  94.5'))

df <- df %>%
  mutate_all(.funs = funs(str_trim)) %>% # remove leading and trailing spaces
  separate(col = Col1, into = c("Value_1", "Reference"), sep = "\\s|,") %>% # split into 2 columns at comma or space
  separate(col = Col2, into = c("Value_2", "Value_3"), sep = "\\s|,") %>% # split into 2 columns at comma or space
  mutate_at(.vars = vars(starts_with("Value")), as.numeric) #convert character to numeric

此代码无法很好地扩展:如果您的数据集有很多列,并且每列需要以不同的方式拆分,事情就会变得复杂。最好先查看您的数据集并对其进行一些质量控制。如果任何列可以包含逗号分隔值:您可以编写代码来捕获它并以统一的方式应用更正。值和文本的组合是您的数据集中不应该允许的。

输出:

> glimpse(df)
Observations: 5
Variables: 4
$ Value_1   <dbl> 421.00, 0.52, -0.88, 1.20, 97.00
$ Reference <chr> NA, NA, NA, "(ref)", NA
$ Value_2   <dbl> 0.00, 0.27, 3.00, 10242.30, 94.50
$ Value_3   <dbl> NA, 0.91, NA, NA, NA

> df
  Value_1 Reference  Value_2 Value_3
1  421.00      <NA>     0.00      NA
2    0.52      <NA>     0.27    0.91
3   -0.88      <NA>     3.00      NA
4    1.20     (ref) 10242.30      NA
5   97.00      <NA>    94.50      NA

【讨论】:

    【解决方案2】:

    我使用regex 构建了一个函数

    library(tidyverse)
    mClean <- function(strVec){
      pass1 <- strVec %>% 
        str_trim() %>% 
        str_extract("(?x)        # Perl-style whitespace
                    ^[\\+\\-]?   # An optional leading +/-
                    \\d+         # the integer part
                    (\\.\\d+)? # A fractional part
                    ") %>% 
        as.numeric()
    }
    

    我将您的数据放在一个 tibble 中并运行它:

    df <- tibble('Col1' = c('421', ' 0.52', '-0.88 ', '1.2 (ref)', ' 97  '),
                     'Col2' = c('0.0', '0.27,0.91', '3.0', ' 10242.3', '  94.5')) %>% 
      mutate(cln1 = as.numeric(mClean(Col1)),
             cln2 = as.numeric(mClean(Col2)))
    df
    
    # A tibble: 5 x 4
      Col1      Col2          cln1     cln2
      <chr>     <chr>        <dbl>    <dbl>
    1 421       0.0         421        0   
    2 " 0.52"   0.27,0.91     0.52     0.27
    3 "-0.88 "  3.0          -0.88     3   
    4 1.2 (ref) " 10242.3"    1.2  10242.  
    5 " 97  "   "  94.5"     97       94.5 
    

    我不确定你想用那个“0.27,0.91”做什么。把它分成两行?为“0.91”创建另一列?无论如何,这会将原始输入与清理后的值保持在同一行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-03
      • 2014-08-23
      • 2017-11-15
      • 1970-01-01
      • 2015-11-16
      • 2020-06-25
      相关资源
      最近更新 更多