2013-03-19 12 views
18

Ho un frame di dati con una variabile numerica ID che identifica le unità di campionamento primarie, secondarie e finali da uno schema di campionamento multistadio. Voglio dividere la variabile ID originale in tre nuove variabili, identificando le diverse unità di campionamento separatamente:Come dividere un numero in cifre in R

Esempio:

>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 

Quello che voglio:

>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 

io ci so è alcune funzioni disponibile in R per dividere le stringhe di caratteri, ma non sono riuscito a trovare le stesse funzionalità per i numeri.

Grazie,

Juan

+4

perché non provare convertire la id per stringa con 'as.character()' quindi di utilizzare 'strsplit()' e poi di nuovo a numeri con 'as.numeric()'? – user974514

+0

Sì, potrebbe essere in questo modo, ma stavo cercando una funzione che potrebbe essere utilizzata direttamente in formato numerico. Grazie lo stesso. –

risposta

10

Ancora un'altra alternativa è rileggere la prima colonna utilizzando read.fwf e specificare le larghezze:

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 

Un vantaggio qui è la possibilità di impostare i nomi delle colonne risultanti in un modo conveniente e assicurarsi che le colonne siano caratteri, conservando così eventuali zeri iniziali che potrebbero essere presenti.

+0

Questo è ancora più veloce dell'approccio precedente. Grazie!! –

18

Si potrebbe utilizzare ad esempio utilizzare 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 
+0

Esattamente quello di cui ho bisogno, e solo in una riga. Di te molto. –

5

Questo dovrebbe funzionare:

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. 

O con substr()

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

Un altro approccio intelligente. Di te! –

5

Poiché si tratta di numeri, è necessario eseguire alcuni calcoli per estrarre le cifre desiderate. Un numero rappresentato in radix-10 può essere scritta come:

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

Così, per estrarre la cifra più significativa da un numero di 6 cifre, che è matematicamente rappresentato come:

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

Come si può vedere , dividendo questo numero per 10^5:

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

Voilà! Ora hai estratto la cifra più significativa se interpreti il ​​risultato come un numero intero, poiché tutte le altre cifre ora hanno un peso inferiore a 0 e quindi sono più piccole di 1. Puoi fare cose simili per estrarre le altre cifre. Per le cifre in posizione meno significativa, è possibile eseguire operazioni modulo anziché divisione.

Esempi:

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 
+2

In R, puoi usare la divisione intero: '% /%' e l'operatore modulo è '%%' – hadley

+0

Grazie, un modo intelligente che di sicuro sarà utile anche –

3

Se non si vuole convertire in character per qualche ragione, che segue è uno dei modi per ottenere ciò che si vuole

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 
+0

ok, capito. Oggi devo dire che ho imparato tutto ciò di cui ho bisogno nel presente e nel prossimo futuro su come dividere un numero !! ;-) –

2

Con così tante risposte si sentiva come avevo bisogno di venire con qualcosa :)

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 
+0

Funzione molto interessante. Grazie! –

4

più risposte accurate sono state fatte anni fa, ma una soluzione che trovo utile, utilizzando la funzione outer, non ha stato menzionato. In questa era di motori di ricerca, l'ho messo qui nel caso in cui altri potessero trovarlo a portata di mano.

mi trovai di fronte a un problema un po 'più semplice: trasformare una colonna di numeri a 6 cifre in 6 colonne che rappresentano ogni cifra. Questo può essere risolto utilizzando una combinazione di outer, divisione intera (%/%) e modulo (%%).

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 

La domanda posta qui è leggermente più complessa e richiede valori diversi sia per la divisione intera che per il modulo.

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 
Problemi correlati