1. 同一個人不同淘寶賬號會存在大數據殺熟嗎
會,
一般後台會根據用戶的行為進行大數據判斷,如果相似度達到80%以上則認定為同一個人。
2. 大數據十大經典演算法之k-means
大數據十大經典演算法之k-means
k均值演算法基本思想:
K均值演算法是基於質心的技術。它以K為輸入參數,把n個對象集合分為k個簇,使得簇內的相似度高,簇間的相似度低。
處理流程:
1、為每個聚類確定一個初始聚類中心,這樣就有k個初始聚類中心;
2、將樣本按照最小距離原則分配到最鄰近聚類
3、使用每個聚類中的樣本均值作為新的聚類中心
4、重復步驟2直到聚類中心不再變化
5、結束,得到K個聚類
劃分聚類方法對數據集進行聚類時的要點:
1、選定某種距離作為數據樣本間的相似性度量,通常選擇歐氏距離。
2、選擇平價聚類性能的准則函數
用誤差平方和准則函數來評價聚類性能。
3、相似度的計算分局一個簇中對象的平均值來進行
K均值演算法的優點:
如果變數很大,K均值比層次聚類的計算速度較快(如果K很小);
與層次聚類相比,K均值可以得到更緊密的簇,尤其是對於球狀簇;
對於大數據集,是可伸縮和高效率的;
演算法嘗試找出使平方誤差函數值最小的k個劃分。當結果簇是密集的,而簇與簇之間區別明顯的時候,效果較好。
K均值演算法缺點:
最後結果受初始值的影響。解決辦法是多次嘗試取不同的初始值。
可能發生距離簇中心m最近的樣本集為空的情況,因此m得不到更新。這是一個必須處理的問題,但我們忽略該問題。
不適合發現非凸面形狀的簇,並對雜訊和離群點數據較敏感,因為少量的這類數據能夠對均值產生較大的影響。
K均值演算法的改進:
樣本預處理。計算樣本對象量量之間的距離,篩掉與其他所有樣本那的距離和最大的m個對象。
初始聚類中心的選擇。選用簇中位置最靠近中心的對象,這樣可以避免孤立點的影響。
K均值演算法的變種:
K眾數(k-modes)演算法,針對分類屬性的度量和更新質心的問題而改進。
EM(期望最大化)演算法
k-prototype演算法
這種演算法不適合處理離散型屬性,但是對於連續型具有較好的聚類效果。
k均值演算法用途:
圖像分割;
衡量足球隊的水平;
下面給出代碼:
#include <iostream>
#include <vector>
//auther archersc
//JLU
namespace CS_LIB
{
using namespace std;
class Kmean
{
public:
//輸入格式
//數據數量N 維度D
//以下N行,每行D個數據
istream& loadData(istream& in);
//輸出格式
//聚類的數量CN
//中心維度CD
//CN行,每行CD個數據
//數據數量DN
//數據維度DD
//以下DN組,每組的第一行兩個數值DB, DDis
//第二行DD個數值
//DB表示改數據屬於一類,DDis表示距離改類的中心的距離
ostream& saveData(ostream& out);
//設置中心的數量
void setCenterCount(const size_t count);
size_t getCenterCount() const;
//times最大迭代次數, maxE ,E(t)表示第t次迭代後的平方誤差和,當|E(t+1) - E(t)| < maxE時終止
void clustering(size_t times, double maxE);
private:
double calDistance(vector<double>& v1, vector<double>& v2);
private:
vector< vector<double> > m_Data;
vector< vector<double> > m_Center;
vector<double> m_Distance;
vector<size_t> m_DataBelong;
vector<size_t> m_DataBelongCount;
};
}
#include "kmean.h"
#include <ctime>
#include <cmath>
#include <cstdlib>
//auther archersc
//JLU
namespace CS_LIB
{
template<class T>
void swap(T& a, T& b)
{
T c = a;
a = b;
b = c;
}
istream& Kmean::loadData(istream& in)
{
if (!in){
cout << "input error" << endl;
return in;
}
size_t dCount, dDim;
in >> dCount >> dDim;
m_Data.resize(dCount);
m_DataBelong.resize(dCount);
m_Distance.resize(dCount);
for (size_t i = 0; i < dCount; ++i){
m_Data[i].resize(dDim);
for (size_t j = 0; j < dDim; ++j){
in >> m_Data[i][j];
}
}
return in;
}
ostream& Kmean::saveData(ostream& out)
{
if (!out){
cout << "output error" << endl;
return out;
}
out << m_Center.size();
if (m_Center.size() > 0)
out << << m_Center[0].size();
else
out << << 0;
out << endl << endl;
for (size_t i = 0; i < m_Center.size(); ++i){
for (size_t j = 0; j < m_Center[i].size(); ++j){
out << m_Center[i][j] << ;
}
out << endl;
}
out << endl;
out << m_Data.size();
if (m_Data.size() > 0)
out << << m_Data[0].size();
else
out << << 0;
out << endl << endl;
for (size_t i = 0; i < m_Data.size(); ++i){
out << m_DataBelong[i] << << m_Distance[i] << endl;
for (size_t j = 0; j < m_Data[i].size(); ++j){
out << m_Data[i][j] << ;
}
out << endl << endl;
}
return out;
}
void Kmean::setCenterCount(const size_t count)
{
m_Center.resize(count);
m_DataBelongCount.resize(count);
}
size_t Kmean::getCenterCount() const
{
return m_Center.size();
}
void Kmean::clustering(size_t times, double maxE)
{
srand((unsigned int)time(NULL));
//隨機從m_Data中選取m_Center.size()個不同的樣本點作為初始中心。
size_t *pos = new size_t[m_Data.size()];
size_t i, j, t;
for (i = 0; i < m_Data.size(); ++i){
pos[i] = i;
}
for (i = 0; i < (m_Data.size() << 1); ++i){
size_t s1 = rand() % m_Data.size();
size_t s2 = rand() % m_Data.size();
swap(pos[s1], pos[s2]);
}
for (i = 0; i < m_Center.size(); ++i){
m_Center[i].resize(m_Data[pos[i]].size());
for (j = 0; j < m_Data[pos[i]].size(); ++j){
m_Center[i][j] = m_Data[pos[i]][j];
}
}
delete []pos;
double currE, lastE;
for (t = 0; t < times; ++t){
for (i = 0; i < m_Distance.size(); ++i)
m_Distance[i] = LONG_MAX;
for (i = 0; i < m_DataBelongCount.size(); ++i)
m_DataBelongCount[i] = 0;
currE = 0.0;
for (i = 0; i < m_Data.size(); ++i){
for (j = 0; j < m_Center.size(); ++j){
double dis = calDistance(m_Data[i], m_Center[j]);
if (dis < m_Distance[i]){
m_Distance[i] = dis;
m_DataBelong[i] = j;
}
}
currE += m_Distance[i];
m_DataBelongCount[m_DataBelong[i]]++;
}
cout << currE << endl;
if (t == 0 || fabs(currE - lastE) > maxE)
lastE = currE;
else
break;
for (i = 0; i < m_Center.size(); ++i){
for (j = 0; j < m_Center[i].size(); ++j)
m_Center[i][j] = 0.0;
}
for (i = 0; i < m_DataBelong.size(); ++i){
for (j = 0; j < m_Data[i].size(); ++j){
m_Center[m_DataBelong[i]][j] += m_Data[i][j] / m_DataBelongCount[m_DataBelong[i]];
}
}
}
}
double Kmean::calDistance(vector<double>& v1, vector<double>& v2)
{
double result = 0.0;
for (size_t i = 0; i < v1.size(); ++i){
result += (v1[i] - v2[i]) * (v1[i] - v2[i]);
}
return pow(result, 1.0 / v1.size());
//return sqrt(result);
}
}
#include <iostream>
#include <fstream>
#include "kmean.h"
using namespace std;
using namespace CS_LIB;
int main()
{
ifstream in("in.txt");
ofstream out("out.txt");
Kmean kmean;
kmean.loadData(in);
kmean.setCenterCount(4);
kmean.clustering(1000, 0.000001);
kmean.saveData(out);
return 0;
}
3. 大數據演算法:分類演算法
KNN演算法,即K近鄰(K Nearest Neighbour)演算法,是一種基本的分類演算法。其主要原理是:對於一個需要分類的數據,將其和一組已經分類標注好的樣本集合進行比較,得到距離最近的K個樣本,K個樣本最多歸屬的類別,就是這個需要分類數據的類別。下面我給你畫了一個KNN演算法的原理圖。
圖中,紅藍綠三種顏色的點為樣本數據,分屬三種類別 、 、 。對於待分類點 ,計算和它距離最近的5個點(即K為5),這5個點最多歸屬的類別為 (4個點歸屬 ,1個點歸屬 ),那麼 的類別被分類為 。
KNN的演算法流程也非常簡單,請看下面的流程圖。
KNN演算法是一種非常簡單實用的分類演算法,可用於各種分類的場景,比如新聞分類、商品分類等,甚至可用於簡單的文字識別。對於新聞分類,可以提前對若干新聞進行人工標注,標好新聞類別,計算好特徵向量。對於一篇未分類的新聞,計算其特徵向量後,跟所有已標注新聞進行距離計算,然後進一步利用KNN演算法進行自動分類。
讀到這你肯定會問,如何計算數據的距離呢?如何獲得新聞的特徵向量呢?
KNN演算法的關鍵是要比較需要分類的數據與樣本數據之間的距離,這在機器學習中通常的做法是:提取數據的特徵值,根據特徵值組成一個n維實數向量空間(這個空間也被稱作特徵空間),然後計算向量之間的空間距離。空間之間的距離計算方法有很多種,常用的有歐氏距離、餘弦距離等。
對於數據 和 ,若其特徵空間為n維實數向量空間 ,即 , ,則其歐氏距離計算公式為
這個歐式距離公式其實我們在初中的時候就學過,平面幾何和立體幾何里兩個點之間的距離,也是用這個公式計算出來的,只是平面幾何(二維幾何)里的n=2,立體幾何(三維幾何)里的n=3,而機器學習需要面對的每個數據都可能有n維的維度,即每個數據有n個特徵值。但是不管特徵值n是多少,兩個數據之間的空間距離的計算公式還是這個歐氏計算公式。大多數機器學習演算法都需要計算數據之間的距離,因此掌握數據的距離計算公式是掌握機器學習演算法的基礎。
歐氏距離是最常用的數據計算公式,但是在文本數據以及用戶評價數據的機器學習中,更常用的距離計算方法是餘弦相似度。
餘弦相似度的值越接近1表示其越相似,越接近0表示其差異越大,使用餘弦相似度可以消除數據的某些冗餘信息,某些情況下更貼近數據的本質。我舉個簡單的例子,比如兩篇文章的特徵值都是:「大數據」「機器學習」和「極客時間」,A文章的特徵向量為(3, 3, 3),即這三個詞出現次數都是3;B文章的特徵向量為(6, 6, 6),即這三個詞出現次數都是6。如果光看特徵向量,這兩個向量差別很大,如果用歐氏距離計算確實也很大,但是這兩篇文章其實非常相似,只是篇幅不同而已,它們的餘弦相似度為1,表示非常相似。
餘弦相似度其實是計算向量的夾角,而歐氏距離公式是計算空間距離。餘弦相似度更關注數據的相似性,比如兩個用戶給兩件商品的打分分別是(3, 3)和(4, 4),那麼兩個用戶對兩件商品的喜好是相似的,這種情況下,餘弦相似度比歐氏距離更合理。
我們知道了機器學習的演算法需要計算距離,而計算距離需要還知道數據的特徵向量,因此提取數據的特徵向量是機器學習工程師們的重要工作,有時候甚至是最重要的工作。不同的數據以及不同的應用場景需要提取不同的特徵值,我們以比較常見的文本數據為例,看看如何提取文本特徵向量。
文本數據的特徵值就是提取文本關鍵詞,TF-IDF演算法是比較常用且直觀的一種文本關鍵詞提取演算法。這種演算法是由TF和IDF兩部分構成。
TF是詞頻(Term Frequency),表示某個單詞在文檔中出現的頻率,一個單詞在一個文檔中出現的越頻繁,TF值越高。
詞頻:
IDF是逆文檔頻率(Inverse Document Frequency),表示這個單詞在所有文檔中的稀缺程度,越少文檔出現這個詞,IDF值越高。
逆文檔頻率:
TF與IDF的乘積就是TF-IDF。
所以如果一個詞在某一個文檔中頻繁出現,但在所有文檔中卻很少出現,那麼這個詞很可能就是這個文檔的關鍵詞。比如一篇關於原子能的技術文章,「核裂變」「放射性」「半衰期」等詞彙會在這篇文檔中頻繁出現,即TF很高;但是在所有文檔中出現的頻率卻比較低,即IDF也比較高。因此這幾個詞的TF-IDF值就會很高,就可能是這篇文檔的關鍵詞。如果這是一篇關於中國原子能的文章,也許「中國」這個詞也會頻繁出現,即TF也很高,但是「中國」也在很多文檔中出現,那麼IDF就會比較低,最後「中國」這個詞的TF-IDF就很低,不會成為這個文檔的關鍵詞。
提取出關鍵詞以後,就可以利用關鍵詞的詞頻構造特徵向量,比如上面例子關於原子能的文章,「核裂變」「放射性」「半衰期」這三個詞是特徵值,分別出現次數為12、9、4。那麼這篇文章的特徵向量就是(12, 9, 4),再利用前面提到的空間距離計算公式計算與其他文檔的距離,結合KNN演算法就可以實現文檔的自動分類。
貝葉斯公式是一種基於條件概率的分類演算法,如果我們已經知道A和B的發生概率,並且知道了B發生情況下A發生的概率,可以用貝葉斯公式計算A發生的情況下B發生的概率。事實上,我們可以根據A的情況,即輸入數據,判斷B的概率,即B的可能性,進而進行分類。
舉個例子:假設一所學校里男生佔60%,女生佔40%。男生總是穿長褲,女生則一半穿長褲一半穿裙子。假設你走在校園中,迎面走來一個穿長褲的學生,你能夠推斷出這個穿長褲學生是男生的概率是多少嗎?
答案是75%,具體演算法是:
這個演算法就利用了貝葉斯公式,貝葉斯公式的寫法是:
意思是A發生的條件下B發生的概率,等於B發生的條件下A發生的概率,乘以B發生的概率,除以A發生的概率。還是上面這個例子,如果我問你迎面走來穿裙子的學生是女生的概率是多少。同樣帶入貝葉斯公式,可以計算出是女生的概率為100%。其實這個結果我們根據常識也能推斷出來,但是很多時候,常識受各種因素的干擾,會出現偏差。比如有人看到一篇博士生給初中學歷老闆打工的新聞,就感嘆讀書無用。事實上,只是少見多怪,樣本量太少而已。而大量數據的統計規律則能准確反映事物的分類概率。
貝葉斯分類的一個典型的應用場合是垃圾郵件分類,通過對樣本郵件的統計,我們知道每個詞在郵件中出現的概率 ,我們也知道正常郵件概率 和垃圾郵件的概率 ,還可以統計出垃圾郵件中各個詞的出現概率 ,那麼現在一封新郵件到來,我們就可以根據郵件中出現的詞,計算 ,即得到這些詞出現情況下,郵件為垃圾郵件的概率,進而判斷郵件是否為垃圾郵件。
現實中,貝葉斯公式等號右邊的概率,我們可以通過對大數據的統計獲得,當有新的數據到來的時候,我們就可以帶入上面的貝葉斯公式計算其概率。而如果我們設定概率超過某個值就認為其會發生,那麼我們就對這個數據進行了分類和預測,具體過程如下圖所示。
訓練樣本就是我們的原始數據,有時候原始數據並不包含我們想要計算的維度數據,比如我們想用貝葉斯公式自動分類垃圾郵件,那麼首先要對原始郵件進行標注,需要標注哪些郵件是正常郵件、哪些郵件是垃圾郵件。這一類需要對數據進行標注才能進行的機器學習訓練也叫作有監督的機器學習。