【问题标题】:How to split a number into digits in R如何在R中将数字拆分为数字
【发布时间】:2013-03-08 01:16:46
【问题描述】:

我有一个带有数字 ID 变量的数据框,用于标识多级抽样方案中的主要、次要和最终抽样单位。我想将原来的 ID 变量拆分成三个新变量,分别标识不同的采样单元:

例子:

>df[1:2,]
ID Var        var1     var2      var3     var4         var5  
501901          9    SP.1          1        W         12.10    
501901          9    SP.1          2        W         17.68  

我想要什么:

>df[1:2,]
ID1    ID2     ID3   var1   var2  var3     var4    var5  
5      01      901    9    SP.1    1        W     12.10    
5      01      901    9    SP.1    2        W     17.68  

我知道 R 中有一些函数可用于拆分字符串,但我找不到相同的数字工具。

谢谢,

胡安

【问题讨论】:

  • 你为什么不尝试使用as.character()将你的id转换为字符串,然后使用strsplit(),然后再使用as.numeric()返回数字?
  • 是的,可能是这样,但我正在寻找一个可以直接用于数字的函数。还是谢谢你。

标签: r split dataframe


【解决方案1】:

您可以使用例如substring:

df <- data.frame(ID = c(501901, 501902))

splitted <- t(sapply(df$ID, function(x) substring(x, first=c(1,2,4), last=c(1,3,6))))
cbind(df, splitted)
#      ID 1  2   3
#1 501901 5 01 901
#2 501902 5 01 902

【讨论】:

  • 正是我需要的,而且只需一行。非常比你。
【解决方案2】:

另一个替代方法是使用read.fwf 重新读取第一列并指定宽度:

cbind(read.fwf(file = textConnection(as.character(df[, 1])), 
               widths = c(1, 2, 3), colClasses = "character", 
               col.names = c("ID1", "ID2", "ID3")), 
      df[-1])
#   ID1 ID2 ID3 var1 var2 var3 var4  var5
# 1   5  01 901    9 SP.1    1    W 12.10
# 2   5  01 901    9 SP.1    2    W 17.68

这里的一个优点是能够以方便的方式设置生成的列名,并确保列是字符,从而保留可能存在的任何前导零。

【讨论】:

  • 这比之前的方法还要快。谢谢!!
【解决方案3】:

这应该可行:

df <- cbind(do.call(rbind, strsplit(gsub('(.)(..)(...)', '\\1 \\2 \\3', paste(df[,1])),' ')), df[,-1]) # You need that paste() there because gsub() works only with text.

substr()

df <- cbind(ID1=substr(df[, 1],1,1), ID2=substr(df[, 1],2,3), ID3=substr(df[, 1],4,6), df[, -1])

【讨论】:

  • 另一种聪明的方法。比你!
【解决方案4】:

由于它们是数字,因此您必须做一些数学运算来提取您想要的数字。以 radix-10 表示的数字可以写成:

d0*10^0 + d1*10^1 + d2*10^2 ... etc. where d0..dn are the digits of the number.

因此,要从数学上表示为的 6 位数字中提取最高有效位:

number = d5*10^5 + d4*10^4 + d3*10^3 + d2*10^2 + d1*10^1 + d0*10^0

如您所见,将此数字除以 10^5 即可得到:

number / 10^5 = d5*10^0 + d4*10^(-1) + d3*10^(-2) + d2*10^(-3) + d1*10^(-4) + d0*10^(-5)

瞧!现在,如果您将结果解释为整数,您已经提取了最高有效数字,因为所有其他数字现在的权重都小于 0,因此小于 1。您可以执行类似的操作来提取其他数字。对于最低有效位的数字,您可以进行模运算而不是除法。

例子:

501901 / 10^5 = 5 // first digit
501901 % 10^5 = 1 // last digit
(501901 / 10^4) % 10^1 = 0 // second digit
(501901 / 10^2) % 10^2 = 19 // third and fourth digit

【讨论】:

  • 在R中,可以使用整数除法:%/%,取模运算符为%%
  • 谢谢你,一个聪明的方法,肯定也会有用
【解决方案5】:

几年前已经提出了几个巧妙的答案,但我认为使用outer 函数的有用解决方案尚未提及。在这个搜索引擎时代,我把它放在这里以防其他人可以找到它。

我遇到了一个稍微简单的问题:将一列 6 位数字转换为代表每个数字的 6 列。这可以使用outer、整数除法 (%/%) 和模数 (%%) 的组合来解决。

 DF <- data.frame("ID" = runif(3)*10^6, "a" = sample(letters, 3,T))
 DF <- cbind(DF, "ID" = outer(DF$ID, 10^c(5:0), function(a, b) a %/% b %% 10))
 DF
#       ID a ID.1 ID.2 ID.3 ID.4 ID.5 ID.6
# 1 814895 z    8    1    4    8    9    5
# 2 417209 q    4    1    7    2    0    9
# 3 545797 c    5    4    5    7    9    7

这里提出的问题稍微复杂一些,整数除法和模数都需要不同的值。

 DF <- data.frame("ID" = runif(3)*10^6, "a" = sample(letters, 3,T))
 DF <- cbind(DF, "ID" = outer(DF$ID, c(1:3), function(a,b) a %/% 10^c(5,3,0)[b] %% 10^b))
 DF
#      ID a ID.1 ID.2 ID.3
# 1 809372 q    8    9  372
# 2 954790 g    9   54  789
# 3 166970 l    1   66  969

【讨论】:

    【解决方案6】:

    如果您出于某种原因不想转换为character,以下是实现您想要的方法之一

    DF <- data.frame(ID = c(501901, 501902), var1 = c("a", "b"), var2 = c("c", "d"))
    
    result <- t(sapply(DF$ID, function(y) {
        c(y%/%1e+05, (y - y%/%1e+05 * 1e+05)%/%1000, y - y%/%1000 * 1000)
    }))
    
    
    DF <- cbind(result, DF[, -1])
    
    names(DF)[1:3] <- c("ID1", "ID2", "ID3")
    
    DF
    ##   ID1 ID2 ID3 var1 var2
    ## 1   5   1 901    a    c
    ## 2   5   1 902    b    d
    

    【讨论】:

    • 好的,知道了。今天我不得不说,我学到了所有我现在和未来需要的关于如何拆分数字的知识! ;-)
    【解决方案7】:

    有这么多答案,我觉得我需要想出一些东西:)

    library(qdap)
    x <- colSplit(dat$ID_Var, col.sep="")
    data.frame(ID1=x[, 1], ID2=paste2(x[, 2:3], sep=""), 
        ID3=paste2(x[, 4:6],sep=""), dat[, -1])
    
    ##   ID1 ID2 ID3 var1 var2 var3 var4  var5
    ## 1   5  01 901    9 SP.1    1    W 12.10
    ## 2   5  01 901    9 SP.1    2    W 17.68
    

    【讨论】:

    • 非常有趣的功能。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-14
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 2010-12-26
    相关资源
    最近更新 更多