2013-03-19 7 views
18

Mam ramkę danych z liczbową zmienną ID, która identyfikuje podstawowe, drugorzędne i najlepsze jednostki próbkowania z wieloetapowego schematu próbkowania. Chcę podzielić się z oryginalną zmienną identyfikatora w trzech nowych zmiennych, identyfikując poszczególne jednostki pobierania próbek oddzielnie:Jak podzielić liczbę na cyfry w R

Przykład:

>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 

Czego chcę:

>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 

wiem, istnieją pewne funkcje dostępne w R, aby podzielić ciąg znaków, ale nie mogłem znaleźć tych samych obiektów dla liczb.

Dziękuję

Juan

+4

dlaczego nie spróbować przekształcić swój identyfikator do łańcucha z 'as.character()' następnie użyć 'strsplit()', a następnie z powrotem do numerów z 'as.numeric()'? – user974514

+0

Tak, może tak być, ale szukałem funkcji, która mogłaby być bezpośrednio użyta na numerycznej. Mimo wszystko dziekuję. –

Odpowiedz

10

Jeszcze inny alternatywny jest ponowne odczytanie pierwszej kolumny przy użyciu read.fwf i określenie szerokości:

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 

Jedną z zalet jest możliwość ustawienia wynikowych nazw kolumn w wygodny sposób i zapewnienie, że kolumny są znaków, zachowując w ten sposób wszelkie wiodące zera, które mogą być obecne.

+0

Jest to jeszcze szybsze niż wcześniejsze podejście. Dziękuję Ci!! –

18

Można użyć na przykład użyć 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

Dokładnie to, czego potrzebuję i tylko w jednej linii. Niż bardzo. –

5

To powinno działać:

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. 

lub przy substr()

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

Kolejne inteligentne podejście. Niż Ty! –

5

Ponieważ są to liczby, musisz wykonać kilka czynności matematycznych, aby wyodrębnić pożądane cyfry. Szereg reprezentowane w radix-10 można zapisać jako:

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

Dlatego, aby wyodrębnić najbardziej znaczącą cyfrę z numeru 6-cyfrowy, który jest matematycznie przedstawiona w postaci:

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

Jak widać , dzieląc tę ​​liczbę przez 10^5 otrzymasz:

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

Voila! Teraz wyodrębniasz najbardziej znaczącą cyfrę, jeśli interpretujesz wynik jako liczbę całkowitą, ponieważ wszystkie pozostałe cyfry mają teraz masę mniejszą niż 0, a zatem są mniejsze niż 1. Możesz wykonać podobne czynności, aby wyodrębnić inne cyfry. W przypadku cyfr o najmniej znaczącej pozycji można wykonać operację modulo zamiast podziału.

Przykłady:

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

W R możesz użyć podziału liczb całkowitych: '% /%' a operatorem modulo jest '%%' – hadley

+0

Dziękuję, sprytny sposób, który z pewnością przyda się również –

3

Jeśli nie chcesz przekonwertować do character z jakiegoś powodu, po to jedna z okazji, aby osiągnąć to, co chcesz

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, Rozumiem. Dziś muszę powiedzieć, że nauczyłem się wszystkiego, czego potrzebuję w teraźniejszości i przyszłej, jak podzielić liczbę! ;-) –

2

Przy tak wielu odpowiedzi, to czułem się jakbym musiał coś wymyślić :)

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

Bardzo interesująca funkcja. Dziękuję Ci! –

4

Kilka schludne odpowiedzi zostały wykonane lat temu, ale to rozwiązanie znaleźć przydatne, używając funkcji outer, nie ma wspomniano. W tym wieku wyszukiwarek, umieściłem go tutaj, na wypadek gdyby inni mogli go znaleźć.

Miałem do czynienia z nieco prostszym problemem: przekształcenie kolumny z 6 cyfr w 6 kolumn reprezentujących każdą cyfrę. Można to rozwiązać, stosując kombinację outer, podział całkowity (%/%) i 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 

Pytanie tutaj zadane jest nieco bardziej złożone, wymagające różnych wartości zarówno dla dzielenia całkowitoliczbowego, jak i 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