【问题标题】:Unwanted leading whitespace before number to char conversion in RR中数字到字符转换之前不需要的前导空格
【发布时间】:2022-08-13 22:36:01
【问题描述】:

考虑以下最小的工作示例:

df <- tibble::tibble(
    x=c(1, 10)
)

mwe <- function(row) {
    return(paste0(row[[\"x\"]]))
}

df$mwe1 = apply(df, 1, mwe)
df$mwe2 = apply(df, 1, mwe)

df 的最终值为

# A tibble: 2 × 3
      x mwe1  mwe2 
  <dbl> <chr> <chr>
1     1 1     \" 1\" 
2    10 10    \"10\" 

我希望它是

# A tibble: 2 × 3
      x mwe1  mwe2 
  <dbl> <chr> <chr>
1     1 1     1 
2    10 10    10 

我可以解释为什么列 mwe2 有额外的空格吗?

R.version 信息

platform       x86_64-pc-linux-gnu         
arch           x86_64                      
os             linux-gnu                   
system         x86_64, linux-gnu           
status                                     
major          4                           
minor          1.2                         
year           2021                        
month          11                          
day            01                          
svn rev        81115                       
language       R                           
version.string R version 4.1.2 (2021-11-01)
nickname       Bird Hippie

    标签: r tibble


    【解决方案1】:

    apply()背后的一些细节:

    1. apply()data.frame(或tibble)转换为带有as.matrix() 的矩阵,然后在数组边距上应用函数。
    2. 如果数据框包含数字和字符列,as.matrix() 将使用format() 将所有数字转换为字符。
    3. format() 强制数字向量在将其转换为字符时具有相同的宽度。例如。
      format(c(123.45, pi))
      
      [1] "123.450000"  "  3.141593"
      

      (注意 123.45 的尾随零和 pi 的前导空格)


      当您创建 mwe1 时:

      df$mwe1 = apply(df, 1, mwe)
      

      df 只有一个数字列 x,所以只有步骤1参与。该过程继续到mwe2

      df$mwe2 = apply(df, 1, mwe)
      

      现在df 有两列,一列是数字(x),另一列是字符(mwe1)。在这种情况下,步骤 2-3参与其中,因此x 列将传递给format() 并成为

      format(df$x)
      
      [1] " 1" "10"
      

      这就是出现前导空格的原因。

    【讨论】:

      【解决方案2】:

      当您创建 mwe1 和 mwe2 时,1 的含义会发生变化,因为新列会更改行。也就是说,拥有 mwe1 列会改变 paste 的工作方式。

      创建 mwe1 时,数据框由一列 (x) 和 2 行组成。创建 mwe2 时,数据框有两列和两行。因此,当您 paste0() 行时,结果会有所不同。

      更新

      首先,mwe1 的创建按您的预期工作是一种错觉。它正在创建一个字符列,但由于没有空格,打印方法没有加上引号。 如果您打印 tibble,您将看到 mwe1 的列类型是字符。

      让我们更仔细地看看。

      mwe <- function(row) {
        paste0(row[["x"]])
      }
      mwe_r1 <- function(row) {
        paste0(trimws(row[["x"]]))
      }
      mwe_r2 <- function(row) {
          as.numeric(paste0(row[["x"]]))
      }
      
      df <- tibble::tibble(
        x=c(1, 10)
      )
      # original tibble
      df
      
      df0 <- df
      df0$mwe1 = apply(df0, 1, mwe)
      df0$mwe2 = apply(df0, 1, mwe)
      #tibble with mwe2 added
      df0
      
      dfr1 <- df
      dfr1$mwe1 = apply(dfr1, 1, mwe_r1)
      dfr1$mwe2 = apply(dfr1, 1, mwe_r1)
      
      dfr1
      
      dfr2 <- df
      dfr2$mwe1 = apply(dfr1, 1, mwe_r2)
      dfr2$mwe2 = apply(dfr1, 1, mwe_r2)
      
      dfr2
      

      这是结果

      > df0
      # A tibble: 2 × 3
            x mwe1  mwe2 
        <dbl> <chr> <chr>
      1     1 1     " 1" 
      2    10 10    "10" 
      
      > dfr1
      # A tibble: 2 × 3
            x mwe1  mwe2 
        <dbl> <chr> <chr>
      1     1 1     1    
      2    10 10    10   
      
      > dfr2
      # A tibble: 2 × 3
            x  mwe1  mwe2
        <dbl> <dbl> <dbl>
      1     1     1     1
      2    10    10    10
      

      请注意前面提到的 df0 是您所拥有的,并且两个新列都是 chr 但它们的打印方式不同。

      然后 dfr1 在粘贴之前简单地删除空格。这给人一种错觉,即两个新列都是数字,但实际上它们都是字符。

      最后 dfr2 是您想要的,它是两个新的数字列。这是因为 mwe_r2 函数显式地将粘贴结果强制转换为数字。

      如果您阅读 ?paste ,您会看到明确描述了该函数:

      连接字符串 描述 转换后连接向量 性格。

      paste0() 总是会给你作为角色的结果。这正是正在发生的事情。因此,如果您想要数字数据,您需要将结果强制转换为数字。

      【讨论】:

      • row[["x"]] 有什么不同? x 列仍然是数字类型。
      • 不,不是,看看中间步骤。我会补充一些细节。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-24
      • 1970-01-01
      • 2021-06-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多