代表查找的三元图数据

时间:2012-09-20 19:58:54

标签: c# data-structures

Soil Types

我试图在这个三元图上表示数据以进行查找。我希望能够将所有三个值都输入到函数中,并返回这些值属于哪个区域类别。我正在研究的方法是使用笛卡尔坐标将每个区域转换为多边形。然后将提供的值转换为一个点,并检查该点是否位于哪个多边形内。我很确定它会起作用,但对于简单的查找来说这似乎有些过分了?

我问是否有办法在数组或对象中表示此图上的数据,以便简单查找就足够了?

2 个答案:

答案 0 :(得分:4)

可以将上述内容翻译成笛卡尔坐标系,但我认为你错过了实际执行此操作所需要的重要方面。

在上图中,您将多边形视为二维结构,但是您有一个三维点。毕竟,我们在上面的二维平面上看到三角形并非不可能,但是笛卡尔空间的转换并不是那么简单。

相反,它看起来像非常,就像decision tree的图形表示一样。看起来像粘土,淤泥和沙子的数量的读数来发展这种表现。

基本上,您有三个值的元组,并且您希望根据这些值进行分类。

在上面的案例中,您可以将分类“淤泥”的决策树建模为:

// These are approximate based on above.  Each branch of the
// tree is evaluated on one value out of all the values.
if (silt >= .8)
{
    // True case.  Check sand content.
    if (sand >= .20)
    {
        // Something else, other branches.
    }
    else
    {
        // False case, can possibly be silt.
        if (clay >= .125)
        {
            // Something else, other branches.
        }
        else
        {
            // Leaf, this is a classification.
            // Can return more strongly typed classification if you want.
            return "silt";
        }            
    }

}
else
{
    // Something else, other branches.
}

每个if / else语句代表决策树中的一个分支。在每个分支中,您将要评估变量的值,该变量的值在分支中为您提供最多information gain(几乎听起来像是什么,您可以分类多少根据对该变量做出决定的entropy(或不确定性)进行分割?)

树木可以自动生成,也可以自己手动编码。虽然后者是可能的,但我强烈建议使用自动/基于代码的方法来开发它。我强烈建议您查看Accord.NET(需要AForge.NET,两者都优秀)。为了帮助您入门,您应该看一下blog post showing how to create decision trees using Accord.NET

无论你走哪条路,你最终都会得到一个函数,它取三个值(粘土,淤泥和沙子)并返回你的分类,根据每个值的值遍历树。

请注意,您不一定会有一对一的标准(分支)映射到每个分类(如第一个代码示例中所示)。根据上例中多边形的顶点数量,您需要额外的分支来处理这些情况。

如果您有原始样本数据,那么您只需通过决策树构建器运行样本数据,它应该创建一个类似上面的决策树。

如果您拥有原始样本数据,您可以使用上面的顶点创建来对其进行分类。例如:

silt    sand    clay    classification
----    ----    ----    --------------
   0      50     100    clay (top point)
 100       0      50    silt (right bottom point)
  50     100       0    sand (left bottom point)
  15      45      40    sandy clay OR clay cloam OR clay (depending on splits)
...

关于最后一行(以及后续行),决策树将根据这些值设置边界,因为它是continuous,它通常会根据大于或等于该值的所有值做出决策

答案 1 :(得分:1)

这样做的方法就像你所建议的那样,使用多边形方法中的“点”,我的意思是,当你在视觉上这样做时,这正是你在脑中所做的。接受的答案的问题是,虽然在这种情况下(和简单的情况)你可能能够建立一个决策树,对于有更多类别的情况,这个过程将变得更加复杂恕我直言。也许类别重叠,也许类别只是一个点,我在这里提出的过程,这些文物对结果没有任何影响。

我已经根据HERE包中提供的数据集,涵盖了ggtern,即USDA土壤分类图的制作,我在下面附上的结果。

enter image description here

但可能不太清楚的是,ggtern包具有一些功能,使其比现有技术稍微麻烦一些。具体来说,ggtern包中有一些内部函数(通常在后端使用)来进行必要的转换,以便针对参考类别评估每个点的多边形真值表中的点。

使用 plyr 包中的 ddply 函数以及 point.in.polygon 函数,这种方法非常直接 sp 包。

首先让我们加载必要的包,然后从ggtern加载USDA数据。让我们创建一些样本数据,测试这个过程,找到一个位于顶点上的点,以及一个位于分类区域中心的点!。

library(ggtern)
library(sp)
library(plyr)

#The Main Data to lookup against
data(USDA)

#The sample Data (Try a point at a vertice, and a point in the middle...)
testData = rbind(data.frame(Clay=.4,Sand=.2,Silt=.4), #Vertice point
                 data.frame(Clay=1,Sand=1,Silt=1)/3)  #Simple middle point

然后我建议使用内部函数transform_tern_to_cart(...)将两个数据集转换为笛卡尔坐标。

#Do the transformation to cartesian
USDA[,c("x","y")]     = transform_tern_to_cart(USDA$Clay,USDA$Sand,USDA$Silt)
testData[,c("x","y")] = transform_tern_to_cart(testData$Clay,testData$Sand,testData$Silt)

通过使用ddply(...)apply(...)的组合,我们可以通过使用point.in.polygon(...)函数,针对参考集中的每个类别测试测试集中的每个点。 / p>

#Create a function to do the lookup
lookup <- function(data=testData,lookupdata=USDA,groupedby="Label"){  
  if(!groupedby %in% colnames(lookupdata))
    stop("Groupedby value is not a column of the lookupdata")

  #For each row in the data
  outer = apply(data[,c("x","y")],1,function(row){

    #for each groupedby in the lookupdata
    inner = ddply(lookupdata,groupedby,function(df){
      if(point.in.polygon(row[1],row[2],df$x,df$y) > 0) #Is in polygon?
        return(df) #Return a valid dataframe
      else
        return(NULL) #Return nothing
    })

    #Extract the groupedby data from the table
    inner = unique(inner[,which(colnames(inner) == groupedby)])

    #Join together in csv string and return to 'outer'
    return(paste(as.character(inner),collapse=","))
  })

  #Combine with the original data and return
  return(cbind(data,Lookups=outer))
}

然后可以通过以下方式调用:

#Execute
lookup()

您会注意到第一个点满足四(4)个类别,第二个点只满足一个(1),这是预期的。