【数据挖掘】将NLP技术引入到股市分析

一、说明

        在交易中实施的机器学习模型通常根据历史股票价格和其他定量数据进行训练,以预测未来的股票价格。但是,自然语言处理(NLP)使我们能够分析财务文档,例如10-k表格,以预测股票走势。

二、对自然语言处理解释

图片来源:亚当·盖特盖

        自然语言处理是人工智能的一个分支,涉及教计算机阅读语言并从语言中获取含义。由于语言是如此复杂,计算机必须经过一系列步骤才能理解文本。以下是典型 NLP 管道中出现的步骤的快速说明。

  1. 句子分割 文本文档被分割
    成单独的句子。
  2. 标记化
    一旦文档被分解成句子,我们进一步将句子分成单独的单词。每个单词称为一个标记,因此称为标记化。
  3. 词性标记
    我们将每个标记及其周围的几个单词输入到预先训练的词性分类模型中,以接收标记的词性作为输出。
  4. 词形还原
    词通常以不同的形式出现,同时指代相同的对象/动作。为了防止计算机将单词的不同形式视为不同的单词,我们执行词形还原,即将单词的各种屈折组合在一起以将它们分析为单个项目的过程,由单词的引理(单词在字典中的出现方式)标识。
  5. 停用词 诸如“and”、“the”和“a”等极其常见的单词不提供任何值,因此我们将它们标识为停用词
    ,以将其从对文本执行的任何分析中排除。
  6. 依赖关系分析 为句子分配句法结构,并通过将单词提供给依赖关系分析
    器来理解句子中的单词之间的关系。
  7. 名词短语 将句子中的名词短语
    组合在一起可以帮助简化我们不关心形容词的情况的句子。
  8. 命名实体识别
    命名实体识别模型可以标记人员姓名、
    公司名称和地理位置等对象。
  9. 共指解决
    由于 NLP 模型分析单个句子,因此它们会被代词引用其他句子中的名词所混淆。为了解决这个问题,我们采用共指解析来跟踪句子中的代词以避免混淆。

        有关 NLP 的更深入描述:请阅读此内容

        完成这些步骤后,我们的文本就可以进行分析了。现在我们更好地理解了NLP,让我们来看看我的项目代码(来自Udacity的AI交易课程的项目5)。单击此处查看完整的 Github 存储库

三、NLP的数据导入/下载

        首先,我们进行必要的进口;project_helper包含各种实用程序和图形函数。

import nltk
import numpy as np
import pandas as pd
import pickle
import pprint
import project_helperfrom tqdm import tqdm

然后我们下载用于删除停用词的停用词语料库和用于词形还原的词网语料库。

nltk.download('stopwords')
nltk.download('wordnet')

四、获取 10-ks数据

        10-K 文档包括公司历史、组织结构、高管薪酬、股权、子公司和经审计的财务报表等信息。要查找 10-k 文档,我们使用每个公司的唯一 CIK(中央索引键)。

cik_lookup = {'AMZN': '0001018724','BMY': '0000014272',   'CNP': '0001130310','CVX': '0000093410','FL': '0000850209','FRT': '0000034903','HON': '0000773840'}

        现在,我们从 SEC 中提取已提交的 10-k 列表,并以亚马逊数据为例显示。

sec_api = project_helper.SecAPI()
from bs4 import BeautifulSoup
def get_sec_data(cik, doc_type, start=0, count=60):rss_url = 'https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany' \'&CIK={}&type={}&start={}&count={}&owner=exclude&output=atom' \.format(cik, doc_type, start, count)sec_data = sec_api.get(rss_url)feed = BeautifulSoup(sec_data.encode('ascii'), 'xml').feedentries = [(entry.content.find('filing-href').getText(),entry.content.find('filing-type').getText(),entry.content.find('filing-date').getText())for entry in feed.find_all('entry', recursive=False)]
return entries
example_ticker = 'AMZN'
sec_data = {}
for ticker, cik in cik_lookup.items():sec_data[ticker] = get_sec_data(cik, '10-K')
pprint.pprint(sec_data[example_ticker][:5])

        我们收到一个 url 列表,这些网址指向包含与每个填充相关的元数据的文件。元数据与我们无关,因此我们通过用填充 URL 替换 url 来提取填充。让我们使用 tqdm 查看下载进度并查看示例文档。

raw_fillings_by_ticker = {}
for ticker, data in sec_data.items():raw_fillings_by_ticker[ticker] = {}for index_url, file_type, file_date in tqdm(data, desc='Downloading {} Fillings'.format(ticker), unit='filling'):if (file_type == '10-K'):file_url = index_url.replace('-index.htm', '.txt').replace('.txtl', '.txt')            raw_fillings_by_ticker[ticker][file_date] = sec_api.get(file_url)
print('Example Document:\n\n{}...'.format(next(iter(raw_fillings_by_ticker[example_ticker].values()))[:1000]))

        将下载的文件分解为其关联的文档,这些文档在填充物中被分割开来,标签 <DOCUMENT> 表示每个文档的开头,</DOCUMENT> 表示每个文档的结尾。

import re
def get_documents(text):extracted_docs = []doc_start_pattern = re.compile(r'<DOCUMENT>')doc_end_pattern = re.compile(r'</DOCUMENT>')   doc_start_is = [x.end() for x in      doc_start_pattern.finditer(text)]doc_end_is = [x.start() for x in doc_end_pattern.finditer(text)]for doc_start_i, doc_end_i in zip(doc_start_is, doc_end_is):extracted_docs.append(text[doc_start_i:doc_end_i])return extracted_docs
filling_documents_by_ticker = {}
for ticker, raw_fillings in raw_fillings_by_ticker.items():filling_documents_by_ticker[ticker] = {}for file_date, filling in tqdm(raw_fillings.items(), desc='Getting Documents from {} Fillings'.format(ticker), unit='filling'):filling_documents_by_ticker[ticker][file_date] = get_documents(filling)
print('\n\n'.join(['Document {} Filed on {}:\n{}...'.format(doc_i, file_date, doc[:200])for file_date, docs in filling_documents_by_ticker[example_ticker].items()for doc_i, doc in enumerate(docs)][:3]))

        定义 get_document_type 函数以返回给定的文档类型。

def get_document_type(doc):type_pattern = re.compile(r'<TYPE>[^\n]+')doc_type = type_pattern.findall(doc)[0][len('<TYPE>'):] return doc_type.lower()

        使用 get_document_type 功能从填充物中过滤掉非 10-k 文档。

ten_ks_by_ticker = {}
for ticker, filling_documents in filling_documents_by_ticker.items():ten_ks_by_ticker[ticker] = []for file_date, documents in filling_documents.items():for document in documents:if get_document_type(document) == '10-k':ten_ks_by_ticker[ticker].append({'cik': cik_lookup[ticker],'file': document,'file_date': file_date})
project_helper.print_ten_k_data(ten_ks_by_ticker[example_ticker][:5], ['cik', 'file', 'file_date'])

五、预处理数据

        删除 html 并将所有文本设置为小写以清理文档文本。

def remove_html_tags(text):text = BeautifulSoup(text, 'html.parser').get_text()return text
def clean_text(text):text = text.lower()text = remove_html_tags(text)return text

        使用clean_text功能清理文档。

for ticker, ten_ks in ten_ks_by_ticker.items():for ten_k in tqdm(ten_ks, desc='Cleaning {} 10-Ks'.format(ticker), unit='10-K'):ten_k['file_clean'] = clean_text(ten_k['file'])
project_helper.print_ten_k_data(ten_ks_by_ticker[example_ticker][:5], ['file_clean'])

        现在我们对所有数据进行词形还原。

from nltk.stem import WordNetLemmatizer
from nltk.corpus import wordnet
def lemmatize_words(words):lemmatized_words = [WordNetLemmatizer().lemmatize(word, 'v') for word in words]return lemmatized_words
word_pattern = re.compile('\w+')
for ticker, ten_ks in ten_ks_by_ticker.items():for ten_k in tqdm(ten_ks, desc='Lemmatize {} 10-Ks'.format(ticker), unit='10-K'):ten_k['file_lemma'] = lemmatize_words(word_pattern.findall(ten_k['file_clean']))
project_helper.print_ten_k_data(ten_ks_by_ticker[example_ticker][:5], ['file_lemma'])

删除停用词。

from nltk.corpus import stopwords
lemma_english_stopwords = lemmatize_words(stopwords.words('english'))
for ticker, ten_ks in ten_ks_by_ticker.items():for ten_k in tqdm(ten_ks, desc='Remove Stop Words for {} 10-Ks'.format(ticker), unit='10-K'):ten_k['file_lemma'] = [word for word in ten_k['file_lemma'] if word not in lemma_english_stopwords]
print('Stop Words Removed')

六、10-ks 的情绪分析

        使用 Loughran-McDonald 情感词列表对 10-ks 执行情感分析(这是专门为文本分析相关的财务构建的)。

sentiments = ['negative', 'positive', 'uncertainty', 'litigious', 'constraining', 'interesting']sentiment_df = pd.read_csv('loughran_mcdonald_master_dic_2018.csv')
sentiment_df.columns = [column.lower() for column in sentiment_df.columns] # Lowercase the columns for ease of use# Remove unused information
sentiment_df = sentiment_df[sentiments + ['word']]
sentiment_df[sentiments] = sentiment_df[sentiments].astype(bool)
sentiment_df = sentiment_df[(sentiment_df[sentiments]).any(1)]# Apply the same preprocessing to these words as the 10-k words
sentiment_df['word'] = lemmatize_words(sentiment_df['word'].str.lower())
sentiment_df = sentiment_df.drop_duplicates('word')sentiment_df.head()

使用情绪词列表从 10-k 文档生成单词的情绪包。单词袋计算每个文档中的情感单词数量。

from collections import defaultdict, Counter
from sklearn.feature_extraction.text import CountVectorizer
def get_bag_of_words(sentiment_words, docs):vec = CountVectorizer(vocabulary=sentiment_words)vectors = vec.fit_transform(docs)words_list = vec.get_feature_names()bag_of_words = np.zeros([len(docs), len(words_list)])for i in range(len(docs)):bag_of_words[i] = vectors[i].toarray()[0]
return bag_of_words.astype(int)
sentiment_bow_ten_ks = {}
for ticker, ten_ks in ten_ks_by_ticker.items():lemma_docs = [' '.join(ten_k['file_lemma']) for ten_k in ten_ks]sentiment_bow_ten_ks[ticker] = {sentiment: get_bag_of_words(sentiment_df[sentiment_df[sentiment]]['word'], lemma_docs)for sentiment in sentiments}
project_helper.print_ten_k_data([sentiment_bow_ten_ks[example_ticker]], sentiments)

七、杰卡德相似性

        现在我们有了词袋,我们可以将其转换为布尔数组并计算 jaccard 相似性。杰卡德相似性定义为交集的大小除以两个集合的并集大小。例如,两个句子之间的jaccard相似性是两个句子之间的常用词数除以两个句子中唯一单词总数的总和。杰卡德相似性值越接近 1,集合就越相似。为了更容易理解我们的计算,我们绘制了杰卡德的相似性。

from sklearn.metrics import jaccard_similarity_score
def get_jaccard_similarity(bag_of_words_matrix):jaccard_similarities = []bag_of_words_matrix = np.array(bag_of_words_matrix, dtype=bool)for i in range(len(bag_of_words_matrix)-1):u = bag_of_words_matrix[i]v = bag_of_words_matrix[i+1]jaccard_similarities.append(jaccard_similarity_score(u,v))    return jaccard_similarities
# Get dates for the universe
file_dates = {ticker: [ten_k['file_date'] for ten_k in ten_ks]for ticker, ten_ks in ten_ks_by_ticker.items()}
jaccard_similarities = {ticker: {sentiment_name: get_jaccard_similarity(sentiment_values)for sentiment_name, sentiment_values in ten_k_sentiments.items()}for ticker, ten_k_sentiments in sentiment_bow_ten_ks.items()}
project_helper.plot_similarities([jaccard_similarities[example_ticker][sentiment] for sentiment in sentiments],file_dates[example_ticker][1:],'Jaccard Similarities for {} Sentiment'.format(example_ticker),sentiments)

八、TFIDF

        从情绪词列表中,让我们从 10-k 文档生成情绪术语频率 – 反向文档频率 (TFIDF)。TFIDF 是一种信息检索技术,用于揭示单词/术语在所选文本集合中出现的频率。每个术语都分配有术语频率 (TF) 和反向文档频率 (IDF) 分数。这些分数的乘积称为该术语的 TFIDF 权重。TFIDF 权重越高表示术语越稀有,TFIDF 分数越低表示术语越常见。

from sklearn.feature_extraction.text import TfidfVectorizer
def get_tfidf(sentiment_words, docs):vec = TfidfVectorizer(vocabulary=sentiment_words)tfidf = vec.fit_transform(docs)return tfidf.toarray()
sentiment_tfidf_ten_ks = {}
for ticker, ten_ks in ten_ks_by_ticker.items():lemma_docs = [' '.join(ten_k['file_lemma']) for ten_k in ten_ks]sentiment_tfidf_ten_ks[ticker] = {sentiment: get_tfidf(sentiment_df[sentiment_df[sentiment]]['word'], lemma_docs)for sentiment in sentiments}
project_helper.print_ten_k_data([sentiment_tfidf_ten_ks[example_ticker]], sentiments)

九、余弦相似性

        根据我们的 TFIDF 值,我们可以计算余弦相似性并将其绘制成随时间变化的图。与 jaccard 相似性类似,余弦相似性是用于确定文档相似程度的指标。余弦相似性通过测量投影在多维空间中的两个向量之间角度的余弦来计算相似性,而不考虑大小。对于文本分析,使用的两个向量通常是包含两个文档字数的数组。

from sklearn.metrics.pairwise import cosine_similarity
def get_cosine_similarity(tfidf_matrix):cosine_similarities = []    for i in range(len(tfidf_matrix)-1):cosine_similarities.append(cosine_similarity(tfidf_matrix[i].reshape(1, -1),tfidf_matrix[i+1].reshape(1, -1))[0,0])return cosine_similarities
cosine_similarities = {ticker: {sentiment_name: get_cosine_similarity(sentiment_values)for sentiment_name, sentiment_values in ten_k_sentiments.items()}for ticker, ten_k_sentiments in sentiment_tfidf_ten_ks.items()}
project_helper.plot_similarities([cosine_similarities[example_ticker][sentiment] for sentiment in sentiments],file_dates[example_ticker][1:],'Cosine Similarities for {} Sentiment'.format(example_ticker),sentiments)

十、价格数据

        现在,我们将通过将其与股票的年度定价进行比较来评估阿尔法因素。我们可以从QuoteMedia下载定价数据。

pricing = pd.read_csv('yr-quotemedia.csv', parse_dates=['date'])
pricing = pricing.pivot(index='date', columns='ticker', values='adj_close')pricing

十一、将数据转换为数据帧

        Alphalens是一个用于alpha因素性能分析的python库,它使用数据帧,因此我们必须将字典转换为数据帧。


cosine_similarities_df_dict = {'date': [], 'ticker': [], 'sentiment': [], 'value': []}
for ticker, ten_k_sentiments in cosine_similarities.items():for sentiment_name, sentiment_values in ten_k_sentiments.items():for sentiment_values, sentiment_value in enumerate(sentiment_values):cosine_similarities_df_dict['ticker'].append(ticker)cosine_similarities_df_dict['sentiment'].append(sentiment_name)cosine_similarities_df_dict['value'].append(sentiment_value)cosine_similarities_df_dict['date'].append(file_dates[ticker][1:][sentiment_values])
cosine_similarities_df = pd.DataFrame(cosine_similarities_df_dict)
cosine_similarities_df['date'] = pd.DatetimeIndex(cosine_similarities_df['date']).year
cosine_similarities_df['date'] = pd.to_datetime(cosine_similarities_df['date'], format='%Y')
cosine_similarities_df.head()

在利用许多 alphalens 函数之前,我们需要对齐索引并将时间转换为 unix 时间戳。

import alphalens as al
factor_data = {}
skipped_sentiments = []
for sentiment in sentiments:cs_df = cosine_similarities_df[(cosine_similarities_df['sentiment'] == sentiment)]cs_df = cs_df.pivot(index='date', columns='ticker', values='value')try:data = al.utils.get_clean_factor_and_forward_returns(cs_df.stack(), pricing.loc[cs_df.index], quantiles=5, bins=None, periods=[1])factor_data[sentiment] = dataexcept:skipped_sentiments.append(sentiment)
if skipped_sentiments:print('\nSkipped the following sentiments:\n{}'.format('\n'.join(skipped_sentiments)))
factor_data[sentiments[0]].head()

        我们还必须创建具有 unix 时间的因子数据帧,以便与 alphalen 的factor_rank_autocorrelation和mean_return_by_quantile函数兼容。

unixt_factor_data = {factor: data.set_index(pd.MultiIndex.from_tuples([(x.timestamp(), y) for x, y in data.index.values],names=['date', 'asset']))for factor, data in factor_data.items()}

十二、因子回报

        让我们来看看随时间推移的因子回报

ls_factor_returns = pd.DataFrame()
for factor_name, data in factor_data.items():ls_factor_returns[factor_name] = al.performance.factor_returns(data).iloc[:, 0]
(1 + ls_factor_returns).cumprod().plot()

        正如预期的那样,表达积极情绪的 10-k 报告产生的收益最大,而包含负面情绪的 10-k 报告导致的最大损失。

十三、营业额分析

        使用因子秩自相关,我们可以分析alpha随时间推移的稳定性。我们希望阿尔法等级在不同时期保持相对相同。

ls_FRA = pd.DataFrame()
for factor, data in unixt_factor_data.items():ls_FRA[factor] = al.performance.factor_rank_autocorrelation(data)
ls_FRA.plot(title="Factor Rank Autocorrelation")

十四、夏普比率

        最后,让我们计算夏普比率,即平均回报减去无风险回报除以投资回报的标准差。

daily_annualization_factor = np.sqrt(252)  
(daily_annualization_factor * ls_factor_returns.mean() / ls_factor_returns.std()).round(2)

        夏普比率为 1 被认为是可以接受的,2 的比率非常好,3 的比率非常好。正如预期的那样,我们可以看到积极情绪与高夏普比率相关,消极情绪与低夏普比率相关。其他情绪也与高夏普比率有关。然而,由于如此多的复杂因素影响股票价格,因此在现实世界中复制这些回报要困难得多。

参考和引用

[1] Udacity, Artificial Intelligence for Trading, Github

罗尚·阿杜苏米利

·

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/6593.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【OpenCV】常见问题及解决办法

文章目录 0 前言1 中文乱码问题2 非法路径问题 0 前言 本篇博客主要是总结OpenCV使用过程中遇到的一些问题&#xff0c;以及对应的解决办法&#xff0c;这里重点是关注OpenCV&#xff0c;既有基于C的&#xff0c;也有基于Python的&#xff0c;比较全面&#xff0c;而且也会随着…

RocketMQ教程-安装和配置

Linux系统安装配置 64位操作系统&#xff0c;推荐 Linux/Unix/macOS 64位 JDK 1.8 Maven3.0 yum 安装jdk8 yum 安装maven 1.下载安装Apache RocketMQ RocketMQ 的安装包分为两种&#xff0c;二进制包和源码包。 点击这里 下载 Apache RocketMQ 5.1.3的源码包。你也可以从这…

Windows11的VS201x编译OpenCV+Contrib+CUDA

(1) CUDA下载&#xff0c;注意要和cudnn版本号相关。 我安装的是cuda11.0,注意VS2015不能编译CUDA11&#xff0c;所以用VS2015的话需要下载CUDA 10。因为更高的版本目前还没有cudnn。 (2) 下载和安装VS2015。 (3) 下载和解压CMake。 CMake地址&#xff1a; Releases Kitw…

Android dp to pix resources.getDimension(R.dimen.xxx) ,kotlin

Android dp to pix resources.getDimension(R.dimen.xxx) ,kotlin <?xml version"1.0" encoding"utf-8"?> <resources><dimen name"my_size_dp">20dp</dimen><dimen name"my_size_px">20px</dime…

数据仓库表设计理论

数据仓库表设计理论 数仓顾名思义是数据仓库&#xff0c;其数据来源大多来自于业务数据(例如:关系型数据库)&#xff0c;当设计数仓中表类型时(拉链表、增量表、全量表、流水表、切片表)时&#xff0c;应先观察业务数据的特点再设计数仓表结构 首先业务数据是会不断增长的-即…

练习——动态内存分配的笔试题

今天我们分享几道经典的笔试题&#xff0c;做完直接变成陈泽 第一题 ~~ --------------------------------------------------------------------------------------------------~~ void GetMemory(char* p) {p (char*)malloc(100); } void Test(void) {char* str NULL;Get…

阿里云容器镜像仓库(ACR)的创建和使用

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

使用spark进行hbase的bulkload

使用spark进行hbase的bulkload 一、 背景 HBase 是一个面向列&#xff0c;schemaless&#xff0c;高吞吐&#xff0c;高可靠可水平扩展的 NoSQL 数据库&#xff0c;用户可以通过 HBase client 提供的 put get 等 api 实现在数据的实时读写。在过去的几年里&#xff0c;HBase …

HTTP 请求走私漏洞(HTTP Request Smuggling)

一、什么是Http 请求走私漏洞&#xff1f; HTTP请求走私漏洞&#xff08;HTTP Request Smuggling&#xff09;是一种安全漏洞&#xff0c;利用了HTTP协议中请求和响应的解析和处理方式的不一致性。攻击者通过构造特定的恶意请求&#xff0c;以欺骗服务器和代理服务器&#xff0…

Godot 4 源码分析 - 增加管道通信

学习研究Godot 4&#xff0c;很爽&#xff0c;虽然很庞杂&#xff0c;但相对于自己的水平来说&#xff0c;很强大&#xff0c;尤其是vulkan这块直接打包可用&#xff0c;省得自己从头琢磨。 一点一点地消化、优化与完善&#xff0c;最终才能成为自己的。 这段时间就在Godot的…

Pytorch迁移学习使用Resnet50进行模型训练预测猫狗二分类

目录 1.ResNet残差网络 1.1 ResNet定义 1.2 ResNet 几种网络配置 1.3 ResNet50网络结构 1.3.1 前几层卷积和池化 1.3.2 残差块&#xff1a;构建深度残差网络 1.3.3 ResNet主体&#xff1a;堆叠多个残差块 1.4 迁移学习猫狗二分类实战 1.4.1 迁移学习 1.4.2 模型训练 1.…

华为数通HCIP-ISIS基础

IS-IS的基本概念 isis&#xff08;中间系统到中间路由协议&#xff09; 链路状态路由协议、IGP、无类路由协议&#xff1b; IS-IS是一种链路状态路由协议&#xff0c;IS-IS与OSPF在许多方面非常相似:运行IS-IS协议的直连设备之间通过发送Hello报文发现彼此&#xff0c;然后建…

从零开始搭建vue3 + ts + pinia + vite +element-plus项目

前言&#xff1a;据说vue2将于 2023 年 12 月 31 日停止维护&#xff0c;最近打算搭建一个vue3项目来学习一下&#xff0c;以防忘记&#xff0c;记录一下搭建过程。 一、使用npm创建项目 前提条件&#xff1a;已安装 16.0 或更高版本的 Node.js 执行 “npm init vuelatest”…

【Java基础教程】(四十三)多线程篇 · 下:深入剖析Java多线程编程:同步、死锁及经典案例——生产者与消费者,探究sleep()与wait()的差异

Java基础教程之多线程 下 &#x1f539;本节学习目标1️⃣ 线程的同步与死锁1.1 同步问题的引出2.2 synchronized 同步操作2.3 死锁 2️⃣ 多线程经典案例——生产者与消费者&#x1f50d;分析sleep()和wait()的区别&#xff1f; &#x1f33e; 总结 &#x1f539;本节学习目标…

谷歌插件(Chrome扩展) “Service Worker (无效)” 解决方法

问题描述&#xff1a; 写 background 文件的时候报错了&#xff0c;说 Service Worker 设置的 background 无效。 解决&#xff08;检查&#xff09;方法&#xff1a; 检查配置文件&#xff08;manifest.json&#xff09; 中的 manifest_version 是否为 3。 background 中的…

如何动态修改 spring aop 切面信息?让自动日志输出框架更好用

业务背景 很久以前开源了一款 auto-log 自动日志打印框架。 其中对于 spring 项目&#xff0c;默认实现了基于 aop 切面的日志输出。 但是发现一个问题&#xff0c;如果切面定义为全切范围过大&#xff0c;于是 v0.2 版本就是基于注解 AutoLog 实现的。 只有指定注解的类或…

DataWhale AI夏令营——机器学习

DataWhale AI夏令营——机器学习 学习记录一1. 异常值分析2. 单变量箱线图可视化3. 特征重要性分析 学习记录一 锂电池电池生产参数调控及生产温度预测挑战赛 已配置环境&#xff0c;跑通baseline&#xff0c;并在此基础上对数据进行了简单的分析。 1. 异常值分析 对训练集…

K8S初级入门系列之八-网络

一、前言 本章节我们将了解K8S的相关网络概念&#xff0c;包括K8S的网络通讯原理&#xff0c;以及Service以及相关的概念&#xff0c;包括Endpoint&#xff0c;EndpointSlice&#xff0c;Headless service&#xff0c;Ingress等。 二、网络通讯原理和实现 同一K8S集群&…

PMP 数据收集工具与技术

数据收集工具与技术 (9个) 标杆对照 标杆对照是指将实际或计划的产品、流程和实践与其他可比组织的 做法进行比较&#xff0c;以便识别最佳实践、形成改进意见&#xff0c;并为绩效考核 提供依据。 头脑风暴 头脑风暴是一种数据收集和创意技术&#xff0c;主要用于在短时间…

三维点云中的坐标变换(只讲关键部分)

一、坐标旋转 坐标旋转包含绕x、y、z轴旋转&#xff0c;在右手坐标系中&#xff0c;x-翻滚(roll)&#xff0c;y-俯仰(pitch)&#xff0c;z-航向(yaw)。如果想详细了解&#xff0c;可以网络搜索 在PCL中&#xff0c;从baseLink到map的转换关系为:先绕x轴旋转,在绕y轴旋转,最后绕…