产量数据选取问题2

数据集

选用了某一单井从18年至21年的1431天产量数据。
缺省:
Flowing Pressure (psi)流动压力属性所有数据都为空。
当天若没有对应的操作,计量的产液量和含水率也为空。

数据处理

整理数据,为数据打上标签。

转换格式
使数据转换成容易用来训练的格式:
方法1. 带有关键词“measuring”或者“sampling”的数据作为数据主元,其余数据按时间逆向查找到前一个主元为止,不包前一个主元。但是会造成每一数据项的属性长度不同的问题。
方法2. 在实际情况下,只有计量或者取样过后,才会出现数据选取问题。所以直接提取带有“measuring”或者“sampling”的数据。
目前暂时选取方法 2

其余操作

  • 对于没有值的属性,用 0 值补充。
  • 对于备注数据,在匹配规则后去掉。
  • 在工作时间这一属性,需要根据备注再严格匹配到产液量(待完善
  • 在有对应规则的操作的情况下,若能匹配到规则,则标签置为1,否则为 -1。若无对应规则的操作,标签置 0

模型

MLP,Multi-layer Perceptron 多层感知机。

结果

匹配含有计量的数据,格式化得到数据453项。训练集与测试集比例为 4:1 。
得到对含水率的选取判断能达到较高的准确率(95%左右)。但是对产液量,准确率较低(80%左右)。

下一步工作

  1. 完成剩余规则的编写,按照匹配规则数量划分数据集。
  2. 学习神经网络的工作过程及原理。

源码

py文件:
rules_data.py:

import copy
import csv
import numpy as np

# 字符匹配
import re

# 时差
import time as t
import datetime as d


class Bunch(dict):
    def __init__(self, **kwargs):
        super().__init__(kwargs)

    def __setattr__(self, key, value):
        self[key] = value

    def __dir__(self):
        return self.keys()

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(key)

    def __setstate__(self, state):
        pass


remarks = ['Measuring', 'Sampling', 'well shut in', 'open well', 'stop pump']


def loadCSVDataset(csvFileName='../data/productionData.csv'):
    csv_reader = csv.reader(open(csvFileName, 'r'))
    data = []
    target = []
    idxFirstCol = 1

    firstRow = next(csv_reader)
    feature_names = firstRow[idxFirstCol:-2]
    target_names = firstRow[-2:]

    row = []
    for row in csv_reader:
        data.append(row[idxFirstCol:-2])
        target.append(row[-2:])

    numInstances = len(target)
    print("feature names: " + str(feature_names) + "\n" + "numInstance: " + str(numInstances))

    data = np.array(data)
    target = np.array(target)
    return Bunch(
        data=data,
        target=target,
        target_names=target_names,
        feature_names=feature_names
    )


# 规则匹配,产液量
# 实质按照产液速率来计算!
def ruleProduction():
    if 1:
        temp = 0
    else:
        temp = 1


# 规则匹配,含水率
def ruleWatercut():
    if 1:
        temp = 0
    else:
        temp = 1


# 规则匹配,停产
def ruleWellshutin():
    if 1:
        temp = 0
    else:
        temp = 1


# 规则匹配,泵频率
def ruleFre():
    if 1:
        temp = 0
    else:
        temp = 1


# 规则匹配,油嘴尺寸
def ruleChoke():
    if 1:
        temp = 0
    else:
        temp = 1


# 规则匹配,开井
def ruleOpenwell():
    if 1:
        temp = 0
    else:
        temp = 1


# 规则匹配,停泵
def ruleStoppump():
    if 1:
        temp = 0
    else:
        temp = 1


# 读取备注,匹配对应规则并执行。
# 非关键词,属性则为必须执行的规则。
def readRemarks():
    if 1:
        temp = 0
    else:
        temp = 1


# 为数据打上标签 when measuring | sampling
# paraDataset: 数据集
# paraIdx: 被处理数据项的下标
# return: 产液量、含水率是否选用的标签
def markLabel(paraDataset, paraIdx):
    measureStr = remarks[0]     # Measuring 关键字
    sampleStr = remarks[1]      # Sampling 关键字

    idxFluidRatInUse = 11       # 正在使用的产液量 下标
    idxWaterCutInUse = 15       # 正在使用的含水率 下标
    idxMeasureF = 8             # 产液量计量 下标
    idxMeasureW = 14            # 含水率取样 下标

    matchMeasure = re.match(measureStr, paraDataset.data[paraIdx][-1], re.M | re.I)     # 关键字匹配
    matchSample = re.match(sampleStr, paraDataset.data[paraIdx][-1], re.M | re.I)       # 关键字匹配

    targetF = 0
    targetW = 0

    if matchMeasure != None:        # 匹配到产液量计量
        preFluidRate = float(paraDataset.data[paraIdx - 1][idxFluidRatInUse])   # 以前选取的产液量
        nowMeasureF = float(paraDataset.data[paraIdx][idxMeasureF])             # 当前计量值
        changeRate = abs(float(preFluidRate) - float(nowMeasureF)) / float(preFluidRate)    # 变化率

        # 匹配具体规则
        if preFluidRate >= 1000:
            if changeRate <= 0.2:
                targetF = 1
            else:
                targetF = -1
        else:
            if changeRate <= 0.3:
                targetF = 1
            else:
                targetF = -1
    else:       # 未匹配到则是没有计量
        paraDataset.data[paraIdx, idxMeasureF:idxMeasureF + 3] = 0

    if matchSample != None:         # 匹配到含水率取样
        preWaterCut = float(paraDataset.data[paraIdx - 1][idxWaterCutInUse])    # 以前选取的产液量
        nowMeasureW = float(paraDataset.data[paraIdx][idxMeasureW])             # 当前计量值
        changeRate = abs(float(preWaterCut) - float(nowMeasureW))               # 变化率

        # 匹配具体规则
        if preWaterCut >= 0.8:
            if changeRate <= 0.05:
                targetW = 1
            else:
                targetW = -1
        elif preWaterCut > 0.2:
            if changeRate <= 0.08:
                targetW = 1
            else:
                targetW = -1
        else:
            if changeRate <= 0.05:
                targetW = 1
            else:
                targetW = -1


    return targetF, targetW


# 03 = {str) 'Choke\n(/64)\n(inch)'
# 04 = (str) 'Fre.\n(hz)'
# 05 = {str)'Pump\nDepth\n(ft.)'
# 06 = {str) 'Pump\nFlowrate\n(bbl/h)'
# 07 = (str} 'Working\nHours\n(h)'
# 08 = {str) 'Fluid Rate\n(bbl/d)       ***
# 09 = {str} 'Oil Rate\n(bbl/d)
# 10 = {str) 'Gas Rate\n(Mscf/d)'       ***
# 11 = {str) 'Fluid Rate\n(bbl/d)'      ***
# 12 = {str) 'Oil Rate\n(bbl/d)'
# 13 = (str) 'Gas Rate\n(Mscf/d)'       ***
# 14 = {str) 'Measured\n(%)'            ***
# 15 = {str) 'Decade\n(%)'              ***
# 16 = {str) 'GOR\n(scf/stb)'
# 17 = {str} 'Wellhead\nPressure\n(psi)'
# 18 = {str) 'CasingVnPressure\n(psi)'
# 19 = {str) 'Back\nPressuren(psi)'
# 20 = (str) 'Tem.\n(RC)'
# 21 = {str) 'Flowing\nPressure\n(psi)'
# 22 = {str} 'ESD\nPre.\n(psi)'
# 23 = {str) 'Pi\n(psi)'
# 24 = (str) 'Pd\n(psi)'
# 25 = {str) 'vVSD\nCurr.\n (A)'
# 26 = {str) 'Remarks'
# _len_ = {int)27
#
# 整理数据,为数据打上标签
# 并且使数据转换成容易用来训练的格式
# 1.
# 带有关键词“measuring”或者“sampling”的数据作为数据主元,
# 其余数据按时间逆向查找到前一个主元为止,不包前一个主元。
# 2.
# 直接提取带有“measuring”或者“sampling”的数据
#
# 暂时选取方法 2
# remarks = ['Measuring', 'Sampling', 'well shut in', 'open well', 'stop pump']

# 数据格式化为便于训练的格式
# paraData: 数据集
# return: 选用数据项的下标, 格式化后的数据集
def dataFormat4rule(paraData):
    measureStr = remarks[0]     # 产液计量关键词
    sampleStr = remarks[1]      # 含水抽样关键词

    dataFormatted = []          # list 格式化后的数据
    labelFormatted = []         # list 格式化后的标签(target)
    selectedIndex = []          # 方法2,被选取数据的下标

    tempData = copy.deepcopy(paraData)

    deleteColumn = [21]     # 该属性暂时无数据 21 = {str) 'Flowing\nPressure\n(psi)'

    for i in deleteColumn:
        tempData.data[:, i] = 0

    i = 0
    for row in tempData.data:
        matchObj = re.match(measureStr + r'|' + sampleStr, row[-1], re.M | re.I)
        if matchObj == None:
            i += 1
            continue
        else:
            tempData.target[i][0], tempData.target[i][1] = markLabel(tempData, i)	# 返回 int,自动转 str_  !!!加载时读入数据长度有关?出错!!!
            dataFormatted.append(row[4:-1].astype(np.float))
            labelFormatted.append(tempData.target[i, :].astype(np.float))
            selectedIndex.append(i)
            i += 1

    tempData.feature_names.pop(-1)
    tempData.data = dataFormatted
    tempData.target = labelFormatted
    tempData.data = np.array(tempData.data)
    tempData.target = np.array(tempData.target)
    return selectedIndex, tempData


# testunit
def testime():
    str1 = 'Sampling,00:10-00:20&01:30-11:20 stop pump'
    str2 = ' stop pump'
    matchObjtime = re.search(r'(\d+:\d+)-(\d+:\d+)&(\d+:\d+)-(\d+:\d+)' + str2, str1, re.M | re.I)
    matchObjtime = re.search(r'(\d+:\d+)-(\d+:\d+)&(\d+:\d+)-(\d+:\d+)' + str2, str1, re.M | re.I)
    if matchObjtime == None:
        print(matchObjtime)
        return
    strtime = matchObjtime.group(0)

    matchObjtimes = re.search(r'(.*)&(.*)', strtime, re.M | re.I)
    time1 = matchObjtimes.group(1)
    time2 = matchObjtimes.group(2)

    matchObjtimes1 = re.search(r'(.*)-(.*)', time1, re.M | re.I)
    timestr = matchObjtimes1.group(1)
    timeend = matchObjtimes1.group(2)

    print(strtime)
    print(time1)
    print(time2)
    print(timestr)
    print(timeend)
    myDate(timestr, timeend)


# 定义时间差函数
def myDate(date1, date2):
    date1 = t.strptime(date1, "%H:%M")
    date2 = t.strptime(date2, "%H:%M")
    startTime = t.strftime("%H:%M", date1)
    endTime = t.strftime("%H:%M", date2)

    startTime = d.datetime.strptime(startTime, "%H:%M")
    endTime = d.datetime.strptime(endTime, "%H:%M")
    date = endTime - startTime

    print(date.seconds / 3600.0)
    print(date)
    return date.seconds / 3600.0


dataSelection.py:

import rules_data as rl

# 模型
from sklearn import neural_network
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score


def main():
    dataset = rl.loadCSVDataset()       # 加载数据
    Index, formattedData = rl.dataFormat4rule(dataset)  # 数据格式化成易于训练的格式

    x_train, x_test, y_train, y_test = \
        train_test_split(formattedData.data, formattedData.target[:, 1], test_size=0.2, random_state=1)     # 数据划分, 标签目前仅选取了一个

    model = neural_network.MLPClassifier(hidden_layer_sizes=10,  # 隐藏层
                                         # hidden_layer_sizes=(50, 50),表示有两层隐藏层,第一层隐藏层有50个神经元,第二层也有50个神经元。
                                         activation='relu',  # 激活函数
                                         solver='adam',
                                         alpha=0.001,  # 正则化项系数
                                         batch_size='auto',
                                         learning_rate='constant',  # 学习率
                                         learning_rate_init=0.01,
                                         power_t=0.5,
                                         max_iter=200,    # 迭代次数
                                         tol=1e-4)

    model.fit(x_train, y_train)         # 模型训练
    x_predict = model.predict(x_test)   # 预测
    print(x_predict)                    # 预测结果
    tempAccuracy = accuracy_score(y_test, x_predict)    # 准确率
    print('准确率:', tempAccuracy)
    # print('类别数:\n', model.n_outputs_)       # 输出类别数
    # print('所有类别:\n', model.classes_)        # 所有类别
    # print('损失函数损失值:\n', model.loss_)    # 损失函数的损失值
    # print('偏移量:\n', model.intercepts_)      # 偏移量
    #
    # print('权重:\n', model.coefs_)
    # print('迭代轮数:\n', model.n_iter_)
    # print('网络层次:\n', model.n_layers_)  # 只有一层隐藏层时 =3
    # print('输出层的激活函数名称:\n', model.out_activation_)

    return


main()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值