J'ai le data.frame ci-dessous. Je souhaite ajouter une colonne qui classe mes données en fonction de la colonne 1 (h_no
), de sorte que la première série de h_no 1,2,3,4 correspond à la classe 1, la deuxième série de h_no
(1 à 7) correspond à la classe 2 etc. comme indiqué dans la dernière colonne.
h_no h_freq h_freqsq
1 0.09091 0.008264628 1
2 0.00000 0.000000000 1
3 0.04545 0.002065702 1
4 0.00000 0.000000000 1
1 0.13636 0.018594050 2
2 0.00000 0.000000000 2
3 0.00000 0.000000000 2
4 0.04545 0.002065702 2
5 0.31818 0.101238512 2
6 0.00000 0.000000000 2
7 0.50000 0.250000000 2
1 0.13636 0.018594050 3
2 0.09091 0.008264628 3
3 0.40909 0.167354628 3
4 0.04545 0.002065702 3
Vous pouvez ajouter une colonne à vos données en utilisant diverses techniques. Les guillemets ci-dessous proviennent de la section "Détails" du texte d'aide correspondant, [[.data.frame
.
Les trames de données peuvent être indexées selon plusieurs modes. Lorsque
[
et[[
sont utilisés avec un seul index vectoriel (x[i]
oux[[i]]
), ils indexent le bloc de données comme s'il s'agissait d'une liste.
my.dataframe["new.col"] <- a.vector
my.dataframe[["new.col"]] <- a.vector
La méthode data.frame pour
$
traitex
comme une liste
my.dataframe$new.col <- a.vector
Lorsque
[
et[[
sont utilisés avec deux index (x[i, j]
etx[[i, j]]
), ils agissent comme une indexation d'une matrice.
my.dataframe[ , "new.col"] <- a.vector
Puisque la méthode pour data.frame
suppose que si vous ne spécifiez pas si vous travaillez avec des colonnes ou des lignes, cela supposera que vous entendez des colonnes.
Pour votre exemple, cela devrait fonctionner:
# make some fake data
your.df <- data.frame(no = c(1:4, 1:7, 1:5), h_freq = runif(16), h_freqsq = runif(16))
# find where one appears and
from <- which(your.df$no == 1)
to <- c((from-1)[-1], nrow(your.df)) # up to which point the sequence runs
# generate a sequence (len) and based on its length, repeat a consecutive number len times
get.seq <- mapply(from, to, 1:length(from), FUN = function(x, y, z) {
len <- length(seq(from = x[1], to = y[1]))
return(rep(z, times = len))
})
# when we unlist, we get a vector
your.df$group <- unlist(get.seq)
# and append it to your original data.frame. since this is
# designating a group, it makes sense to make it a factor
your.df$group <- as.factor(your.df$group)
no h_freq h_freqsq group
1 1 0.40998238 0.06463876 1
2 2 0.98086928 0.33093795 1
3 3 0.28908651 0.74077119 1
4 4 0.10476768 0.56784786 1
5 1 0.75478995 0.60479945 2
6 2 0.26974011 0.95231761 2
7 3 0.53676266 0.74370154 2
8 4 0.99784066 0.37499294 2
9 5 0.89771767 0.83467805 2
10 6 0.05363139 0.32066178 2
11 7 0.71741529 0.84572717 2
12 1 0.10654430 0.32917711 3
13 2 0.41971959 0.87155514 3
14 3 0.32432646 0.65789294 3
15 4 0.77896780 0.27599187 3
16 5 0.06100008 0.55399326 3
Facilement: votre bloc de données est un
b <- A[,1]
b <- b==1
b <- cumsum(b)
Ensuite, vous obtenez la colonne b.
Si je comprends bien la question, vous souhaitez détecter si le h_no
n'augmente pas, puis incrémenter la class
. (Je vais expliquer comment j'ai résolu ce problème, il y a une fonction autonome à la fin.)
Nous ne nous intéressons qu'à la colonne h_no
pour le moment, nous pouvons donc extraire cela du bloc de données:
> h_no <- data$h_no
Nous voulons détecter quand h_no
ne monte pas, ce que nous pouvons faire en déterminant quand la différence entre les éléments successifs est négative ou nulle. R fournit la fonction diff
qui nous donne le vecteur des différences:
> d.h_no <- diff(h_no)
> d.h_no
[1] 1 1 1 -3 1 1 1 1 1 1 -6 1 1 1
Une fois que nous avons cela, il est simple de trouver ceux qui ne sont pas positifs:
> nonpos <- d.h_no <= 0
> nonpos
[1] FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[13] FALSE FALSE
Dans R, TRUE
et FALSE
sont fondamentalement identiques à 1
et 0
; ainsi, si nous obtenons la somme cumulative de nonpos
, elle augmentera de 1 dans (presque) les emplacements appropriés. La fonction cumsum
(qui est fondamentalement le contraire de diff
) peut le faire.
> cumsum(nonpos)
[1] 0 0 0 1 1 1 1 1 1 1 2 2 2 2
Mais, il y a deux problèmes: les chiffres sont un trop petit; et, il nous manque le premier élément (il devrait y en avoir quatre dans la première classe).
Le premier problème est simplement résolu: 1+cumsum(nonpos)
. Et le second nécessite simplement l’ajout d’un 1
à l’avant du vecteur, car le premier élément est toujours dans la classe 1
:
> classes <- c(1, 1 + cumsum(nonpos))
> classes
[1] 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3
Maintenant, nous pouvons le rattacher à notre cadre de données avec cbind
(en utilisant la syntaxe class=
, nous pouvons donner à la colonne l'en-tête class
):
> data_w_classes <- cbind(data, class=classes)
Et data_w_classes
contient maintenant le résultat.
Nous pouvons compresser les lignes ensemble et envelopper le tout dans une fonction facilitant son utilisation:
classify <- function(data) {
cbind(data, class=c(1, 1 + cumsum(diff(data$h_no) <= 0)))
}
Ou, puisqu'il est logique que class
soit un facteur:
classify <- function(data) {
cbind(data, class=factor(c(1, 1 + cumsum(diff(data$h_no) <= 0))))
}
Vous utilisez soit une fonction comme:
> classified <- classify(data) # doesn't overwrite data
> data <- classify(data) # data now has the "class" column
(Cette méthode de résolution de ce problème est bonne car elle évite les itérations explicites, ce qui est généralement recommandé pour R, et évite de générer beaucoup de vecteurs intermédiaires et de listes etc. Et c'est aussi très bien comment on peut l'écrire sur une ligne :))
En plus de la réponse de Roman, une telle chose pourrait être encore plus simple. Notez que je ne l’ai pas testé car je n’ai pas accès à R pour le moment.
# Note that I use a global variable here
# normally not advisable, but I liked the
# use here to make the code shorter
index <<- 0
new_column = sapply(df$h_no, function(x) {
if(x == 1) index = index + 1
return(index)
})
La fonction parcourt les valeurs dans n_ho
et renvoie toujours la catégorie à laquelle la valeur actuelle appartient. Si une valeur de 1
est détectée, nous augmentons la variable globale index
et continuons.
Data.frame[,'h_new_column'] <- as.integer(Data.frame[,'h_no'], breaks=c(1, 4, 7))
Approche basée sur le nombre de groupes (x
dans mapply
) et sa longueur (y
dans mapply
)
mytb<-read.table(text="h_no h_freq h_freqsq group
1 0.09091 0.008264628 1
2 0.00000 0.000000000 1
3 0.04545 0.002065702 1
4 0.00000 0.000000000 1
1 0.13636 0.018594050 2
2 0.00000 0.000000000 2
3 0.00000 0.000000000 2
4 0.04545 0.002065702 2
5 0.31818 0.101238512 2
6 0.00000 0.000000000 2
7 0.50000 0.250000000 2
1 0.13636 0.018594050 3
2 0.09091 0.008264628 3
3 0.40909 0.167354628 3
4 0.04545 0.002065702 3", header=T, stringsAsFactors=F)
mytb$group<-NULL
positionsof1s<-grep(1,mytb$h_no)
mytb$newgroup<-unlist(mapply(function(x,y)
rep(x,y), # repeat x number y times
x= 1:length(positionsof1s), # x is 1 to number of nth group = g1:g3
y= c( diff(positionsof1s), # y is number of repeats of groups g1 to penultimate (g2) = 4, 7
nrow(mytb)- # this line and the following gives number of repeat for last group (g3)
(positionsof1s[length(positionsof1s )]-1 ) # number of rows - position of penultimate group (g2)
) ) )
mytb
vous pouvez d'abord ajouter une colonne vide à votre data.frame puis spécifier vos conditions pour la nouvelle colonne,
agtoexcel2$NONloan <- NA
agtoexcel2$NONloan[agtoexcel2$haveloan==2 & agtoexcel2$ifoloan==2 & agtoexcel2$both==0 ] <- 1
agtoexcel2$NONloan[agtoexcel2$haveloan==1 | agtoexcel2$ifoloan==1 | agtoexcel2$both==1 ] <- 0
Selon moi, utiliser "cbind" est le moyen le plus simple d’ajouter une colonne à une trame de données en R. Ci-dessous un exemple:
myDf = data.frame(index=seq(1,10,1), Val=seq(1,10,1))
newCol= seq(2,20,2)
myDf = cbind(myDf,newCol)