Comme mon titre l'indique, je souhaite "faire pousser" des amas de cellules à partir de graines dans un raster. Mon raster de base est plein de 1 et de 0, 1 indique la terre et 0 la mer / NA. À partir des 1, je souhaite sélectionner 60 pixels / cellules aléatoires comme graines, puis développer aléatoirement un groupe connecté d'un non prédéfini. de pixels / cellules limite à partir de cette graine. J'ai entendu dire que la technique peut être qualifiée de «colorant à tartiner», mais je n'ai pas eu de chance d'en trouver beaucoup. La cellule de graine serait transformée à une valeur de 2, puis la cellule suivante choisie parmi les 1 environnants serait également convertie en 2. Les 2 ne sont alors plus disponibles pour être convertis à l'avenir.
Ce fil aide un peu, car je serais également disposé à le faire dans R car je suis familier avec la lecture et la manipulation des données SIG dans R. Cependant, ce dont j'ai besoin est un ensemble de règles pour sélectionner au hasard les pixels entourant un groupe existant .
Si quelqu'un a fait cette forme plus basique d'automates cellulaires dans un environnement SIG, j'apprécierais tout conseil / orientation.
Exemple:
J'ai un objectif de 250 cellules. Je sélectionne au hasard une cellule qui a une valeur de 1. Ceci est transformé en une valeur de 2. Ensuite, l'un des voisins de la cellule de semence qui = 1 est transformé en un 2. Ensuite, l'un des voisins de l'une ou l'autre des cellules avec une valeur 2 est sélectionnée et transformée en 2. Cela continuerait jusqu'à ce qu'une forme continue numérotée de 250 cellules soit atteinte.
Edit: Autres questions
Basé sur la grande réponse de whuber, j'ai quelques questions sur le code:
- Comment puis-je attribuer les valeurs des cellules cultivées à un «2» plutôt qu'à des valeurs variables qui représentent l'ordre dans lequel elles ont été créées?
- J'ai besoin de créer 60 amas de cellules dans ma zone de 1. J'ai imaginé des façons de choisir des positions de départ aléatoires, mais j'ai du mal à le faire fonctionner dans une boucle en utilisant la
expand
fonction que vous avez aimablement écrite. Pouvez-vous suggérer un moyen de créer 60 blocs qui ne se heurtent pas les uns aux autres et sont contenus dans la même matrice finale?
Edit: Explication supplémentaire du problème
Chaque groupe de cellules représentera une zone protégée d'une taille définie, par exemple 250 cellules. Chaque zone doit commencer et se développer en cellules avec une valeur de 1 car cela représente la terre et éviter les cellules avec une valeur de 0, car cela représente la mer. J'ai besoin d'itérer cette 1000 fois avec 60 zones protégées à chaque itération pour créer un modèle nul, montrant quelles distributions de ces zones seront par hasard. Pour cette raison, le nombre total de cellules dans les 60 zones devra être identique dans chacune des 1000 itérations afin qu'elles soient comparables. Par conséquent, c'est ok si les zones se touchent, mais s'il y a une collision, alors idéalement, la touffe se développerait dans une autre direction disponible jusqu'à ce que l'objectif de 250 soit atteint.
Une fois que chacun de ces 1000 réseaux d'aires protégées sera créé, ils seront utilisés comme masque contre d'autres données matricielles telles que les mesures de biodiversité pour voir (a) si elles croisent des gammes d'espèces particulières et (b) quel% d'espèces particulières range ces réseaux aléatoires des aires protégées couvrent.
Merci à @whuber pour votre aide jusqu'à présent, je ne m'attends pas à ce que vous passiez plus de temps à m'aider, mais j'ai pensé que j'essaierais de clarifier ma situation comme vous l'avez demandé.
Réponses:
Je proposerai une
R
solution qui est codée de manière légèrement nonR
illustrée pour illustrer comment elle pourrait être abordée sur d'autres plateformes.La préoccupation de
R
(ainsi que de certaines autres plates-formes, en particulier celles qui favorisent un style de programmation fonctionnel) est que la mise à jour constante d'un grand tableau peut être très coûteuse. Au lieu de cela, cet algorithme conserve sa propre structure de données privées dans laquelle (a) toutes les cellules qui ont été remplies jusqu'à présent sont répertoriées et (b) toutes les cellules qui peuvent être choisies (autour du périmètre des cellules remplies) sont répertoriés. Bien que la manipulation de cette structure de données soit moins efficace que l'indexation directe dans un tableau, en conservant les données modifiées à une petite taille, cela prendra probablement beaucoup moins de temps de calcul. (Aucun effort n'a été fait pour l'optimiserR
non plus. La pré-allocation des vecteurs d'état devrait permettre de gagner du temps d'exécution, si vous préférez continuer à travailler à l'intérieurR
.)Le code est commenté et doit être simple à lire. Pour rendre l'algorithme aussi complet que possible, il n'utilise aucun module complémentaire, sauf à la fin pour tracer le résultat. La seule partie délicate est que pour l'efficacité et la simplicité, il préfère indexer dans les grilles 2D en utilisant des index 1D. Une conversion se produit dans la
neighbors
fonction, qui a besoin de l'indexation 2D afin de comprendre ce que pourraient être les voisins accessibles d'une cellule, puis les convertit en index 1D. Cette conversion est standard, donc je ne commenterai pas plus loin, sauf pour souligner que dans d'autres plates-formes SIG, vous voudrez peut-être inverser les rôles des index de colonnes et de lignes. (DansR
, les index de ligne changent avant les index de colonne.)Pour illustrer, ce code prend une grille
x
représentant la terre et une caractéristique semblable à une rivière de points inaccessibles, commence à un emplacement spécifique (5, 21) dans cette grille (près du coude inférieur de la rivière) et l'étend au hasard pour couvrir 250 points . Le chronométrage total est de 0,03 seconde. (Lorsque la taille du tableau est augmentée d'un facteur de 10 000 à 3 000 lignes par 5 000 colonnes, le délai ne monte que jusqu'à 0,09 seconde - un facteur de 3 environ - ce qui démontre l'évolutivité de cet algorithme.) Au lieu de produisant juste une grille de 0, 1 et 2, il sort la séquence avec laquelle les nouvelles cellules ont été allouées. Sur la figure, les premières cellules sont vertes, passant de l'or à la couleur saumon.Il doit être évident qu'un voisinage en huit points de chaque cellule est utilisé. Pour les autres quartiers, modifiez simplement la
nbrhood
valeur vers le début deexpand
: c'est une liste de décalages d'index par rapport à une cellule donnée. Par exemple, un voisinage "D4" pourrait être spécifié commematrix(c(-1,0, 1,0, 0,-1, 0,1), nrow=2)
.Il est également évident que cette méthode d'épandage a ses problèmes: elle laisse des trous. Si ce n'est pas ce qui était prévu, il existe plusieurs façons de résoudre ce problème. Par exemple, conservez les cellules disponibles dans une file d'attente afin que les premières cellules trouvées soient également les plus anciennes remplies. Une certaine randomisation peut toujours être appliquée, mais les cellules disponibles ne seront plus choisies avec des probabilités uniformes (égales). Une autre façon, plus compliquée, serait de sélectionner les cellules disponibles avec des probabilités qui dépendent du nombre de voisins remplis qu'elles ont. Une fois qu'une cellule est entourée, vous pouvez augmenter ses chances de sélection de manière à ce qu'il reste peu de trous non remplis.
Je terminerai en commentant que ce n'est pas tout à fait un automate cellulaire (CA), qui ne procéderait pas cellule par cellule, mais mettrait à jour des pans entiers de cellules à chaque génération. La différence est subtile: avec l'AC, les probabilités de sélection des cellules ne seraient pas uniformes.
Avec de légères modifications, nous pouvons effectuer une boucle
expand
pour créer plusieurs clusters. Il convient de différencier les clusters par un identifiant, qui s'exécutera ici 2, 3, ..., etc.Tout d'abord, changez
expand
pour retourner (a)NA
à la première ligne s'il y a une erreur et (b) les valeurs dansindices
plutôt qu'une matricey
. (Ne perdez pas de temps à créer une nouvelle matricey
à chaque appel.) Une fois cette modification effectuée, le bouclage est facile: choisissez un démarrage aléatoire, essayez de vous développer autour de lui, accumulez les index de cluster enindices
cas de succès et répétez jusqu'à ce que cela soit fait. Un élément clé de la boucle est de limiter le nombre d'itérations dans le cas où de nombreux clusters contigus ne peuvent pas être trouvés: cela se fait aveccount.max
.Voici un exemple où 60 centres de grappes sont choisis uniformément au hasard.
Voici le résultat lorsqu'il est appliqué à une grille de 310 par 500 (rendue suffisamment petite et grossière pour que les grappes soient apparentes). L'exécution prend deux secondes; sur une grille de 3100 par 5000 (100 fois plus grande), cela prend plus de temps (24 secondes) mais le timing évolue assez bien. (Sur d'autres plateformes, telles que C ++, le timing ne devrait guère dépendre de la taille de la grille.)
la source
y[indices] <- 1:length(indices)
pary[indices] <- 2
. La réponse à # 2 est presque aussi simple: il suffit de boucler.size.clusters
. Comment puis-je m'assurer qu'un agrégat atteint la taille correcte, car, pour le moment, je suppose qu'il essaie de devenir un agrégat existant, échoue, mais s'inscrit toujours comme une expansion réussie. J'ai également l'intention d'itérer la production des 60 blocs 1000 fois en créant un ensemble de données de style de modèle nul moyen. Le positionnement aléatoire varierait-il à chaque fois dans unefor
boucle?Sans jamais avoir effectué votre opération, et sans avoir de temps à perdre pour jouer, je ne peux qu'ajouter ces deux liens à votre liste:
Trouvez la valeur de cellule raster la plus proche basée sur un point vectoriel (La première réponse (avec 4 votes) m'a intrigué).
Aussi: Hawth's Gridspread pourrait-il aider?
la source