Android防重复点击 Java Out Of Memory rest vector jboss vue添加class web前端开发实战项目 jquery循环遍历 sublime分屏快捷键 oracle删除字段 mysql合并结果集 matlab自然对数 SketchUp python中文文档 python文件操作 python基本语法 python学习网站 python处理json文件 java的继承 java删除数组中的元素 jdbc连接mysql java时间格式化 java实例方法 java删除文件 python的用途 js格式化时间 战地联盟辅助 方正兰亭字体下载 快打旋风3出招表 编程语言实现模式 摩斯密码翻译器 js刷新页面 udp测试工具 经典雅黑 ajaxpro 非凡资源搜索器 微信问卷调查怎么做 mysql索引面试题 数组对象去重 php苹果动态锁屏
当前位置: 首页 > 学习教程  > python

用topsis来建模

2021/2/6 22:23:05 文章标签: 测试文章如有侵权请发送至邮箱809451989@qq.com投诉后文章立即删除

topsis过程简略概括 将所有的数据正向化标准化数据归一化数据计算得到权值 第一步 正向化 对于所有的数据一般有四种类型,极大型、极小型、中间型和区间型 对于极小型的正向化处理:max−xmax -xmax−x 对于中间型: Mmax(xi−xbest)x1−∣x…

topsis过程简略概括
  • 将所有的数据正向化
  • 标准化数据
  • 归一化数据
  • 计算得到权值
第一步 正向化

对于所有的数据一般有四种类型,极大型、极小型、中间型和区间型
对于极小型的正向化处理: m a x − x max -x maxx
对于中间型:
M = m a x ( x i − x b e s t ) x = 1 − ∣ x − x b e s t ∣ M M =max(x_i-x_{best})\\ x = 1- \frac{|x-x_{best}|}{M} M=max(xixbest)x=1Mxxbest
对于区间型([a,b])为例
M = m a x ( a − m i n ( x i ) , m a x ( x i ) − b ) x ˉ = { 1 − a − x i M    ( x i < a ) 1 ( a ⩽ x ⩽ b ) 1 − x i − b M ( x i > b ) M = max(a-min(x_i), max(x_i)-b )\\ \bar{x}=\begin{cases} 1-\frac{a-x_i}{M}\quad\,\, \left( x_i<a \right)\\ 1 \quad \quad \quad \quad \left( a\leqslant x\leqslant b \right)\\ 1-\frac{x_i-b}{M}\quad \left( x_i>b \right)\\ \end{cases} M=max(amin(xi),max(xi)b)xˉ=1Maxi(xi<a)1(axb)1Mxib(xi>b)
在这里,我们很容易就会理解出 M M M就是 x x x是与极值的绝对差值
代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
import pandas as pd
import xlrd

def readxlsx(file):
    xlsx = xlrd.open_workbook(filename=file)  # 函数
    sheet = xlsx.sheet_by_index(0)  # 通过sheet索引获取所需sheet对象 ,sheet(x)为索引值,索引从0开始计算;
    rows = sheet.nrows  # 获取所有的行
    print(rows)
    print('\n')
    col = sheet.ncols  # 获取所有的列
    print(col)
    print('\n')
    readcontent = []
    for j in range(1, col):  ##遍历第二列到最后一列,注意是第二列!!!
        temp = []
        for i in range(1, rows):
            cell = sheet.cell_value(i, j)  ##读取表格数据
            temp.append(cell)
        readcontent.append(temp)
        temp = []
    return np.array(readcontent)##转为array

def opsis(x,typp):
    if typp==2:
        print("极小型\n")
        x =max(x)-x
    if typp==3:
        print("中间型,需要输入best:\n")
        # best=input('输入best: ')
        best=7
        best = int(best)##这块一定要转为整型
        m=max(np.abs(x-best))
        x=1-np.abs(x-best)/m
    if typp==4:
        l=x.shape[0]
        print("区间型,需要输入区间[a,b]:\n")
        # a=input("输入a:\n")
        # b=input("输入b:\n")
        a=10
        b=20
        a = int(a)
        b = int(b)
        m=max(a-min(x),max(x)-b)
        for i in range(0,l):
            if x[i]<a:
              x[i]=1-(a-x[i])/m
            elif x[i]>b:
                x[i]=1-(x[i]-b)/m
            else:
              x[i]=1
    return x


d = readxlsx("20条河流的水质情况数据.xlsx")
print(len(d))#长度:4列
print(d)
# ainpos = input("请输入要处理的数据")
# pos = [int(n) for n in ainpos.split()]#split()把数据分开,转换为list
pos=[2,3,4]
print(pos)
pos =np.array(pos)
# typ = input("请输入数据对应的类型")
# typp = [int(n) for n in typ.split()]
typp=[3,2,4]
np.array(typp)

for i in range(0,len(pos)):
    d[pos[i]-1,:]=opsis(d[pos[i]-1,:],typp[i])
np.set_printoptions(suppress=True)

print(d)

print(d.shape)
bb=d.T
# print(bb)

##写入文件
pd_data = pd.DataFrame(bb,columns=['A','B','C','D'])
print(pd_data)
pd_data.to_csv('pd_data.csv')


# np.savetxt('asb.csv',d,delimiter=',')

在这里,我想说明几个点
先summary一下~

  1. 写入excel
  2. np几个函数的运用
  3. 转dataframe 存csv

写入excel
用xlrd这个库来,读取index然后获取所有的行和列,用一个空list来存数据,
最后为了方便进行下一步的数据处理,需要转ndarray

xlsx=xlrd.open_workbook
xlsx.sheet_by_index(0) # 通过sheet索引获取所需sheet对象 ,sheet(x)为索引值,索引从0开始计算;
rows = sheet.nrows
readcontent = []# 用空list来存已经处理完的数据

np几个函数的运用需要注意一下:

np.abs(x)
#使用np.abs()之前需要将x整型化
np.set_printoptions(suppress=True)#强制小数点化

转dataframe存表格

bb=d.T
# print(bb)
##写入文件
pd_data = pd.DataFrame(bb,columns=['A','B','C','D'])
print(pd_data)
pd_data.to_csv('pd_data.csv')
第二步 标准化

其实标准化的方法与公式有很多很多,网上有用scikit-learn封装好的标准化函数来进行标准化的,我这里直接用清风教的标准化方法
构造加权规范矩阵,属性进行向量规范化,即每一列元素都除以当前列向量的范数(使用余弦距离度量))
对所有已经正向化后的矩阵:
z i j = x i j / ∑ i = 1 n x i j 2 \mathrm{z}_{\mathrm{ij}}=\mathrm{x}_{\mathrm{ij}}/\sqrt{\sum_{\mathrm{i}=1}^{\mathrm{n}}{\mathrm{x}_{\mathrm{ij}}^{2}}} zij=xij/i=1nxij2
代码也很简单:

def sta(m):
    summ = sum(m * m)
    okm = m / np.sqrt(summ)
    return okm
#主函数:
for i in range(0, d.shape[0]):
    d[i, :] = sta(d[i, :])

第三步 归一化并计算得分在这里插入图片描述
def dp(arr):
    maxx = np.max(arr, axis=0)#沿纵轴方向进行
    minn = np.min(arr, axis=0)
    summ = 0
    sumn = 0
    dump = []
    dumn = []
    s = []
    for i in range(0, arr.shape[0]):
        for j in range(0, arr.shape[1]):
            summ += (maxx[j] - arr[i, j]) ** 2
            sumn += (minn[j] - arr[i, j]) ** 2
        dump.append(np.sqrt(summ))
        dumn.append(np.sqrt(sumn))
        temp = np.sqrt(sumn) / (np.sqrt(summ) + np.sqrt(sumn))
        s.append(temp)
    return np.array(s)
ss = dp(dd)

Pandas效率搞定topsis

部分代码参考于这篇文章

读取excel的xlsx
d = readxlsx("20条河流的水质情况数据.xlsx")
def readxlsx(file):
    sheet = pd.read_excel(io=file, index_col=0)
    # io 文件名   index_col=0   将表格第一列指定为dataframe的index
    return sheet

这时候数据就会被读取为dataframe格式
在这里插入图片描述

同向化

首先在主函数中:

file_columns = d.columns.tolist()#读取所有的列的列顶
print("共有以下几列数据需要处理,请输入每组数据对应的type:\n")
print(file_columns)
print("\n")
for i in file_columns:
    print("对应 ( %s ) 的数据,它的type是:"%i)
    tt=input('type: ')
    opsis(d[i],int(tt))#依次询问遍历

在这里插入图片描述
在这里我写了个函数来处理各种数据类型

def opsis(x, typp):#x  一整列数据  typp 数据对应的类型
    if typp == 1:
        def normalization(data):
            return data
    if typp == 2:
        print("极小型\n")
        def normalization(data):
            return max(x) - data
    if typp == 3:
        print("中间型,需要输入best:\n")
        best = 7
        best = int(best)  ##这块一定要转为整型
        m = max(np.abs(x - best))

        def normalization(data):
            return 1 - np.abs(data - best) / m
    if typp == 4:
        print("区间型,需要输入区间[a,b]:\n")
        a = 10
        b = 20
        a = int(a)
        b = int(b)
        m = max(a - min(x), max(x) - b)

        def normalization(data):
            if data < a:
                return 1 - (a - data) / m
            elif data > b:
                return 1 - (data - b) / m
            else:
                return 1
    return list(map(normalization, x))

看到这么多代码,你是不是眼花了呢,下面我来一一解释
对于极小型:

    if typp == 2:
        print("极小型\n")
        def normalization(data):
            return max(x) - data

对于中间型:

 if typp == 3:
        print("中间型,需要输入best:\n")
        best = input('你觉得最佳中间值是:')
        best = int(best)  ##这块一定要转为整型,不然是str
        m = max(np.abs(x - best))
        def normalization(data):
            return 1 - np.abs(data - best) / m

对于区间型:

    if typp == 4:
        print("区间型,需要输入区间[a,b]:\n")
        a = input('请输入区间的下界: \n')
        b = input('请输入区间的上界: \n')
        a = int(a)
        b = int(b)
        m = max(a - min(x), max(x) - b)
        def normalization(data):
            if data < a:
                return 1 - (a - data) / m
            elif data > b:
                return 1 - (data - b) / m
            else:
                return 1

最后再return 一下

 return list(map(normalization, x))

这里的map是利用了map的映射原理,将数据丢进定义好的normalization进行一一对应的处理
list是使得所有的数据变成list类型好修改原来dataframe的数据

标准化与归一化&程序完成

到这里,只要对原来的数据进行标准化与归一化处理之后,再根据公式进行计算得分,整个程序基本就完事了
先定义一个函数topsis,参考某个大佬的代码

def topsis(data, weight=None):
    # 归一化
    data = data / np.sqrt((data ** 2).sum())
    print("----------------\n")
    print(data)
    # 最优最劣方案
    Z = pd.DataFrame([data.min(), data.max()], index=['负理想解', '正理想解'])
    # print(Z)
    # 距离
    # weight = entropyWeight(data) if weight is None else np.array(weight)* weight* weight
    Result = data.copy()
    Result['正理想解'] = np.sqrt(((data - Z.loc['正理想解']) ** 2).sum(axis=1))
    Result['负理想解'] = np.sqrt(((data - Z.loc['负理想解']) ** 2).sum(axis=1))
    # print(Result)
    # 综合得分指数
    Result['综合得分指数'] = Result['负理想解'] / (Result['负理想解'] + Result['正理想解'])
    Result['标准化得分指数'] = Result['综合得分指数'] / Result['综合得分指数'].sum()
    Result['排序'] = Result.rank(ascending=False)['标准化得分指数']
    Result.to_csv("ans.csv", encoding="utf_8_sig")
    return Result, Z, weight

先标准化

data = data / np.sqrt((data ** 2).sum())

这块注意下~dataframe的求和不是sum(dataframe),而是dataframe.sum()
用一个dataframe来装最优最劣解

 Z = pd.DataFrame([data.min(), data.max()], index=['负理想解', '正理想解'])

这里的.min()和.max()是按照每一列相加
按照每一行相加是.sum(axis=1)
接着算每个数据的解

    Result = data.copy()
    Result['正理想解'] = np.sqrt(((data - Z.loc['正理想解']) ** 2).sum(axis=1))
    Result['负理想解'] = np.sqrt(((data - Z.loc['负理想解']) ** 2).sum(axis=1))

loc用于提取数据
接着算分,然后排序

    Result['综合得分指数'] = Result['负理想解'] / (Result['负理想解'] + Result['正理想解'])
    Result['标准化得分指数'] = Result['综合得分指数'] / Result['综合得分指数'].sum()
    Result['排序'] = Result.rank(ascending=False)['标准化得分指数']
    Result.to_csv("ans.csv", encoding="utf_8_sig")
    return Result, Z, weight

整个程序完事儿

整个python 代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
import pandas as pd
import xlrd
from sklearn import preprocessing


def readxlsx(file):
    sheet = pd.read_excel(io=file, index_col=0)
    return sheet


def dataDirection_1(datas, offset=0):
    def normalization(data):
        return 1 / (data + offset)

    return list(map(normalization, datas))


def opsis(x, typp):
    if typp == 1:
        def normalization(data):
            return data
    if typp == 2:
        print("极小型\n")
        def normalization(data):
            return max(x) - data
    if typp == 3:
        print("中间型,需要输入best:\n")
        best = 7
        best = int(best)  ##这块一定要转为整型
        m = max(np.abs(x - best))

        def normalization(data):
            return 1 - np.abs(data - best) / m
    if typp == 4:
        print("区间型,需要输入区间[a,b]:\n")
        a = 10
        b = 20
        a = int(a)
        b = int(b)
        m = max(a - min(x), max(x) - b)

        def normalization(data):
            if data < a:
                return 1 - (a - data) / m
            elif data > b:
                return 1 - (data - b) / m
            else:
                return 1
    return list(map(normalization, x))


def topsis(data, weight=None):
    # 归一化
    data = data / np.sqrt((data ** 2).sum())
    print("----------------\n")
    print(data)
    # 最优最劣方案
    Z = pd.DataFrame([data.min(), data.max()], index=['负理想解', '正理想解'])
    # print(Z)
    # 距离
    # weight = entropyWeight(data) if weight is None else np.array(weight)* weight* weight
    Result = data.copy()
    Result['正理想解'] = np.sqrt(((data - Z.loc['正理想解']) ** 2).sum(axis=1))
    Result['负理想解'] = np.sqrt(((data - Z.loc['负理想解']) ** 2).sum(axis=1))
    # print(Result)
    # 综合得分指数
    Result['综合得分指数'] = Result['负理想解'] / (Result['负理想解'] + Result['正理想解'])
    Result['标准化得分指数'] = Result['综合得分指数'] / Result['综合得分指数'].sum()
    Result['排序'] = Result.rank(ascending=False)['标准化得分指数']
    Result.to_csv("ans.csv", encoding="utf_8_sig")
    return Result, Z, weight


d = readxlsx("20条河流的水质情况数据.xlsx")
print(d)
file_columns = d.columns.tolist()
print("共有以下几列数据需要处理,请输入每组数据对应的type:\n")
print(file_columns)
print("\n")
for i in file_columns:
    print("对应 ( %s ) 的数据,它的type是:"%i)
    tt=input('type:\n')
    opsis(d[i],int(tt))



# d['PH值'] = opsis(d['PH值'], 3)
# # print(d['PH值'])
# d['细菌总数(个/mL)'] = opsis(d['细菌总数(个/mL)'], 2)
# d['植物性营养物量(ppm)'] = opsis(d['植物性营养物量(ppm)'], 4)
# d.to_csv("zhengxianghua.csv", encoding="utf_8_sig")
# dd = d[['含氧量(ppm)', 'PH值', '细菌总数(个/mL)', '植物性营养物量(ppm)']]
topsis(d)

基于熵权法对于Topsis的改进

实际上,对于每种数据,他们肯定有着不同的权重,下面我们用熵权法来获取这些数据的权重。

百度这样解释熵权法:

根据信息熵的定义,对于某项指标,可以用熵值来判断某个指标的离散程度,其信息熵值越小,指标的离散程度越大, 该指标对综合评价的影响(即权重)就越大,如果某项指标的值全部相等,则该指标在综合评价中不起作用。

上面的话简单着来说,就是用熵来分析一种数据的离散程度,如果熵值越小,其离散程度就会越大,其指标对综合评价的影响也会也大,通过量化这个熵值来确定各种数据的权重
用熵权法求权重一共有几个步骤

对初始数据进行归一化

使所有的数据都归一于[ 0 ,1 ]之间,使用公式
z i j = x i j / ∑ i = 1 n x i j 2 z_{ij}=x_{ij}/\sqrt{\sum_{i=1}^n{x_{ij}^{2}}} zij=xij/i=1nxij2
你有没有发现这个公式和之前进行归一化用的公式一样呢,没错是一模一样的~,但是归一化的方式有很多,不单单是这个公式有用。
这个公式只能用于非负数据中,而对于存在负数的数据集
就要用下列的公式:
z i j = x i j − min ⁡ { x 1 j , x 2 j , x 3 j , . . . , x n j } max ⁡ { x 1 j , x 2 j , x 3 j , . . . , x n j } − min ⁡ { x 1 j , x 2 j , x 3 j , . . . , x n j } z_{ij}=\frac{x_{ij}-\min \left\{ x_{1j},x_{2j},x_{3j},...,x_{nj} \right\}}{\max \left\{ x_{1j},x_{2j},x_{3j},...,x_{nj} \right\} -\min \left\{ x_{1j},x_{2j},x_{3j},...,x_{nj} \right\}} zij=max{x1j,x2j,x3j,...,xnj}min{x1j,x2j,x3j,...,xnj}xijmin{x1j,x2j,x3j,...,xnj}

  if data[data < 0].value_counts().empty:
        data = data / np.sqrt((data ** 2).sum())
    else:
        data = (data -data.min())/(data.max()-data.min())
求出各项数据的出现概率

计算第j项指标下第i个样本所占的比重,并将其看作相对熵计算中用到的概率

对于处理完后的数据
A = [ a 11 a 12 ⋯ a 1 m a 21 a 22 ⋯ a 2 m ⋮ ⋮ ⋱ ⋮ a n 1 a n 2 ⋯ a n m ] A=\left[ \begin{matrix} a_{11}& a_{12}& \cdots& a_{1m}\\ a_{21}& a_{22}& \cdots& a_{2m}\\ \vdots& \vdots& \ddots& \vdots\\ a_{n1}& a_{n2}& \cdots& a_{nm}\\ \end{matrix} \right] A=a11a21an1a12a22an2a1ma2manm
计算每个元素的概率值 p i j p_{ij} pij
p i j = a i j ∑ i = 1 n a i j p_{ij}=\frac{a_{ij}}{\sum\limits_{i=1}^n{a_{ij}}} pij=i=1naijaij
信息熵计算公式
e i j = − 1 ln ⁡ n ∑ i = 1 n p i j ln ⁡ ( p i j )    ( j = 1 , 2 , . . . , m ) e_{ij}=-\frac{1}{\ln n}\sum_{i=1}^n{p_{ij}\ln \left( p_{ij} \right) \,\,\left( j=1,2,...,m \right)} eij=lnn1i=1npijln(pij)(j=1,2,...,m)
为了更好地进行比较,对信息熵进行归一化
归一化后的数据就是我们要求的权值
W j = ( 1 − e i j ) / ∑ j = 1 m ( 1 − e i j )    ( j = 1 , 2 , . . . , m ) W_j=\left( 1-e_{ij} \right) /\sum_{j=1}^m{\left( 1-e_{ij} \right) \,\,\left( j=1,2,...,m \right)} Wj=(1eij)/j=1m(1eij)(j=1,2,...,m)

def w(data):
    # file_columns = d.columns.tolist()
    # for i in file_columns:
    #     d[i<0]
    # print("####################")
    # print(data[data<0].value_counts())
    if data[data < 0].value_counts().empty:
        data = data / np.sqrt((data ** 2).sum())
    else:
        data = (data -data.min())/(data.max()-data.min())
    P = data/data.sum()
    # E = np.nansum(-P * np.log(P)), axis=0)
    E = np.sum(-P*np.log(P)/np.log(len(data.index)),axis=0)
    print(E)
    return (1-E)/sum((1-E))

本文链接: http://www.dtmao.cc/news_show_2000051.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?