數據切片演算法
① 數據結構和演算法在實際的軟體開發中都有哪些
應用太多了。
基本上來說C#是基於面向對象語言,你所定義的所有類/結構體都算是數據結構,而且在.net類庫中已經定義中諸多可用的類型以供使用。實際開發中根本就離不開結構與演算法。
題主之所以有這樣的問題,基本上認識到了很多程序員易犯的一個毛病——理論知識與實際應用中的脫節問題,不少程序員都說自己寫程序用不上理論知識,或者是理論無用。我一直認為理論才是真正編程的指導,別說你所學的理論知識了,有時我們必須遵守一些軟體活動上的標准/規范/規定。比如ISO29500標准有多少程序員讀過或聽說過?他實事就是關於openxml的一個國際標准,我們要想達到通用的程序,這些標准還是讀一讀的好。
扯回你的問題,什麼是數據結構,什麼是演算法?如果你真的狹義理由數據結構,或者只是從課本上例子來說,數據結構被定義成一個只有屬性成員的類或結構體才算是數據結構嗎?事實上並不是,那麼是不是只有鏈表/棧/隊列才算是數據結構呢?可以說這是某些人狹義理解數據結構時的一種常規定勢思維,但事實上來說,類或結構是數據結構的基本,否則你鏈表存在的實體到底是什麼東西?所以數據結構包含著基本結構與狹義上的順序表/鏈表/棧/隊等存在實體的集體。為什麼我說數據結構在實際運用中廣泛體現呢?就數據結構而言,課本上只是為了講明白結構而已,弱化了其中實體的真正含義,而且不語言的具體實現亦不盡相同,所以他們所講的數據結構是基本理論的。
我來個例子:鏈表(C#語言)
publicclassMember
{
publicstringName{get;set;}
publicstringResponsibility{get;set;}
publicstringPosotion{get;set;}
}
publicclassMemberNode
{
publicMemberMember{get;set;}
publicMemberNext{get;set;}
}
//Node其他就是鏈表中的一個結點結構,這個結點結構除了指明當前的Member之下還指向下Next的下一個結構結構,它最終可以形成一個鏈表。這就是定義的一個鏈表。
從以上例子上你可以看出這是一個類似於課本的標準定義,但事實上在C#語法中存在泛型的特點,那麼這類似的結構我們不須要一個個地定義了!所以在不同的語言中為了方便編程者,我們甚至可以把這樣的結構進行簡單化,從而達到一種最簡單的使用方式。以C#為例,我們可以使用Node<T>來表示鏈表/List<T>表示順序表/Stack<T>表示棧/Queue<T>表示隊列,在這種情況下,我們只需要定義我們的泛型即可,結構鏈之類的本身使用泛型已經在類庫中實現了——雖然你不用定義,但不代表不使用或者不用理解這其中的知識。而在課本講理論的時候,他不可能附帶泛型來講的,所以很多人認為自己去定義數據結構才行,那才是「真正」的數據結構,其實不然。以鏈表為例,我們需要一個節點除了其實體意義之外,還存在指向下一結點的指針(其實是地址引用)才算是數據結構。根據課本,他們必須這么定義(C#):
publicclassMemberNode
{
publicstringName{get;set;}
publicstringResponsibility{get;set;}
publicstringPosition{get;set;}
publicMemberNodeNext{get;set;}
}
//死讀書的只會承認這種才是真正的數據結構吧(鏈表節點)
事實上,鏈表講的只是一種形式,能最終形成的一種組織數據結構的形式。這個代碼會導致我們出現一種極大的誤解——每個類型的結構都需要重新定義一次。如果有多個類型結構的話,我們會出現多個不同的定義,這會導致將來類的定義越來越多,對於維護上來說是比較麻煩的。由於設計模式/面向切片等各種開發方式的介入,我們會使用相對比較簡單的形式。所以才會有我定義兩個類的進步,而後可以出現泛型的更進一步。
你可以這樣理解,這種課本上的結構,會導致我們造成每種結構基本上都需要重新定義一次,我最開始給出的例子可以使用繼承的方式,實現某個基類的數據結構(下面的似乎也行,但在使用中可能會出現部分問題),而Node<T>則從根本上解決了這個問題,可以支撐多種類型。
所以此時在理解數據結構時,比如Node<T>,他不旦要求理解鏈表的節點,還要理解T泛型,那麼在數據結構上來說,它指的不再是單一的節點結構,還在包括一個基礎的類型。
換句話來說,你在C#等語言中已經不需要再做類似的定義了,只需要定義其基本結構類型即可。但課本上在講知識的時候,它不可能只針對面向對象或支持泛型的語言來講,若不支持泛型時,我們必須使用課本上或我最開始寫的例子中的形式,若不支持繼承的面向過程語言,那麼課本上的知識就是硬性的規定,你必須以這種形式來說,而引用則使用指針引用的方式(面向對象的引用其實是一種引用型引用,也就是址引用或稱地址引用,與指針類似)。
相信講到這里你能明白,數據結構在不同的語言中只是變了個形而已,並不是必須是存在指針的才是,也不是只說表面上的那點東西。早期教程都是以fortain語言為主的,而且課本的目的是講清道理,而不是一種規定。死讀書的人以為用不到數據結構,其實他們一直在使用。
再來說一下演算法,演算法是什麼?是解決問題的一種模式,比如解二元一次方程等等,所以演算法的定義其實已經告訴你,順序代碼他也算是一種演算法,不能說只有背包問題,八皇後問題,回溯問題才算是演算法——你能明白嗎?其實你正常寫的就是一種演算法,這種演算法簡單,就是順序執行下來就可以了,他也是一種演算法的,就算解二元一次方程組有固定的模式(演算法),但不代表加減法就不是演算法了!所以演算法也是常用的東西,那麼你學習的演算法其實算是開辟思路的一種而已。演算法自身的概念已經決定,基本上程序都是由結構與演算法構成。我也來舉個例子,怎麼判斷某個鏈表是否為循環鏈表?是你的回溯演算法,貪心演算法還是背包演算法?它們只是在解決一些典型問題的一種通用方式而已,很顯然,我的問題不是這種典型問題,但不代表他不典型,我們正常的演算法是設計兩個變數等於頭元素,然後開始進入循環,一個變數每次向下推一,即找到他下一個節點,而另一個變數每次找到其孫節點,就算當於兩個變數一個每次向下推進一次,而另一個每點推進兩次(如果可能),如果不是循環鏈表,則進兩次的那個會在鏈表總長度的一半時,遇到空引用,否則會在某一時間兩指針引用同一對象(不是對象相等,而是引用相同的對象),什麼意思呢,好象兩個人在圓型跑道上跑步,一個每秒1米,另一個每秒2米,同時同地同向出發,最歸跑得快的那個會追上跑得慢的那個!當然這種情況下你也可以給他起個名字,叫「追及演算法」?如果只有你學的那幾個典型演算法是演算法的話,這個算不算演算法?
現在我們的問題是,如果語言層面上已經實現了這些東西,那麼這些理論我們是否可以不用理解就可以了?答案是可以——如果你只是一個不思進取的程序員或允許bug亂飛的沒有責任心的編程人員的話,可以不用理解——畢竟有些人只是「混」飯吃而已!
理解了不會去應用,這就是典型的理論聯系不到實際,他們也不知道自己的代碼將如何控制。我舉一個例子,由於性能等各方面的要求,我們要使用多線程對某些數據進行處理。怎麼處理?不好人會使用多線程——他們定義一個臨界資源,然後讓多個線程在讀取數據表(DataSet)時進行阻塞,然後每個線程去處理那些超時長的問題,處理完的時個再按這種方式讀取數據——這樣有問題嗎?沒有,這也算是演算法的一種!反正如果編程代碼有功底的話沒有任何問題的,這種代碼算不算優雅呢——很多人認為代碼的優雅就是代碼編寫過程的形式或是良好的編程習慣!這里邊其實用不到數據結構與演算法的。
好吧,我承認,但如果我們換一句思路來看看,如果我用一個線程負責讀取數據,並不停地放入到一個隊列中,而多個線程從隊列中不停地讀取處理這些放入的數據,這樣如何?我的意思是說,並沒有直接在DataSet中處理,而是選擇使用隊列的方式。
我們看一個問題,這個隊列Queue<T>,一個線程用來插入數據,多個線程用來讀取數據,而且要保證不能重復,那麼我們可以使用隊列的安全版本(CorrentQueue<T>,在.net中如果非線程安全的情況下,多線程使用實應該找到其對應的安全版本或者控制線程安全)。
插入線程如果發現隊列中的長度(容量)較大時,可以暫緩插入。這樣可以保證隊列的長度基本固定,佔用內存得到控制(不是DataSet批量讀來一大堆),由於使用安全隊列,所以各線程不用考慮線程之間的安全問題,每個線程從隊中獲得數據並刪除,可以保證數據只被處理一次。當然還可以考慮優雅的通知機制,插入線程在插入數據時通知處理線程啟動,如果插入速度過快,發現插入數量達指定的長度(比如30個),停止插入,插入線程阻塞;處理處理再次處理時可通知插入線程再進行插入。
這也算是一種演算法吧?它可以讓插入線程與處理線程同時工作,而使用DataSet那種常規的結果時,只能是等待處理完或加入多個控制條件進行控制,既然這么控制的話,何不直接使用隊列的方式?CorrentQueue<T>中的T也完全可以是一條記錄DataRow嘛!
如果你認為第一種是你經常使用方式,那麼演算法對於你來說學與不學無所謂的,你必須使用自己的編程/調試功底以保證你的代碼盡量很少出錯或不出錯。而如果你認為第二種方案優雅一些的話,那麼你會認為你學習的演算法與結構還是有用的,理論與實踐結合了。
我之所以舉這么一個例子,其實告訴你的無非是幾點非常重要的信息:
你有選擇演算法的自由(只不過是代碼質量、後期維護的問題)
如果你知道的較多的演算法與結構,你會有更多的選擇。
演算法或結構在實際使用中,所謂的典型問題並不是使用場景和書上描述一模一樣(試想一下,我第二種考慮的例子中,是不是跟書上比他不典型?其實也是非常典型的)
分析問題時,應該拿要點,而不是整體去套。(如果整體去套用的話,你肯定會想不到使用哪種結構或演算法)
不管是數據結構/演算法/設計模式都要求是靈活運用,而不是場景對比使用,也不是生搬硬套。
試想一下,你的背包問題,怎麼可能公司也讓你分拆包裝?你的八皇後問題公司恰好讓你下棋?你的貪心演算法公司恰好讓你找零錢?你的回溯演算法公司恰好讓你走迷宮?學不能致用的原因就是太死板——這幾個舉個例子的場景你再遇到或理能遇到的機率是非常小的,所以如果覺得學了沒用,那就真沒用了——只不過不是演算法沒用,而是人沒人!
講個小故事:從前一個家人的板凳壞了,要找一個合適的兩股叉的樹杈重新製做一個板凳腿,讓孩子到樹園里找了半天,孩子回來說「我都沒見過有向下叉的樹杈!他老爹氣得要死——怎麼會可能有向下長的樹杈呢!這孩子是不是笨——你就不會把地刨了找一個向下分叉的樹根!
演算法也是一樣,迷宮找路可以使用回溯演算法,但不是所有的回溯演算法都用於迷宮找路——它還可以用來設計迷宮!嘿嘿嘿!
② 數據可視化技術是什麼
數據可視化指的是,通過商業智能BI以圖形化手段為基礎,將復雜、抽象和難以理解的數據用圖表進行表達,清晰有效地傳達信息。數據可視化是商業智能BI數據分析的延伸,分析人員藉助統計分析方法,將數據轉化為信息,然後進行可視化展現。
可視化大屏-派可數據商業智能BI
在商業智能BI中,數據可視化能分別為PC、移動端、大屏製作可視化報表,只需拖拉拽就能完成數據可視化分析,製作可視化報表,還擁有詳細的用戶許可權設置功能保護數據安全。
派可數據-商業智能BI-可視化分析平台-官網
③ 3d列印切片演算法 採用什麼數據類型
一般採用最普通的三角網格模型,建立點線面連接關系,然後用水平面求交,再連成多邊形。
列印機通過讀取文件中的橫截面信息,用液體狀、粉狀或片狀的材料將這些截面逐層地列印出來,再將各層截面以各種方式粘合起來從而製造出一個實體。這種技術的特點在於其幾乎可以造出任何形狀的物品。
列印機打出的截面的厚度(即Z方向)以及平面方向即X-Y方向的解析度是以dpi(像素/英寸)或者微米來計算的。一般的厚度為100微米,即0.1毫米,也有部分列印機如ObjetConnex 系列還有三維Systems' ProJet 系列可以列印出16微米薄的一層。而平面方向則可以列印出跟激光列印機相近的解析度。
列印出來的「墨水滴」的直徑通常為50到100個微米。 用傳統方法製造出一個模型通常需要數小時到數天,根據模型的尺寸以及復雜程度而定。而用三維列印的技術則可以將時間縮短為數個小時,當然其是由列印機的性能以及模型的尺寸和復雜程度而定的。
傳統的製造技術如注塑法可以以較低的成本大量製造聚合物產品,而三維列印技術則可以以更快,更有彈性以及更低成本的辦法生產數量相對較少的產品。一個桌面尺寸的三維列印機就可以滿足設計者或概念開發小組製造模型的需要。
(3)數據切片演算法擴展閱讀
3D列印技術是無法應用於大量生產,所以有些專家鼓吹3D列印是第三次工業革命,這個說法只是個噱頭。富士康為蘋果代工生產iPhone已經多年。郭台銘以3D列印製造的手機為例,說明3D列印的產品只能看不能用,因為這些產品上不能加上電子元器件,無法為電子產品量產。3D列印即使不生產電子產品,但受材料的限制,可以生產的其他產品也很少,「即使生產出來的產品,也無法量產,而且一摔就碎。
「3D列印的確更適合一些小規模製造,尤其是高端的定製化產品,比如汽車零部件製造。雖然主要材料還是塑料,但未來金屬材料肯定會被運用到3D列印中來,」克倫普說,3D列印技術先後進入了牙醫、珠寶、醫療行業,未來可應用的范圍會越來越廣。
2014年11月末,3D列印技術被《時代》周刊為2014年25項年度最佳發明。對消費者和企業而言,這是個福音。僅在過去一年中,中學生們3D列印了用於物理課實驗的火車車廂,科學家們3D列印了人類器官組織,通用電氣公司則使用3D列印技術改進了其噴氣引擎的效率。
美國三維系統公司的3D列印機能列印糖果和樂器等,該公司首席執行官阿維·賴興塔爾說:「這的確是一種巧奪天工的技術。」
④ 什麼是marching cubes演算法具體怎麼講的
Marching Cubes演算法(醫學圖像三維繪制中的面繪制)2007-08-16 00:50建議要看的資料
[1] Lorensen W E, Cline H E .Marching cubes: a high-resoulution 3D suface construction algorithm [J], Computer Graphics,1987, 21(4):163~169
[2]集成化醫學影像演算法平台理論與實踐田捷,趙明昌,何暉光 清華大學出版社2004年10月
[3]Polygonising a scalar field Also known as: "3D Contouring", "Marching Cubes", "Surface Reconstruction"
http://local.wasp.uwa.e.au/~pbourke/geometry/polygonise/Marching Cubes;
[4]www.3dmed.net
Marching Cubes演算法工作原理
Marching Cubes演算法是三維數據場等值面生成的經典演算法,是體素單元內等值面抽取技術的代表。
等值面是空間中所有具有某個相同值的點的集合。它可以表示為, ,c是常數。則稱F(f)為體數據f中的等值面。
在MC演算法中,假定原始數據是離散的三維空間規則數據場。用於醫療診斷的斷層掃描(CT)及核磁共振成像(MRI) 等產生的圖像均屬於這一類型。MC演算法的基本思想是逐個處理數據場中的體素,分類出與等值面相交的體素,採用插值計算出等值面與體素棱邊的交點。根據體素中每一頂點與等值面的相對位置,將等值面與立方體邊的交點按一定方式連接生成等值面,作為等值面在該立方體內的一個逼近表示。在計算出關於體數據場內等值面的有關參數後山常用的圖形軟體包或硬體提供的面繪制功能繪制出等值面。
圖2.1 離散的三維空間規則數據場中的一個體素
2.1.1 MC演算法的主要步驟
1. 確定包含等值面的體素
離散的三維空間規則數據場中的一個體素可以用圖2.1表示。8個數據點分別位於該體素的8個角點上。MC演算法的基本假設是:沿著體素的邊其數據場呈局部連續線性變化,根據這個假設,可認為,如果兩個相鄰采樣點一個為正點,一個為負點,則它們連成的邊上一定存在且僅有一個等值點 (設等值面值為c)。如果得到了體素各條邊上的等值點,就可以以這些點為頂點,用一系列的三角形擬合出該體素中的等值面。因此確定立方體體素中等值面的分布是該演算法的基礎。
首先對體素的8個頂點進行分類,以判斷其頂點是位於等值面之外,還是位於等值面之內。再根據8個頂點的狀態,確定等值面的剖分模式。頂點分類規則為:
1. 如體素頂點的數據值大於或等於等值面的值,則定義該頂點位於等值面之外, 記為正點,即「1「
2. 如體素頂點的數據值小於等值面的值,則定義該頂點位於等值面之內,記為負點, 即「0"
由於每個體素共有8個頂點,且每個頂點有正負兩種狀態,所以等值面可能以 =256種方式與一個體素相交。通過列舉出這256種情況,就能創建一張表格,利用它可以查出任意體素中的等值面的三角面片表示。如果考慮互補對稱性,將等值面的值和8個角點的函數值的大小關系顛倒過來,即將體素的頂點標記置反(0變為1, 1變為0),這樣做不會影響該體素的8個角點和等值面之間的拓撲結構,可將256種方式簡化成128種。其次,再利用旋轉對稱性,可將這128種構型進一步簡化成15種。圖3.2給出了這15種基本構型[131其中黑點標記為「1」的角點。
圖2.2 分布狀態表
圖2.3 體素角點分布不同情況
基於上面的分析,MC演算法中用一個位元組的空間構造了一個體素狀態表,如圖2.2所示,該狀態表中的每一位可表示出該體元中的一個角點的0或1的狀態。根據這一狀態表,就可知道當前體素屬於圖2.3中哪一種情況,以及等值面將與哪一條邊相交。
2.求等值面與體元邊界的交點
在確定體素內三角剖分模式後,就要計算三角片頂點位置。當三維離散數據場的密度較高時,即當體素很小時,可以假定函數值沿體素邊界呈線性變化,這就是MC演算法的基本假設。因此,根據這一基本假設,可以直接用線性插值計算等值面與體素邊的交點。
對於當前被處理體素的某一條邊,如果其兩頂點 , 的標記值不同,那麼等值面一定與此邊相交,且僅有一個交點。交點為 其中P代表等值點坐標, , 代表兩個端點的坐標, , 代表兩個端點的灰度值,v代表域值。求出等值面與體素棱邊的交點以後,就可以將這些交點連接成三角形或多邊形,形成等值面的一部分。
3.等值面的法向量計算
為了利用圖形硬體顯示等值面圖象,必須給出形成等值面的各三角面片的法向分量,選擇適當的局部面光照模型進行光照計算,以生成真實感圖形。
對於等值面上的每一點,其沿面的切線方向的梯度分量應該是零,因此,該點的梯度矢量的方向也就代表了等值面在該點的法向量,當梯度值非零。所幸的是等值面往往是由兩種具有不同密度的物質的分解面,因此其上的每點的梯度矢量均不為零,即
Mc演算法採用中心差分方法求采樣點p〔m ,n, k ) 處的梯度矢量,公式如下:
Gx=〔g(i+1,j,k)-g(i-1,j,k)〕/2dx
Gy=〔g(i,j+1,k)-g(i,j-1,k)〕/2dy
Gz=〔g(i,j,k+1)-g(i,j,k-1)〕/2dz
其中D(i,j ,k)是切片k在像素(i,j)的密度, , , 是立方體邊的長度。對g進行歸一化,得到(gx/|g|,gy/|g|,gz/|g|)作為(i,j,k)上的單位法向量。然後,對體素八個頂點上法向量進行線性插值就可得到位於體素棱邊上的三角片的各個頂點上的法向量。設計算得到的某個三角片的三個頂點上的單位法向量分別為( , 和 ),這個三角片的幾何重心為 ,則該三角片的法向量起始於 ,終止於 。代入Gourand光照模型公式,就可計算出小三角片表面的光強(灰度)。將其投影在某個特定的二維平面上進行顯示,從而顯示出物體富有光感的整個表面形態。其中我們在內存中保留四個切片來計算立方體中所有頂點梯度。
2.1.2 MC演算法流程
1、將三維離散規則數據場分層讀入內存;
2、掃描兩層數據,逐個構造體素,每個體素中的8個角點取自相鄰的兩層;
3、將體素每個角點的函數值與給定的等值面值c做比較,根據比較結果,構造
該體素的狀態表;
4、根據狀態表,得出將與等值面有交點的邊界體素;
5、通過線性插值方法計算出體素棱邊與等值面的交點;
6、利用中心差分方法,求出體素各角點處的法向量,再通過線性插值方法,求出三角面片各頂點處的法向;
7,根據各三角面片上各頂點的坐標及法向量繪制等值面圖像。
========================================================
MC代碼
MarchingCubes(float lowThreshold,float highThreshold,float XSpace,float YSpace,float ZSpace)
{
//記錄生成的頂點數和面數初始時應該為0
m_vNumber=0;
m_fNumber=0;
//當前Cube中生成的頂點和面數
int vertPos,facePos;
//包圍盒的尺寸 用於繪製程序計算整個場景的包圍盒,用於調整觀察位置,以使整個場景盡可能占滿整個窗口。
float min[3],max[3];
min[0]=min[1]=min[2]=max[0]=max[1]=max[2]=0;//初始化
//當前掃描層的切片數據和一個臨時的切片數據
short *pSliceA,*pSliceB,*pSliceC,*pSliceD,*tempSlice;
pSliceA=pSliceB=pSliceC=tempSlice=NULL;
int imageWidth,imageHeight,imageSize,sliceNumber;
imageWidth=imageHeight=512;//我們是512×512的數據
imageSize=imageWidth*imageHeight;
sliceNumber=m_FileCount-1;
if((highThreshold*lowThreshold)==0)
{
return 0;
}
pSliceD =new short [imageSize];
//因為等值面是每相鄰兩層切片為單位進行提取的,所以在處理後兩層切片時難免生成前兩層切片已經生成的頂點,這時候就用下面的數組記錄哪些邊上的頂點已經生成了,如果遇到已經生成的頂點就不再重復計算而是直接使用記錄的索引,否則就生成新的頂點。
long *bottomXEdge=new long[imageSize];
long *bottomYEdge=new long[imageSize];
long *topXEdge=new long[imageSize];
long *topYEdge=new long[imageSize];
long *zEdge=new long[imageSize];
tempSlice=new short [imageSize];
if(bottomXEdge==NULL||bottomYEdge==NULL||
topXEdge==NULL||topYEdge==NULL||
zEdge==NULL||tempSlice==NULL)
{
return 0;//錯誤
}
//初始化數據
memset(bottomXEdge,-1,sizeof(long)*imageSize);
memset(bottomYEdge,-1,sizeof(long)*imageSize);
memset(topXEdge,-1,sizeof(long)*imageSize);
memset(topYEdge,-1,sizeof(long)*imageSize);
memset(zEdge,-1,sizeof(long)*imageSize);
memset(tempSlice,0,sizeof(short)*imageSize);
//計算某一層頂點和三角時所需要的一些變數
//一些循環變數
int i,j,k,w,r;
//cube類型
unsigned char cubeType(0);
//計演算法向量
float dx[8],dy[8],dz[8],squaroot;
//記錄某個Cube生成
float vertPoint[12][6];
int cellVerts[12]; //what use
int triIndex[5][3]; //每個cube最多生成5條邊
//用於記錄已生成頂點索引的臨時變數
int offset;
//當前cube8個頂點的灰度值
short cubegrid[8];
long *edgeGroup;
//得到數據
pSliceD=m_volumeData;
pSliceB=tempSlice;
pSliceA=tempSlice;
int tt,tt1;
//掃描4層切片的順序
/*
-----------------------D |
-----------------------B |
-----------------------C |
-----------------------A |
V
*/
//marching cubes 演算法開始實行 ?第一次循環時,只讀入一個切片?
for(i=0;i<=(sliceNumber);i++)
{
pSliceC=pSliceA;
pSliceA=pSliceB;
pSliceB=pSliceD;
if(i>=sliceNumber-2)
{
pSliceD=tempSlice;
}
else
{
pSliceD+=imageSize;
}
for(j=0;j<imageHeight-1;++j)
for(k=0;k<imageWidth-1;++k)
/* for(j=10;j<imageHeight-5;j++)//調試用
for(k=10;k<imageWidth-5;k++)*/
{
//得到八個頂點的灰度值step0
cubegrid[0]=pSliceA[j*imageWidth+k];
cubegrid[1]=pSliceA[j*imageWidth+k+1];
cubegrid[2]=pSliceA[(j+1)*imageWidth+k+1];
cubegrid[3]=pSliceA[(j+1)*imageWidth+k];
cubegrid[4]=pSliceB[j*imageWidth+k];
cubegrid[5]=pSliceB[j*imageWidth+k+1];
cubegrid[6]=pSliceB[(j+1)*imageWidth+k+1];
cubegrid[7]=pSliceB[(j+1)*imageWidth+k];
//計算cube的類型
cubeType=0;
for(w=0;w<8;w++)
{
if((cubegrid[w]>lowThreshold)&&(cubegrid[w]<highThreshold))//需要畫的點
{
cubeType|=(1<<w);
}
}//end for計算cube的類型
if(cubeType==0||cubeType==255)
{
continue;
}
for(w=0;w<12;w++) //初始化cellVerts表到零
{
cellVerts[w]=-1;
}
//計算6個方向相鄰點的象素差值(用於計演算法向量)
if(k==0)
{
dx[0]=pSliceA[j*imageWidth+1];
dx[3]=pSliceA[(j+1)*imageWidth+1];
dx[4]=pSliceB[j*imageWidth+1];
dx[7]=pSliceB[(j+1)*imageWidth+1];
}
else
{
dx[0]=pSliceA[j*imageWidth+k+1]
-pSliceA[j*imageWidth+k-1];
dx[3]=pSliceA[(j+1)*imageWidth+k+1]
-pSliceA[(j+1)*imageWidth+k-1];
dx[4]=pSliceB[j*imageWidth+k+1]
-pSliceB[j*imageWidth+k-1];
dx[7]=pSliceB[(j+1)*imageWidth+k+1]
-pSliceB[(j+1)*imageWidth+k-1];
}
if(k==imageWidth-2)
{
dx[1]=-pSliceA[j*imageWidth+imageWidth-2];
dx[2]=-pSliceA[(j+1)*imageWidth+imageWidth-2];
dx[5]=-pSliceB[j*imageWidth+imageWidth-2];
dx[6]=-pSliceB[(j+1)*imageWidth+imageWidth-2];
}
else
{
dx[1]=pSliceA[j*imageWidth+k+2]
-pSliceA[j*imageWidth+k];
dx[2]=pSliceA[(j+1)*imageWidth+k+2]
-pSliceA[(j+1)*imageWidth+k];
dx[5]=pSliceB[j*imageWidth+k+2]
-pSliceB[j*imageWidth+k];
dx[6]=pSliceB[(j+1)*imageWidth+k+2]
-pSliceB[(j+1)*imageWidth+k];
}
if(j==0)
{
dy[0]=pSliceA[imageWidth+k];
dy[1]=pSliceA[imageWidth+k+1];
dy[4]=pSliceB[imageWidth+k];
dy[5]=pSliceB[imageWidth+k+1];
}
else
{
dy[0]=pSliceA[(j+1)*imageWidth+k]
-pSliceA[(j-1)*imageWidth+k];
dy[1]=pSliceA[(j+1)*imageWidth+k+1]
-pSliceA[(j-1)*imageWidth+k+1];
dy[4]=pSliceB[(j+1)*imageWidth+k]
-pSliceB[(j-1)*imageWidth+k];
dy[5]=pSliceB[(j+1)*imageWidth+k+1]
-pSliceB[(j-1)*imageWidth+k+1];
}
if(j==imageHeight-2)
{
dy[2]=-pSliceA[(imageHeight-2)*imageWidth+k+1];
dy[3]=-pSliceA[(imageHeight-2)*imageWidth+k];
dy[6]=-pSliceB[(imageHeight-2)*imageWidth+k+1];
dy[7]=-pSliceB[(imageHeight-2)*imageWidth+k];
}
else
{
dy[2]=pSliceA[(j+2)*imageWidth+k+1]-pSliceA[j*imageWidth+k+1];
dy[3]=pSliceA[(j+2)*imageWidth+k]-pSliceA[j*imageWidth+k];
dy[6]=pSliceB[(j+2)*imageWidth+k+1]-pSliceB[j*imageWidth+k+1];
dy[7]=pSliceB[(j+2)*imageWidth+k]-pSliceB[j*imageWidth+k];
}
dz[0]=pSliceB[j*imageWidth+k]
-pSliceC[j*imageWidth+k];
dz[1]=pSliceB[j*imageWidth+k+1]
-pSliceC[j*imageWidth+k+1];
dz[2]=pSliceB[(j+1)*imageWidth+k+1]
-pSliceC[(j+1)*imageWidth+k+1];
dz[3]=pSliceB[(j+1)*imageWidth+k]
-pSliceC[(j+1)*imageWidth+k];
dz[4]=pSliceD[j*imageWidth+k]
-pSliceA[j*imageWidth+k];
dz[5]=pSliceD[j*imageWidth+k+1]
-pSliceA[j*imageWidth+k+1];
dz[6]=pSliceD[(j+1)*imageWidth+k+1]
-pSliceA[(j+1)*imageWidth+k+1];
dz[7]=pSliceD[(j+1)*imageWidth+k]
-pSliceA[(j+1)*imageWidth+k];
//計算三角形頂點的坐標和梯度
vertPos=0;
facePos=0;
for(w=0;w<12;w++)
{
if(g_EdgeTable[cubeType]&(1<<w)) //what …..
{
//根據g_edgeTable[256]對應值判斷cube的那一條邊與等值面有交點
switch(w)
{
case 0:
offset=j*imageWidth+k;
edgeGroup=bottomXEdge;
break;
case 1:
offset=j*imageWidth+k+1;
edgeGroup=bottomYEdge;
break;
case 2:
offset=(j+1)*imageWidth+k;
edgeGroup=bottomXEdge;
break;
case 3:
offset=j*imageWidth+k;
edgeGroup=bottomYEdge;
break;
case 4:
offset=j*imageWidth+k;
edgeGroup=topXEdge;
break;
case 5:
offset=j*imageWidth+k+1;
edgeGroup=topYEdge;
break;
case 6:
offset=(j+1)*imageWidth+k;
edgeGroup=topXEdge;
break;
case 7:
offset=j*imageWidth+k;
edgeGroup=topYEdge;
break;
case 8:
offset=j*imageWidth+k;
edgeGroup=zEdge;
break;
case 9:
offset=j*imageWidth+k+1;
edgeGroup=zEdge;
break;
case 10:
offset=(j+1)*imageWidth+k+1;
edgeGroup=zEdge;
break;
case 11:
offset=(j+1)*imageWidth+k;
edgeGroup=zEdge;
break;
}//對應switch的{。。。end for//根據g_EdgeTable對應值判斷cube的那一條邊與等值面有交點
//該邊上的頂點是否已經在上一層中生成
if(edgeGroup[offset]==-1)
{
int index1,index2;
short s1,s2,s;
float x1,y1,z1,nx1,ny1,nz1;
float x2,y2,z2,nx2,ny2,nz2;
//得到該邊兩端點的索引進而得到兩點的灰度值
index1=g_CoordTable[w][3];
index2=g_CoordTable[w][4];
s1=cubegrid[index1];
s2=cubegrid[index2];
if(s1<highThreshold&&s1>lowThreshold)
{
if(s2>=highThreshold)
{
s=highThreshold;
}
else if(s2<=lowThreshold)
{
s=lowThreshold;
}
}
else if(s2<highThreshold&&s2>lowThreshold)
{
if(s1>=highThreshold)
{
s=highThreshold;
}
else if(s1<=lowThreshold)
{
s=lowThreshold;
}
}
//計算兩端點實際坐標
x1=(k+g_CoordVertex[index1][0])*XSpace;
y1=(j+g_CoordVertex[index1][1])*YSpace;
z1=(i+g_CoordVertex[index1][2])*ZSpace;
x2=(k+g_CoordVertex[index2][0])*XSpace;
y2=(j+g_CoordVertex[index2][1])*YSpace;
z2=(i+g_CoordVertex[index2][2])*ZSpace;
//計算兩端點的法向量
nx1=dx[index1]/XSpace;
ny1=dy[index1]/YSpace;
nz1=dz[index1]/ZSpace;
nx2=dx[index2]/XSpace;
ny2=dy[index2]/YSpace;
nz2=dz[index2]/ZSpace;
float factor=((float)(s-s1))/((float)(s2-s1));
//插值計算交點坐標
vertPoint[vertPos][0]=factor*(x2-x1)+x1;
vertPoint[vertPos][1]=factor*(y2-y1)+y1;
vertPoint[vertPos][2]=factor*(z2-z1)+z1;
//計演算法向量
vertPoint[vertPos][3]=factor*(nx1-nx2)-nx1;
vertPoint[vertPos][4]=factor*(ny1-ny2)-ny1;
vertPoint[vertPos][5]=factor*(nz1-nz2)-nz1;
//法向量歸一化
squaroot=sqrt(vertPoint[vertPos][3]*vertPoint[vertPos][3]+vertPoint[vertPos][4]*vertPoint[vertPos][4]
+vertPoint[vertPos][5]*vertPoint[vertPos][5]);
if(squaroot<=0)squaroot=1.0;
vertPoint[vertPos][3]/=squaroot;
vertPoint[vertPos][4]/=squaroot;
vertPoint[vertPos][5]/=squaroot;
//更新包圍盒數據
if(min[0]>vertPoint[vertPos][0])
{
min[0]=vertPoint[vertPos][0];
}
if(min[1]>vertPoint[vertPos][1])
{
min[1]=vertPoint[vertPos][1];
}
if(min[2]>vertPoint[vertPos][2])
{
min[2]=vertPoint[vertPos][2];
}
if(max[0]<vertPoint[vertPos][0])
{
max[0]=vertPoint[vertPos][0];
}
if(max[1]<vertPoint[vertPos][1])
{
max[1]=vertPoint[vertPos][1];
}
if(max[2]<vertPoint[vertPos][2])
{
max[2]=vertPoint[vertPos][2];
}
//記錄新生成的頂點索引
cellVerts[w]=m_vNumber;
edgeGroup[offset]=cellVerts[w];
m_vNumber++;
vertPos++;
} //end if(edgeGroup[offset]==-1) ////
else
{
//若該點已經在上一層生成,則直接得到其索引
cellVerts[w]=edgeGroup[offset];
}
} // end對應if(g_EdgeTable[cubeType]&(1<<w)) //
} //對應for(w=0;w<12;w++)
//保存當前cubes 頂點和法向量
tt1=m_vNumber-vertPos;
for(tt=0;tt<vertPos;tt++)
{
vPointNomal[tt1+tt][0]=vertPoint[tt][0];
vPointNomal[tt1+tt][1]=vertPoint[tt][1];
vPointNomal[tt1+tt][2]=vertPoint[tt][2];
vPointNomal[tt1+tt][3]=vertPoint[tt][3];
vPointNomal[tt1+tt][4]=vertPoint[tt][4];
vPointNomal[tt1+tt][5]=vertPoint[tt][5];
}
// memcpy(vPointNomal+6*(m_vNumber-vertPos) ,vertPoint,sizeof(float)*6*vertPos);
//記錄新生成的三角面片數據
w=0;
while (g_TriTable[cubeType][w]!=-1)
{
for(r=0;r<3;r++)
{
triIndex[facePos][r]=cellVerts[g_TriTable[cubeType][w++]];
if(triIndex[facePos][r]<0)
{
AfxMessageBox("有問題",MB_OK,0);
}
}
facePos++;
m_fNumber++;
} //end 對應while (g_TriTable[cubeType][w]!=-1)
//保存面數據
tt1=m_fNumber-facePos;
for(tt=0;tt<facePos;tt++)
{
pFace[tt1+tt][0]=triIndex[tt][0];
pFace[tt1+tt][1]=triIndex[tt][1];
pFace[tt1+tt][2]=triIndex[tt][2];
}
// memcpy(pFace+3*(m_fNumber-facePos)*sizeof(long),triIndex,sizeof(int)*3*facePos);
} memcpy(bottomXEdge,topXEdge,sizeof(short)*imageSize);
memcpy(bottomYEdge,topYEdge,sizeof(short)*imageSize);
memset(topXEdge,-1,sizeof(short)*imageSize);
memset(topYEdge,-1,sizeof(short)*imageSize);
memset(zEdge,-1,sizeof(short)*imageSize);
}
delete []tempSlice;
delete []bottomXEdge;
delete []bottomYEdge;
delete []topXEdge;
delete []topYEdge;
delete []zEdge;
return 1;
}
在OnDraw
glBegin(GL_TRIANGLES);
for(i=0;i<pDoc->m_fNumber;i++)
{
glNormal3fv(&(pDoc->vPointNomal[pDoc->pFace[ i][0]][3]));
glVertex3fv(&(pDoc->vPointNomal[pDoc->pFace[ i][0]][0]));
glNormal3fv(&(pDoc->vPointNomal[pDoc->pFace[ i ][1]][3]));
glVertex3fv(&(pDoc->vPointNomal[pDoc->pFace[ i ][1]][0]));
glNormal3fv(&(pDoc->vPointNomal[pDoc->pFace[ i ][2]][3]));
glVertex3fv(&(pDoc->vPointNomal[pDoc->pFace[ i ][2]][0]));
}
glEnd();
以上代碼只用於理解,未測試
⑤ 如何給3D切片軟體cura自編切片演算法
首先我們需要事先做出一個模型,在這里我們製作的是一個小方塊的模型文件,我們可以在3ds max中製作,也可以在Solid Works 丶UG丶MAYA等其他的三維模型製作軟體中製作。如下圖所示:
接下來,我們需要在3ds max 中將此方塊的模型進行導出,導出為STL格式的文件,並命名為適當的文件名稱,值得注意的是命名的時候要使用英文或者拼音命名操作,或者字母加數字兩者組合。為接下來的使用「Cura軟體」生成Gcode格式的可列印格式文件做好准備工作:如下圖所示...
3
在導出的時候,我們會看到一個提示選項框,需要我們選擇生成什麼格式的STL文件,是「二進制」的還是「ASCII」碼的,而且還有一個復選框「僅選定」
這里我們需要選擇「二進制」,不選擇「僅選定」復選框,這樣我們導出STL格式的文件才會更有利於我們列印操作。具體設置,請看下面的圖像:
步驟閱讀
4
導出STL格式文件之後我們會得到一個命名為「fkuai」的文件,然後我們就可以在Cura軟體中進行設置具體參數進行列印了。
⑥ 體數據可視化的各種演算法和技術的特點有哪些
LightingChart:網頁鏈接
體數據集可以通過MRI,CT,PET,USCT或回聲定位等技術捕獲,也可以通過物理模擬(流體動力學或粒子系統)產生。
視化體數據包括四種主要演算法。
1、基於切片方法,這意味著給予每個體數據切片滾動交互單獨可視化機會。此技術的優點在於操作簡單和復雜計算少。而它的缺點是可視化人員需要想像重建整個對象結構
2、其他技術模擬:這種方法很適合於熟悉一定技術的專家可視化分析應用。比如,應用於醫療和地震行業的新技術開發,專家們可以從舊技術解決方案平穩過渡到現代化技術
3、間接體繪制:間接體渲染可以有多種工具用於多邊形網格模型。此方法包含兩個階段,第一階段是根據特定閾值從數據集中提取等值面,有幾種演算法可以進行該任務(最受歡迎的是Marching Cubes )。 有時,可以通過開發基於特定數據集的特定特徵的特殊演算法來改進等值面提取。然後用三維圖像引擎或其它工具可視化多邊形曲面模型,比如: LightningChart的網格模型非常合適於該方法。
4、直接體繪制:直接體繪制不要求預處理。 直接從原始數據集觀察數據,為演算法提供了動態修改傳遞功能和閾值的機會。而且有些方法允許以半透明的方式可視化數據集的內部結構。
直接體繪制是目前可視化數據最強大的方法。可視化具有多邊網格模型的所有優點,並且可以在同一場景中輕松綁定。此外,可以切割模型的一部分來查看被物體表面隱藏的結構。
⑦ 法大大節約了哪些成本
法大大合同碎片化減少了安全存儲的成本。
法大大合同碎片化安全存儲機制通過法大大自主研發的數據安全切片技術(Data Security Slice,簡稱DSS),對合同文件進行加密、分片、混淆、分雲存儲等操作,將文件以亂序的方式在不同的雲上按照不同比例(用戶自定義)存儲,從而確保合同文件在每個雲存儲節點中都沒有完整的數據全量,完整的文件數據全程僅由客戶掌握,而無法被任何第三方(包括法大大)獲取,在保障數據安全性、私密性的同時,又充分利用了公有雲存儲的彈性與成本優勢。
法大大通過加密、分片、混淆、分雲存儲等步驟,DSS可以確保合同文件在每個雲存儲節點中都沒有完整的數據全量,通過獨有文件拼接演算法,基於碎片拼接恢復的文件與原始文件具備哈希一致性。在文件注入存儲後,對每個合同文件按照特定大小分割成若干個數據塊,之後對數據塊進行隨機亂序混淆,並按照不同的策略加密存放到不同的公有雲或本地的數據中心。
⑧ 誰了解lightingchart體數據可視化的各種演算法和特點
Arction lightingchart可視化體數據包括四種主要演算法。基於切片方法、其他技術模擬、體渲染(間接體繪制、直接體繪制)、光線投射演算法;
⑨ 電子合同平台是如何保障文件安全不被他人查看的
這就要提到「合同碎片化安全存儲機制」,是通過我們自主研發的數據安全切片技術(簡稱DDS)。
DSS會對合同文件進行加密、分片、混淆、分雲存儲等操作,將文件以亂序的方式在不同的雲上按照不同比例(用戶自定義)存儲,從而確保合同文件在每個雲存儲節點中都沒有完整的數據全量,完整的文件數據全程僅由客戶掌握,而無法被任何第三方(包括平台本身)獲取,在保障數據安全性、私密性的同時,又充分利用了公有雲存儲的彈性與成本優勢。
⑩ 數據挖掘演算法與生活中的應用案例
數據挖掘演算法與生活中的應用案例
如何分辨出垃圾郵件」、「如何判斷一筆交易是否屬於欺詐」、「如何判斷紅酒的品質和檔次」、「掃描王是如何做到文字識別的」、「如何判斷佚名的著作是否出自某位名家之手」、「如何判斷一個細胞是否屬於腫瘤細胞」等等,這些問題似乎都很專業,都不太好回答。但是,如果了解一點點數據挖掘的知識,你,或許會有柳暗花明的感覺。
本文,主要想簡單介紹下數據挖掘中的演算法,以及它包含的類型。然後,通過現實中觸手可及的、活生生的案例,去詮釋它的真實存在。 一般來說,數據挖掘的演算法包含四種類型,即分類、預測、聚類、關聯。前兩種屬於有監督學習,後兩種屬於無監督學習,屬於描述性的模式識別和發現。
有監督學習有監督的學習,即存在目標變數,需要探索特徵變數和目標變數之間的關系,在目標變數的監督下學習和優化演算法。例如,信用評分模型就是典型的有監督學習,目標變數為「是否違約」。演算法的目的在於研究特徵變數(人口統計、資產屬性等)和目標變數之間的關系。
分類演算法分類演算法和預測演算法的最大區別在於,前者的目標變數是分類離散型(例如,是否逾期、是否腫瘤細胞、是否垃圾郵件等),後者的目標變數是連續型。一般而言,具體的分類演算法包括,邏輯回歸、決策樹、KNN、貝葉斯判別、SVM、隨機森林、神經網路等。
預測演算法預測類演算法,其目標變數一般是連續型變數。常見的演算法,包括線性回歸、回歸樹、神經網路、SVM等。
無監督學習無監督學習,即不存在目標變數,基於數據本身,去識別變數之間內在的模式和特徵。例如關聯分析,通過數據發現項目A和項目B之間的關聯性。例如聚類分析,通過距離,將所有樣本劃分為幾個穩定可區分的群體。這些都是在沒有目標變數監督下的模式識別和分析。
聚類分析聚類的目的就是實現對樣本的細分,使得同組內的樣本特徵較為相似,不同組的樣本特徵差異較大。常見的聚類演算法包括kmeans、系譜聚類、密度聚類等。
關聯分析關聯分析的目的在於,找出項目(item)之間內在的聯系。常常是指購物籃分析,即消費者常常會同時購買哪些產品(例如游泳褲、防曬霜),從而有助於商家的捆綁銷售。
基於數據挖掘的案例和應用上文所提到的四種演算法類型(分類、預測、聚類、關聯),是比較傳統和常見的。還有其他一些比較有趣的演算法分類和應用場景,例如協同過濾、異常值分析、社會網路、文本分析等。下面,想針對不同的演算法類型,具體的介紹下數據挖掘在日常生活中真實的存在。下面是能想到的、幾個比較有趣的、和生活緊密關聯的例子。
基於分類模型的案例這裡面主要想介紹兩個案例,一個是垃圾郵件的分類和判斷,另外一個是在生物醫葯領域的應用,即腫瘤細胞的判斷和分辨。
垃圾郵件的判別郵箱系統如何分辨一封Email是否屬於垃圾郵件?這應該屬於文本挖掘的范疇,通常會採用樸素貝葉斯的方法進行判別。它的主要原理是,根據郵件正文中的單詞,是否經常出現在垃圾郵件中,進行判斷。例如,如果一份郵件的正文中包含「報銷」、「發票」、「促銷」等詞彙時,該郵件被判定為垃圾郵件的概率將會比較大。
一般來說,判斷郵件是否屬於垃圾郵件,應該包含以下幾個步驟。
第一,把郵件正文拆解成單片語合,假設某篇郵件包含100個單詞。
第二,根據貝葉斯條件概率,計算一封已經出現了這100個單詞的郵件,屬於垃圾郵件的概率和正常郵件的概率。如果結果表明,屬於垃圾郵件的概率大於正常郵件的概率。那麼該郵件就會被劃為垃圾郵件。
醫學上的腫瘤判斷如何判斷細胞是否屬於腫瘤細胞呢?腫瘤細胞和普通細胞,有差別。但是,需要非常有經驗的醫生,通過病理切片才能判斷。如果通過機器學習的方式,使得系統自動識別出腫瘤細胞。此時的效率,將會得到飛速的提升。並且,通過主觀(醫生)+客觀(模型)的方式識別腫瘤細胞,結果交叉驗證,結論可能更加靠譜。
如何操作?通過分類模型識別。簡言之,包含兩個步驟。首先,通過一系列指標刻畫細胞特徵,例如細胞的半徑、質地、周長、面積、光滑度、對稱性、凹凸性等等,構成細胞特徵的數據。其次,在細胞特徵寬表的基礎上,通過搭建分類模型進行腫瘤細胞的判斷。
基於預測模型的案例這裡面主要想介紹兩個案例。即通過化學特性判斷和預測紅酒的品質。另外一個是,通過搜索引擎來預測和判斷股價的波動和趨勢。
紅酒品質的判斷如何評鑒紅酒?有經驗的人會說,紅酒最重要的是口感。而口感的好壞,受很多因素的影響,例如年份、產地、氣候、釀造的工藝等等。但是,統計學家並沒有時間去品嘗各種各樣的紅酒,他們覺得通過一些化學屬性特徵就能夠很好地判斷紅酒的品質了。並且,現在很多釀酒企業其實也都這么幹了,通過監測紅酒中化學成分的含量,從而控制紅酒的品質和口感。
那麼,如何判斷鑒紅酒的品質呢?
第一步,收集很多紅酒樣本,整理檢測他們的化學特性,例如酸性、含糖量、氯化物含量、硫含量、酒精度、PH值、密度等等。
第二步,通過分類回歸樹模型進行預測和判斷紅酒的品質和等級。
搜索引擎的搜索量和股價波動一隻南美洲熱帶雨林中的蝴蝶,偶爾扇動了幾下翅膀,可以在兩周以後,引起美國德克薩斯州的一場龍卷風。你在互聯網上的搜索是否會影響公司股價的波動?
很早之前,就已經有文獻證明,互聯網關鍵詞的搜索量(例如流感)會比疾控中心提前1到2周預測出某地區流感的爆發。
同樣,現在也有些學者發現了這樣一種現象,即公司在互聯網中搜索量的變化,會顯著影響公司股價的波動和趨勢,即所謂的投資者注意力理論。該理論認為,公司在搜索引擎中的搜索量,代表了該股票被投資者關注的程度。因此,當一隻股票的搜索頻數增加時,說明投資者對該股票的關注度提升,從而使得該股票更容易被個人投資者購買,進一步地導致股票價格上升,帶來正向的股票收益。這是已經得到無數論文驗證了的。
基於關聯分析的案例:沃爾瑪的啤酒尿布啤酒尿布是一個非常非常古老陳舊的故事。故事是這樣的,沃爾瑪發現一個非常有趣的現象,即把尿布與啤酒這兩種風馬牛不相及的商品擺在一起,能夠大幅增加兩者的銷量。原因在於,美國的婦女通常在家照顧孩子,所以,她們常常會囑咐丈夫在下班回家的路上為孩子買尿布,而丈夫在買尿布的同時又會順手購買自己愛喝的啤酒。沃爾瑪從數據中發現了這種關聯性,因此,將這兩種商品並置,從而大大提高了關聯銷售。
啤酒尿布主要講的是產品之間的關聯性,如果大量的數據表明,消費者購買A商品的同時,也會順帶著購買B產品。那麼A和B之間存在關聯性。在超市中,常常會看到兩個商品的捆綁銷售,很有可能就是關聯分析的結果。
基於聚類分析的案例:零售客戶細分對客戶的細分,還是比較常見的。細分的功能,在於能夠有效的劃分出客戶群體,使得群體內部成員具有相似性,但是群體之間存在差異性。其目的在於識別不同的客戶群體,然後針對不同的客戶群體,精準地進行產品設計和推送,從而節約營銷成本,提高營銷效率。
例如,針對商業銀行中的零售客戶進行細分,基於零售客戶的特徵變數(人口特徵、資產特徵、負債特徵、結算特徵),計算客戶之間的距離。然後,按照距離的遠近,把相似的客戶聚集為一類,從而有效的細分客戶。將全體客戶劃分為諸如,理財偏好者、基金偏好者、活期偏好者、國債偏好者、風險均衡者、渠道偏好者等。
基於異常值分析的案例:支付中的交易欺詐偵測採用支付寶支付時,或者刷信用卡支付時,系統會實時判斷這筆刷卡行為是否屬於盜刷。通過判斷刷卡的時間、地點、商戶名稱、金額、頻率等要素進行判斷。這裡面基本的原理就是尋找異常值。如果您的刷卡被判定為異常,這筆交易可能會被終止。
異常值的判斷,應該是基於一個欺詐規則庫的。可能包含兩類規則,即事件類規則和模型類規則。第一,事件類規則,例如刷卡的時間是否異常(凌晨刷卡)、刷卡的地點是否異常(非經常所在地刷卡)、刷卡的商戶是否異常(被列入黑名單的套現商戶)、刷卡金額是否異常(是否偏離正常均值的三倍標准差)、刷卡頻次是否異常(高頻密集刷卡)。第二,模型類規則,則是通過演算法判定交易是否屬於欺詐。一般通過支付數據、賣家數據、結算數據,構建模型進行分類問題的判斷。
基於協同過濾的案例:電商猜你喜歡和推薦引擎電商中的猜你喜歡,應該是大家最為熟悉的。在京東商城或者亞馬遜購物,總會有「猜你喜歡」、「根據您的瀏覽歷史記錄精心為您推薦」、「購買此商品的顧客同時也購買了商品」、「瀏覽了該商品的顧客最終購買了商品」,這些都是推薦引擎運算的結果。
這裡面,確實很喜歡亞馬遜的推薦,通過「購買該商品的人同時購買了**商品」,常常會發現一些質量比較高、較為受認可的書。一般來說,電商的「猜你喜歡」(即推薦引擎)都是在協同過濾演算法(Collaborative Filter)的基礎上,搭建一套符合自身特點的規則庫。即該演算法會同時考慮其他顧客的選擇和行為,在此基礎上搭建產品相似性矩陣和用戶相似性矩陣。基於此,找出最相似的顧客或最關聯的產品,從而完成產品的推薦。
基於社會網路分析的案例:電信中的種子客戶種子客戶和社會網路,最早出現在電信領域的研究。即,通過人們的通話記錄,就可以勾勒出人們的關系網路。電信領域的網路,一般會分析客戶的影響力和客戶流失、產品擴散的關系。
基於通話記錄,可以構建客戶影響力指標體系。採用的指標,大概包括如下,一度人脈、二度人脈、三度人脈、平均通話頻次、平均通話量等。基於社會影響力,分析的結果表明,高影響力客戶的流失會導致關聯客戶的流失。其次,在產品的擴散上,選擇高影響力客戶作為傳播的起點,很容易推動新套餐的擴散和滲透。
此外,社會網路在銀行(擔保網路)、保險(團伙欺詐)、互聯網(社交互動)中也都有很多的應用和案例。
基於文本分析的案例這裡面主要想介紹兩個案例。一個是類似「掃描王」的APP,直接把紙質文檔掃描成電子文檔。相信很多人都用過,這里准備簡單介紹下原理。另外一個是,江湖上總是傳言紅樓夢的前八十回和後四十回,好像並非都是出自曹雪芹之手,這裡面准備從統計的角度聊聊。
字元識別:掃描王APP手機拍照時會自動識別人臉,還有一些APP,例如掃描王,可以掃描書本,然後把掃描的內容自動轉化為word。這些屬於圖像識別和字元識別(Optical Character Recognition)。圖像識別比較復雜,字元識別理解起來比較容易些。
查找了一些資料,字元識別的大概原理如下,以字元S為例。
第一,把字元圖像縮小到標准像素尺寸,例如12*16。注意,圖像是由像素構成,字元圖像主要包括黑、白兩種像素。
第二,提取字元的特徵向量。如何提取字元的特徵,採用二維直方圖投影。就是把字元(12*16的像素圖)往水平方向和垂直方向上投影。水平方向有12個維度,垂直方向有16個維度。這樣分別計算水平方向上各個像素行中黑色像素的累計數量、垂直方向各個像素列上的黑色像素的累計數量。從而得到水平方向12個維度的特徵向量取值,垂直方向上16個維度的特徵向量取值。這樣就構成了包含28個維度的字元特徵向量。
第三,基於前面的字元特徵向量,通過神經網路學習,從而識別字元和有效分類。
文學著作與統計:紅樓夢歸屬這是非常著名的一個爭論,懸而未決。對於紅樓夢的作者,通常認為前80回合是曹雪芹所著,後四十回合為高鶚所寫。其實主要問題,就是想確定,前80回合和後40回合是否在遣詞造句方面存在顯著差異。
這事讓一群統計學家比較興奮了。有些學者通過統計名詞、動詞、形容詞、副詞、虛詞出現的頻次,以及不同詞性之間的相關系做判斷。有些學者通過虛詞(例如之、其、或、亦、了、的、不、把、別、好),判斷前後文風的差異。有些學者通過場景(花卉、樹木、飲食、醫葯與詩詞)頻次的差異,來做統計判斷。總而言之,主要通過一些指標量化,然後比較指標之間是否存在顯著差異,藉此進行寫作風格的判斷。
以上是小編為大家分享的關於數據挖掘演算法與生活中的應用案例的相關內容,更多信息可以關注環球青藤分享更多干貨