时间序列问题解题(基于经验模型,使用机器学习模型)(Datawhale AI 夏令营)

数学难 2024-08-23 13:01:01 阅读 93

示例题目:2024 iFLYTEK A.I.开发者大赛-讯飞开放平台 (xfyun.cn)

一,时间序列问题概述

1、时间序列问题定义

        时间序列问题是一类重要的统计和数据分析问题,它涉及对按时间顺序排列的数据点进行分析、建模和预测。时间序列数据是由一系列随时间变化而观测到的数值组成的,这些数据可以反映各种现象,如股票价格、气温变化、销售额、交通流量等。时间序列分析广泛应用于经济学、金融学、气象学、工程学、公共卫生学等众多领域。

2、时间序列预测问题的数据的主要特点

时间依赖性:时间序列数据中的观测值之间存在时间上的依赖性,即当前的值往往受到过去值的影响。这种依赖性是时间序列数据最本质的特征,它使得时间序列分析能够揭示数据随时间变化的动态规律。

趋势性:时间序列数据可能呈现出一种长期的增长或下降趋势。这种趋势可能是由于外部因素(如政策变化、技术进步等)或内部因素(如市场需求、消费者偏好等)引起的。趋势分析是时间序列分析的重要内容之一。

季节性:某些时间序列数据会呈现出周期性的波动,这种波动通常与季节、节日、假期等因素有关。季节性分析有助于我们理解数据中的周期性变化,并据此进行预测和规划。

随机性:尽管时间序列数据具有时间依赖性、趋势性和季节性等特点,但仍然存在一些无法解释的随机波动。这些随机波动可能是由于偶然因素、测量误差或系统噪声等原因引起的。在时间序列分析中,我们需要考虑这些随机波动对预测结果的影响。

不可重复性:每个时间序列都是独特的,因为它包含了在特定时间点和条件下发生的特定事件和观测值。这意味着我们不能简单地复制或重新生成一个完全相同的时间序列,除非在完全相同的条件下进行重复实验或观测。

数据长度:时间序列的长度(即观测值的数量)可以影响分析的复杂性和准确性。较长的时间序列通常包含更多的信息,有助于揭示更复杂的模式和关系。然而,过长的时间序列也可能包含过多的噪声和冗余信息,需要进行适当的数据预处理和特征选择。

非平稳性:许多时间序列数据是非平稳的,即其统计特性(如均值、方差等)随时间而变化。非平稳性增加了时间序列分析的难度,因为传统的统计方法往往假设数据是平稳的。为了处理非平稳时间序列,我们可能需要采用差分、趋势分解或季节性调整等方法来使其变得平稳。

3、时间序列预测问题建模

1、模型概述与建模思路

传统时间序列模型

建模思路:基于时间序列数据的统计特性,如自相关性、季节性等,通过ARIMA、SARIMA、指数平滑等方法,识别并建模数据的趋势和季节性成分。优点:模型结构简单,易于理解和解释;计算效率高,适合处理小规模数据集;直接针对时间序列特性设计,能有效处理季节性和趋势。缺点:对非线性模式和复杂数据预测能力有限;需手动调整参数;对数据的平稳性有严格要求,非平稳数据需预处理。机器学习模型

建模思路:将时间序列预测转化为监督学习问题,利用历史数据作为特征,未来值作为标签,采用决策树、随机森林、梯度提升树等模型。通过特征工程提取有用信息。优点:能够处理非线性关系和复杂数据模式;可通过特征工程引入额外变量,提高预测准确性;模型选择多样,支持模型融合。缺点:对时间序列内在时间结构和季节性的敏感度可能不足;需要大量特征工程;模型解释性可能不如传统时间序列模型直观。深度学习模型

建模思路:利用RNN、LSTM、1D-CNN等网络结构,捕捉时间序列中的长期依赖关系和复杂模式,通过大量参数训练学习数据特征。优点:擅长处理复杂数据模式和长期依赖关系;适用于大数据集,能自动提取特征;模型灵活性和适应性强。缺点:需要大量数据和计算资源;模型训练和调优复杂耗时;解释性较差,难以直接理解预测依据。

2、对比总结

适用性

传统模型:适用于数据量小、模式简单、对解释性要求高的场景。机器学习模型:适用于中等复杂度问题,特别是当需要引入额外变量或进行复杂特征工程时。深度学习模型:适用于大数据量、模式复杂、对预测精度要求高的任务。解释性

传统时间序列模型:通常具有较好的解释性,便于理解和应用。机器学习模型:解释性取决于特征工程的质量和模型选择,可能需要额外分析。深度学习模型:解释性较差,通常需要借助其他工具或方法进行后验分析。计算资源

传统模型:计算效率最高,资源需求最少。机器学习模型:资源需求适中,依赖于特征工程和数据集大小。深度学习模型:通常需要最多的计算资源和时间,特别是训练大型网络时。预测能力

深度学习模型:在捕捉复杂模式和长期依赖方面表现优异,但需大量数据支持。传统和机器学习模型:在数据量较小或模式较简单时,可能更为有效,特别是当快速响应和可解释性更为重要时。

二、基于经验模型(使用均值作为结果数据)来解决的问题

1、导入相关库

<code># 1. 导入需要用到的相关库

# 导入 pandas 库,用于数据处理和分析

import pandas as pd

# 导入 numpy 库,用于科学计算和多维数组操作

import numpy as np

2、读取训练集和测试集

# 使用 read_csv() 函数从文件中读取训练集数据,文件名为 'train.csv'

train = pd.read_csv('train.csv')

# 使用 read_csv() 函数从文件中读取测试集数据,文件名为 'test.csv'

test = pd.read_csv('test.csv')

3、计算训练数据最近11-20单位时间内对应id的目标均值

dt列表示时间或日期的某种索引,且从较小的数值开始(如1, 2, 3, ...)

这里选择dt<=20作为条件,意味着我们关注从时间起点开始的前20个单位时间(但实际上是第11到第20个,因为dt=1时也在内)

使用groupby按id分组,然后对每个分组内的target列计算平均值

注意:这里的选择可能忽略了dt的确切范围,因为我们是直接对所有dt<=20的数据进行平均,而不是对每个id分别考虑其最近的11-20个时间单位

 

target_mean = train[train['dt'] <= 20].groupby('id')['target'].mean().reset_index()

# train[train['dt'] <= 20]:首先筛选出dt列值小于或等于20的行。

# .groupby('id'):然后按照id列的值对数据进行分组。

# ['target'].mean():对每个分组内的target列计算平均值。

# .reset_index():将分组键(即id)从索引转换为DataFrame中的一列,并添加一个新的整数索引。

4、将target_mean作为测试集结果进行合并

使用merge函数将target_mean DataFrame与test DataFrame合并

合并基于id列,使用左连接(how='left'),这样test中的所有id都会保留在结果中

如果某个id在target_mean中没有对应的平均值(即该id在训练集的指定时间段内没有记录),则合并后的DataFrame中该id的target列将为NaN

<code>test = test.merge(target_mean, on='id', how='left')code>

5、保存结果文件到本地

test[['id', 'dt', 'target']].to_csv('submit.csv', index=None)

三、使用机器学习模型解决本次问题

使用机器学习方法一般主要需要从 获取数据&增强特征提取模型 三个方面下手。

1、使用机器学习方法的一般步骤

1. 问题定义与数据收集

问题定义:首先,需要明确机器学习要解决的问题是什么,比如分类、回归、聚类等。数据收集:根据问题定义收集相关的数据集。数据集应包含足够多的样本和特征,以便模型能够从中学习到有效的规律。

2. 数据预处理

数据预处理是机器学习流程中至关重要的一个环节,它直接影响到后续模型的性能和准确度。数据预处理通常包括以下几个步骤:

数据清洗:去除数据中的噪声、重复项、无效数据等,确保数据的准确性和一致性。缺失值处理:对缺失的数据进行填充或删除,常用的方法包括均值填充、中位数填充、插值填充等。数据转换:将原始数据转换为适合模型处理的形式,包括特征缩放、独热编码、离散化等。数据归一化/标准化:将不同量纲或量级的特征值转换到同一尺度下,以避免对模型训练的影响。

3. 特征选择与提取

特征选择:从原始特征中选择出对预测目标最有用的特征,以提高模型的效率和准确度。特征提取:通过一定的算法从原始数据中提取出新的特征,这些特征可能更有助于模型的学习。

4. 模型选择与训练

模型选择:根据问题的性质和数据的特性选择合适的机器学习模型,如线性回归、逻辑回归、决策树、随机森林、神经网络等。模型训练:使用训练数据集对选定的模型进行训练,通过调整模型的参数来优化模型在训练集上的表现。

5. 模型评估与优化

模型评估:使用测试数据集对训练好的模型进行评估,以检验模型的泛化能力。常用的评估指标包括准确率、召回率、F1分数等。模型优化:根据评估结果对模型进行调整和优化,以提高模型在测试集上的表现。优化方法包括调整模型参数、改进特征选择、更换模型等。

6. 模型部署与应用

模型部署:将训练好并经过优化的模型部署到实际的生产环境中,以便对新的数据进行预测或分类。模型应用:根据业务需求使用模型进行预测或决策支持,同时监控模型的性能并根据需要进行更新和维护。

2、基本概念

1、GBDT

GBDT(Gradient Boosting Decision Tree),全称为梯度提升决策树,是一种基于集成学习思想的决策树模型。它通过迭代地训练多个弱学习器(通常是决策树),并将它们的预测结果累加起来作为最终的预测输出。下面将从GBDT的定义、原理、优缺点及应用等方面进行详细介绍。

定义

GBDT是一种迭代式的boosting算法,通过不断减小训练过程产生的残差,对数据进行回归或分类。其核心在于利用损失函数的负梯度作为残差的近似值,通过多轮迭代来构建一个强大的预测模型。

原理

初始化:首先,GBDT会初始化一个弱学习器,这个学习器的预测值通常为常数或者预测数据的均值等。迭代训练:在每一轮迭代中,GBDT会计算当前预测值与真实值之间的残差,并基于这个残差来训练一个新的弱学习器。这个新的弱学习器会尽量拟合这个残差,从而使得预测值更接近真实值。累加预测:将新训练的弱学习器的预测结果累加到之前的预测结果上,得到新的预测值。重复迭代:重复上述步骤,直到达到预定的迭代次数或者残差小于某个阈值为止。

优缺点

优点

预测准确率高:通过组合多个弱学习器来形成一个强学习器,能够显著提高预测准确率。对异常值鲁棒性强:GBDT使用一些健壮的损失函数,如Huber损失函数和Quantile损失函数,这些函数能够对异常值进行有效处理,从而增强了模型对噪声和异常值的鲁棒性。可以灵活处理各种类型的数据:GBDT能够处理连续值和离散值,无需对数据进行复杂的预处理。具有解释性:由于GBDT基于决策树构建,因此模型具有较好的解释性,可以清晰地看到每个特征对预测结果的影响。

缺点

难以并行训练:由于GBDT的迭代特性,每棵树的训练都需要依赖于前一棵树的残差,这使得在训练过程中难以实现完全的并行化。对高维稀疏数据敏感:在处理高维稀疏的数据集时,GBDT的表现可能不如支持向量机或神经网络等其他算法。调参较复杂:GBDT需要调整多个参数,包括树的数量、树的深度、学习率等,这需要一定的经验和技巧。容易过拟合:GBDT具有较强的拟合能力,在训练数据上的表现很好,但容易过拟合。为了避免过拟合,需要设置较小的学习率和较少的树的数量。

应用

GBDT以其卓越的预测精度、良好的泛化能力以及对异常值的稳健性,广泛应用于信用评分、广告点击预测、疾病诊断等多个实际场景。例如,在信用评分领域,GBDT可以通过分析用户的各种信息(如年龄、收入、消费习惯等)来预测用户的信用等级;在广告点击预测领域,GBDT可以根据用户的浏览历史和点击行为来预测用户是否会对某个广告进行点击。

综上所述,GBDT是一种强大的集成学习算法,在回归和分类任务中表现出色。然而,在实际应用中也需要注意其优缺点和适用范围,以便更好地发挥其性能。

2、LightGBM

LightGBM(Light Gradient Boosting Machine)是一种快速、高效的机器学习算法,属于梯度提升框架的一种,主要用于处理分类、回归和排序等任务。它由微软公司开发,旨在提供一个高效、快速的梯度提升决策树(GBDT)实现,具有较低的内存占用和更快的训练速度。以下是对LightGBM的详细介绍:

基本原理

LightGBM基于梯度提升决策树(GBDT)的原理,通过迭代地构建决策树来优化损失函数。与传统的GBDT算法相比,LightGBM在以下几个方面进行了优化:

基于直方图的算法:LightGBM使用了一种基于直方图的算法来处理数据。它将特征值离散化为有限的桶(bins),并为每个桶计算累计统计量(如梯度和样本数),从而构建直方图。这种方法减少了内存消耗并加速了训练过程。

单边梯度采样(GOSS):为了处理不平衡的数据分布,LightGBM采用了单边梯度采样算法。该算法保留梯度较大的样本,并对梯度较小的样本进行随机采样,同时增加这些样本的权重,以保持数据分布的一致性。

互斥特征捆绑(EFB):为了减少特征的数量并降低计算复杂度,LightGBM通过特征捆绑的方式将互斥的特征合并为一个新的特征。这种方法在不损失太多信息的情况下减少了特征的数量。

带深度限制的叶子生长(leaf-wise):在构建决策树时,LightGBM采用了按叶子节点分割的策略(leaf-wise),即每次选择增益最大的叶子节点进行分裂,并限制树的最大深度。这种策略可以更快地降低损失函数,但也可能导致过拟合。

优点

训练速度快:由于采用了基于直方图的算法和高效的并行计算技术,LightGBM的训练速度非常快,特别适合处理大规模数据集。

内存占用低:通过离散化特征和构建直方图,LightGBM显著降低了内存消耗,使得在内存有限的环境下也能进行高效的训练。

支持分布式与GPU:LightGBM支持分布式训练,可以充分利用多机多核的计算资源。同时,它也支持GPU加速,进一步提高了训练速度。

高准确率:通过优化算法和特征选择等方法,LightGBM能够构建出具有较高准确率的模型。

支持多种任务:LightGBM不仅支持分类和回归任务,还支持排序等任务,具有广泛的应用场景。

应用场景

LightGBM在多个领域都有广泛的应用,包括但不限于:

推荐系统:用于商品推荐、广告推荐等任务。

搜索引擎:用于网页排序、广告排序等任务。

金融风控:用于信用评分、欺诈检测等任务。

医疗健康:用于疾病诊断、药物研发等任务。

自然语言处理:用于情感分析、文本分类等任务。

图像识别:用于图像分类、目标检测等任务。

时间序列预测:用于股票价格预测、交通流量预测等任务。

综上所述,LightGBM是一种高效、快速且功能强大的机器学习算法,在多个领域都有广泛的应用前景。然而,在使用时需要注意参数调优、数据预处理和防止过拟合等问题。

3、代码详解

1、导入模块

import numpy as np

import pandas as pd

import lightgbm as lgb

from sklearn.metrics import mean_squared_log_error, mean_absolute_error, mean_squared_error

import tqdm

import sys

import os

import gc

import argparse

import warnings

# 告诉 Python 解释器忽略掉所有的警告信息

warnings.filterwarnings('ignore')

warnings.filterwarnings('ignore') 是 Python 中用于控制警告信息(warnings)显示的一个语句。这个语句来自于 Python 的 warnings 模块,该模块允许你控制警告的过滤、显示等行为。

当你调用 warnings.filterwarnings('ignore') 时,你实际上是在告诉 Python 解释器忽略掉所有的警告信息。这意味着,即使代码中存在可能会触发警告的条件,这些警告也不会被打印到控制台或日志文件中。

2、探索性数据分析(EDA)

1、不同type类型对应target的柱状图

train = pd.read_csv('train.csv')

test = pd.read_csv('test.csv')

type_target_df = train.groupby('type')['target'].mean().reset_index()

plt.figure(figsize=(8, 4)) # 设置图形的大小为8x4英寸。

plt.bar(type_target_df['type'], type_target_df['target'], color=['blue', 'green'])

plt.xlabel('Type') # X轴标签

plt.ylabel('Average Target Value') # Y轴标签

plt.title('Bar Chart of Target by Type') # 图形标题

plt.show() # 显示图形

 2、id为00037f39cf的按dt为序列关于target的折线图

<code>plt.figure(figsize=(10, 5))

# 使用plot函数绘制折线图。specific_id_df['dt']作为x轴的数据,specific_id_df['target']作为y轴的数据。marker='o'表示在数据点上添加圆圈标记,linestyle='-'表示使用实线连接数据点。code>

plt.plot(specific_id_df['dt'], specific_id_df['target'], marker='o', linestyle='-')code>

plt.xlabel('DateTime')

plt.ylabel('Target Value')

plt.title("Line Chart of Target for ID '00037f39cf'")

plt.show()

 3、特征工程

这里主要构建了 历史平移特征 窗口统计特征

历史平移特征

历史平移特征是一种在数据分析和机器学习中常用的特征提取方法,特别是在处理时间序列数据时。这种方法的基本思想是将过去某个时间点的数据值作为当前时间点的特征。具体来说,对于单位d时刻的数据,直接将d-1时刻(或其他历史时间点)的值作为特征加入到数据集中。

特点与应用

简单直观:历史平移特征直接利用了历史数据,无需复杂的计算或转换。反映趋势:通过平移特征,可以捕捉到数据随时间变化的趋势,如增长、下降或波动。广泛应用:在销售预测、股票价格预测、交通流量预测等多个领域都有应用。

窗口统计特征

窗口统计特征是通过在时间序列数据上滑动一个固定大小的窗口,并计算窗口内数据的统计量来提取的特征。这些统计量可以包括最大值、最小值、均值、中位数、方差等。

特点与应用

反映区间状况:窗口统计特征能够反映区间内数据的整体状况,如波动范围、平均水平等。灵活性强:窗口大小可以根据需要进行调整,以适应不同的数据特性和分析需求。鲁棒性:通过计算窗口内的统计量,可以在一定程度上减少噪声和异常值的影响。

1、合并训练数据和测试数据,并进行排序

<code>data = pd.concat([test, train], axis=0, ignore_index=True)

data = data.sort_values(['id', 'dt'], ascending=False).reset_index(drop=True)

pd.concat([test, train], axis=0, ignore_index=True): 这行代码将测试集(test)和训练集(train)沿着行方向(axis=0)合并成一个新的DataFrame dataignore_index=True参数确保新的DataFrame的索引是从0开始重新排序的。data.sort_values(['id','dt'], ascending=False).reset_index(drop=True): 这行代码根据'id''dt'列对data进行降序排序。排序后,使用reset_index(drop=True)重置索引,以确保索引的连续性。

2、历史平移

for i in range(10, 30):

data[f'last{i}_target'] = data.groupby(['id'])['target'].shift(i)

这段代码遍历从10到29的整数,为每个整数i创建一个新列f'last{i}_target'。这些新列是通过groupby(['id'])'target'列进行分组,并使用shift(i)函数将每个'id'组的'target'值向下移动i个位置得到的。这实际上是在创建历史特征,即每个时间点的'target'值之前的第i个时间点的'target'值。

3、窗口统计

data[f'win3_mean_target'] = (data['last10_target'] + data['last11_target'] + data['last12_target']) / 3

这行代码计算了一个名为'win3_mean_target'的新列,该列是前三个历史平移特征('last10_target''last11_target''last12_target')的平均值。这可以视为一个窗口统计特征,其中窗口大小为3(即最近的3个历史'target'值)

4、数据切分

train = data[data.target.notnull()].reset_index(drop=True)

test = data[data.target.isnull()].reset_index(drop=True)

这两行代码将合并并排序后的data DataFrame切分回训练集(train)和测试集(test)。这是通过检查'target'列是否包含非空值来完成的。'target'列非空的行被分配给训练集,而'target'列为空的行则被分配给测试集。reset_index(drop=True)用于重置索引,确保索引的连续性。

5、确定输入特征

train_cols = [f for f in data.columns if f not in ['id', 'target']]

这行代码通过列表推导式创建一个名为train_cols的列表,其中包含除了'id''target'之外的所有列名。这些列名将被用作训练模型的输入特征。

4、模型训练与测试集预测

这里选择使用Lightgbm模型,也是通常作为数据挖掘比赛的基线模型,在不需要过程调参的情况的也能得到比较稳定的分数。

另外需要注意的训练集和验证集的构建:因为数据存在时序关系,所以需要严格按照时序进行切分,

这里选择原始给出训练数据集中dt为30之后的数据作为训练数据,之前的数据作为验证数据

这样保证了数据不存在穿越问题(不使用未来数据预测历史数据)

def time_model(lgb, train_df, test_df, cols):

# 训练集和验证集切分

trn_x, trn_y = train_df[train_df.dt>=31][cols], train_df[train_df.dt>=31]['target']

val_x, val_y = train_df[train_df.dt<=30][cols], train_df[train_df.dt<=30]['target']

# 构建模型输入数据

train_matrix = lgb.Dataset(trn_x, label=trn_y)

valid_matrix = lgb.Dataset(val_x, label=val_y)

# lightgbm参数

lgb_params = {

'boosting_type': 'gbdt',

'objective': 'regression',

'metric': 'mse',

'min_child_weight': 5,

'num_leaves': 2 ** 5,

'lambda_l2': 10,

'feature_fraction': 0.8,

'bagging_fraction': 0.8,

'bagging_freq': 4,

'learning_rate': 0.05,

'seed': 2024,

'nthread' : 16,

'verbose' : -1,

}

# 训练模型

model = lgb.train(lgb_params, train_matrix, 50000, valid_sets=[train_matrix, valid_matrix],

categorical_feature=[], verbose_eval=500, early_stopping_rounds=500)

# 验证集和测试集结果预测

val_pred = model.predict(val_x, num_iteration=model.best_iteration)

test_pred = model.predict(test_df[cols], num_iteration=model.best_iteration)

# 离线分数评估

score = mean_squared_error(val_pred, val_y)

print(score)

return val_pred, test_pred

lgb_oof, lgb_test = time_model(lgb, train, test, train_cols)

# 保存结果文件到本地

test['target'] = lgb_test

test[['id','dt','target']].to_csv('submit.csv', index=None)

 LightGBM参数:

1. 核心参数

1.1 树结构相关参数

max_depth:树的最大深度,用于控制树的复杂度,防止过拟合。通常设置为3到10之间,具体值需要根据数据集的特征数量和数据量来确定。num_leaves:叶子节点的最大数量,与max_depth相关,但提供了更直接的控制方式。较大的值可能导致过拟合,需要小心调整。min_data_in_leaf(或min_child_samples):一个叶子节点所需的最小数据量,用于控制树的分裂过程,防止过拟合。默认值为20,对于大数据集可以设置为更大的值。

1.2 训练控制参数

learning_rate:学习率,控制每次迭代中权重的更新步长。较小的值需要更多的迭代次数,但通常可以获得更稳定的模型。一般设置在0.01到0.3之间。n_estimators:迭代次数(或称为树的数量)。默认值为100,通常根据数据集的大小和特征数量在100到1000之间调整。

2. 正则化参数

lambda_l1(或reg_alpha):L1正则化项的权重,用于控制模型复杂度,防止过拟合。取值范围通常为[0, +∞),但实际应用中一般设置在较小的范围内,如0到100之间。lambda_l2(或reg_lambda):L2正则化项的权重,同样用于控制模型复杂度。与lambda_l1类似,取值范围也是[0, +∞)。

3. 采样参数

subsample:训练每棵树时使用的样本比例。小于1的值可以用于防止过拟合,通常设置在0.5到1之间。colsample_bytree:训练每棵树时使用的特征比例。小于1的值同样可以用于防止过拟合,通常也设置在0.5到1之间。

4. 其他重要参数

boosting_type:提升算法的类型,默认为'gbdt'(梯度提升决策树)。其他选项包括'rf'(随机森林)、'dart'(带有dropout的正则化梯度提升)和'goss'(基于梯度的单边采样)。objective:目标函数,根据具体任务选择,如二分类的'binary'、多分类的'multiclass'等。metric:评估指标,用于监控训练过程和选择最佳模型。对于二分类问题,常用的有'binary_logloss'、'auc'等。num_threads:用于LightGBM算法的线程数,默认为OpenMP的默认线程数。可以根据CPU的核数来设置,以加快训练速度。

参考文章:

1、‬‌​‬‬​‬⁠‌‌​​​​⁠‬​​​⁠‍​‌‬‌‌​​‍⁠‌​​​​​​‌‬从零入门机器学习竞赛 - 飞书云文档 (feishu.cn)

2、‌‬​​‍‍​​​‍‍‍​​‍‌​​​​‬​​​​​​‬⁠‌‌​‌‬‬‌‬​⁠⁠‌​​‌​Task2:入门lightgbm,开始特征工程 - 飞书云文档 (feishu.cn)



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。