当 R 中只有数字时,删除空格并将值转换为数字

Remove spaces and convert values to as numeric when only numbers in R

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

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

比如说:

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'))

我想从仅由数字组成的单元格中删除 spaces。不确定 0.52dot 字符是否仍将其视为数字。同样在 -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(.)))   

但我不想只替换每个 space,例如值 1.2 (ref),我想保留 space。此外,不要将每个值更改为 as.numeric,仅在纯数字或 \d+\.\d+\-\d+\.\d+(正则表达式)

的情况下

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

提前致谢

您遇到了 akrunHenrik 指出的几个问题:由于数据框中的列只能具有相同的 class,因此 1.2(ref) 值强制列为 class 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

我使用 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()
}

我把你的数据放在小标题中 运行 它:

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”创建另一列?无论如何,这会将原始输入与清理后的值保持在同一行。