初学者数据分析——Python职位全链路分析

news2024/11/26 16:55:39

最近在做Python职位分析的项目,做这件事的背景是因为接触Python这么久,还没有对Python职位有一个全貌的了解。所以想通过本次分析了解Python相关的职位有哪些、在不同城市的需求量有何差异、薪资怎么样以及对工作经验有什么要求等等。分析的链路包括:

  • 数据采集

  • 数据清洗

  1. 异常的创建时间
  2. 异常的薪资水平
  3. 异常的工作经验
  • 统计分析
  1. 大盘数据
  2. 单维度分析
  3. 二维交叉分析
  4. 多维钻取
  • 文本分析
  1. 文本预处理
  2. 词云
  3. FP-Growth关联分析
  4. LDA主题模型分析

分为上下两篇文章。上篇介绍前三部分内容,下篇重点介绍文本分析。

0. 数据采集

巧妇难为无米之炊,我们做数据分析大部分情况是用公司的业务数据,因此就不需要关心数据采集的问题。然而我们自己业余时间做的一些数据探索更多的需要自己采集数据,常用的数据采集技术就是爬虫

本次分享所用的数据是我从拉勾网爬取的,主要分为三部分,确定如何抓取数据、编写爬虫抓取数据、将抓取的数据格式化并保存至MongoDB。关于数据采集这部分内容我之前有一篇文章单独介绍过,源码也开放了,这里我就不再赘述了,想了解的朋友可以翻看之前那篇文章《Python爬职位》。

1. 数据清洗

有了数据后,先不要着急分析。我们需要对数据先有个大概的了解,并在这个过程中剔除一些异常的记录,防止它们影响后续的统计结果。

举个例子,假设有101个职位,其中100个的薪资是正常值10k,而另外一个薪资是异常值1000k,如果算上异常值计算的平均薪资是29.7k,而剔除异常值计算的平均薪资是10k,二者差了将近3倍。

所以我们在作分析前要关注数据质量,尤其数据量比较少的情况。本次分析的职位数有1w条左右,属于比较小的数据量,所以在数据清洗这一步花了比较多的时间。

下面我们就从数据清洗开始,进入编码阶段

1.0 筛选python相关的职位

导入常用库

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pymongo import MongoClient

from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei']  #解决seaborn中文字体显示问题
%matplotlib inline
复制代码

MongoDB读取数据

mongoConn = MongoClient(host='192.168.29.132', port=27017)
db = mongoConn.get_database('lagou')
mon_data = db.py_positions.find()
# json转DataFrame
jobs = pd.json_normalize([record for record in mon_data])
复制代码

预览数据

jobs.head(4)
复制代码

打印出jobs的行列信息

jobs.info()
复制代码

一共读取了1.9w个岗位,但这些岗位里并不都是跟Python相关的。所以我们首先要做的就是筛选Python相关的职位,采用的规则是职位标题或正文包含python字符串

# 抽取职位名称或者职位正文里包含 python 的
py_jobs = jobs[(jobs['pName'].str.lower().str.contains("python")) | (jobs['pDetail'].str.lower().str.contains("python"))]

py_jobs.info()
复制代码

筛选后,只剩下10705个岗位,我们继续对这部分岗位进行清洗。

1.1 按照创建时间清洗异常值

对 “职位创建时间” 维度清洗主要是为了防止有些创建时间特别离谱的岗位混进来,比如:出现了2000年招聘的岗位。

# 创建一个函数将职位创建时间戳转为月份
import time
def timestamp_to_date(ts):
    ts = ts / 1000
    time_local = time.localtime(ts)
    return time.strftime("%Y-%m", time_local)
    
# 增加'职位创建月份'一列
py_jobs['createMon'] = py_jobs['createTime'].map(timestamp_to_date)

# 按照职位id、创建月份分组计数
py_jobs[['pId', 'createMon']].groupby('createMon').count()
复制代码

不同月的职位

创建timestamp_to_date 函数将“职位创建时间”转为“职位创建月份”,然后按“职位创建月份”分组计数。从结果上看,职位创建的时间没有特别离谱的,也就是说没有异常值。即便如此,我仍然对职位创建时间进行了筛选,只保留了10、11、12三个月的数据,因为这三个月的职位占了大头,并且我只想关注新职位。

# 只看近三个月的职位
py_jobs_mon = py_jobs[py_jobs['createMon'] > '2020-09']
复制代码

1.2 按照薪资清洗异常值

对薪资进行清洗主要是防止某些职位的薪资特别离谱。这块主要考察3个特征:薪资高的离群点、薪资低的离群点和薪资跨度较大的。

首先,列出所有的薪资

py_jobs_mon[['pId', 'salary']].groupby('salary').count().index.values
复制代码

以薪资高的离群点为例,观察是否有异常值

# 薪资高的离群值
py_jobs_mon[py_jobs_mon['salary'].isin(['150k-200k', '100k-150k'])]
复制代码

薪资高的异常值

果然发现了一个异常岗位,一个应届实习生居然给150k-200k,很明显需要将其清洗掉。

同样地,我们也能发现其他特征的异常职位

1.3 小节要介绍的按照工作经验清洗异常值也与之类似,为了避免篇幅过长我这里就不贴代码了。总之,按照这3个属性清洗完之后,还剩 9715 个职位。

完成数据清洗后,我们就正式进入分析的环节了,分析分为两部分,统计分析和文本分析,前者是对数值型指标做统计,后者是对文本进行分析。我们平时接触到最多是前者,它可以让我们从宏观的角度去了解被分析的对象。文本分析也有不可替代的价值,我们下篇重点介绍。

2. 统计分析

我们做统计分析除了要清楚分析的目外,还需要了解分析结果面向的对象是谁。本次分析中,我假想面向的是在校学生,因为他们是真正想要了解Python职位的人。因此,我们的分析思路就要按照他们所想看的去展开,而不能没有章法的乱堆数据。

2.0 大盘数据

统计分析的数据一般都是按照数据粒度由粗到细展开的,粒度最粗的数据就是不加任何过滤条件、不按照任何维度拆分的数字。在我们的项目里其实就是总职位数,上面我们也看到了 9715 个。如果跟Java、PHP职位去对比,或许我们能得出一些结论,然而单纯看这个总数显然是没有实际参考价值的。

所以接下来我们需要按照维度来进行细粒度的拆分。

2.1 单维度分析

我们由粗到细,先来按照单维度进行分析。对于一个在校生来说,他最迫切想了解的数据是什么?我觉得是不同城市之间职位数量的分布。因为对于学生来说考虑工作的首要问题是考虑在哪个城市,考虑哪个城市需要参考的一点就是职位的数量,职位越多,前景自然更好。

# 城市
fig = plt.figure(dpi=85)
py_jobs_final['city'].value_counts(ascending=True).plot.barh()
复制代码

分城市的职位数量

北京的岗位是最多的,比第二名上海还要高出一倍。广州的岗位最少,少于深圳。

确定了在哪个城市发展后,再进一步需要考虑的就是从事什么岗位。我们都知道Python的应用面很广,自然就想看看不同类别的Python职位的分布

# 按照p1stCat(一级分类)、p2ndCat(二级分类)分组计数
tmp_df = py_jobs_final.groupby(['p1stCat', 'p2ndCat']).count()[['_id']].sort_values(by='_id')
tmp_df = tmp_df.rename(columns={'_id':'job_num'})
tmp_df = tmp_df[tmp_df['job_num'] > 10]

tmp_df.plot.barh(figsize=(12,8), fontsize=12)
复制代码

p1stCatp2ndCat是拉勾的标记,并不是我打的标。

数据上我们发现,需要Python技能的职位里,测试是最多的,数据开发排第二,后端开发比较少,这也符合我们的认知。

这里我们看的指标是职位数量,当然你也可以看平均薪资。

从城市、职位分类这俩维度,我们对Python职位有了一个大概的认知了。那其他的维度还需要看吗,比如:薪资、工作经验,并且这俩维度也是大家比较关心的。我认为,从单维度来看,城市和职位分类就够了,其他都没有实际参考价值。因为薪资一定是跟某一类岗位相关的,人工智能职位工资自然偏高;同样地,工作经验也是跟岗位类别相关,大数据刚起步的时候,职位的工作经验自然就偏低。所以这俩维度从单维度上看没有参考价值,一定是需要限定了某类职位后去看才有意义。我们在做统计分析时不要乱堆数据,要想清楚数据背后的逻辑,以及对决策人是否有价值。

2.1 二维交叉分析

对于一个学生来说,当他确定了自己工作的城市,也了解了不同的职位分布,接下来我们需要给他展示什么样的数据能为他提供择业的决策呢?

对于想去北京发展的学生来说,他想了解北京的不同类型的职位分布、薪资情况、工作经验的要求、什么样的公司在招聘。同样的,想去上海、深圳、广州的同学也有类似的需求。这样,我们就确定了我们需要分析的维度和指标了,维度是城市、职位类别,且需要二者交叉。指标是职位数量、平均薪资、工作经验和公司,前三个好说,但第四个需要找一个量化指标去刻画,这里我选的是公司规模。

维度已经有了,我们要做需要是准备指标,比如:在我们的数据集里,薪资(salary)这一列是15k-20k这样的文本,我们需要处理成数值类型。以薪资为例,编写函数将其转为数字

# 薪资转为数字
def get_salary_number(salary):
    salary = salary.lower().replace('k', '')
    salary_lu = salary.split('-')
    lower = int(salary_lu[0])
    if len(salary_lu) == 1:
        return lower
    upper = int(salary_lu[1])
    
    return (lower + upper) / 2
复制代码

工作经验和公司规模也用类似逻辑处理,为了节省篇幅我就补贴代码了。

# 将3个文本列转为数字
py_jobs_final['salary_no'] = py_jobs_final['salary'].map(get_salary_number)
py_jobs_final['work_year_no'] = py_jobs_final['workYear'].map(get_work_year_number)
py_jobs_final['csize_no'] = py_jobs_final['cSize'].map(get_csize_number)
复制代码

有了维度和指标,我们如何展示数据呢?我们平时展示的数据大部分是二维的,横坐标是维度,纵坐标是指标。既然要展示二维交叉的指标,自然就要用3维图形展示。这里我们使用Axes3D来绘制

# 只选择 开发|测试|运维类 一级分类下,测试、数据开发、人工智能、运维、后端开发 二级分类
job_arr = ['测试', '数据开发', '人工智能', '运维', '后端开发']
py_jobs_2ndcat = py_jobs_final[(py_jobs_final['p1stCat'] == '开发|测试|运维类') & (py_jobs_final['p2ndCat'].isin(job_arr))]

%matplotlib notebook

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D  
# 画3d柱状图
city_map = {'北京': 0, '上海': 1, '广州': 2, '深圳': 3} # 将城市转为数字,在坐标轴上显示
idx_map = {'pId': '职位数', 'salary_no': '薪资(单位:k)', 'work_year_no': '工作经验(单位:年)', 'csize_no': '公司规模(单位:人)'}

fig = plt.figure()
for i,col in enumerate(idx_map.keys()):
    if col == 'pId':
        aggfunc = 'count'
    else:
        aggfunc = 'mean'
    jobs_pivot = py_jobs_2ndcat.pivot_table(index='p2ndCat', columns='city', values=col, aggfunc=aggfunc)
    
    ax = fig.add_subplot(2, 2, i+1, projection='3d')
    for c, city in zip(['r', 'g', 'b', 'y'], city_map.keys()):
        ys = [jobs_pivot[city][job_name] for job_name in job_arr]
        cs = [c] * len(job_arr)
        
        ax.bar(job_arr, ys, zs=city_map[city], zdir='y', color=cs)
    
    ax.set_ylabel('城市')
    ax.set_zlabel(idx_map[col])
    ax.legend(city_map.keys())

plt.show()
复制代码

首先我只选了top5的职位类别,然后循环计算每个指标,计算指标使用DataFrame中的透视图(pivot_table),它很容易将二维的指标聚合出来,并且得到我们想要的数据,最后将维度和指标展示在3d柱状图中。

以北京为例,可以看到,人工智能职位的薪资最高,数据开发和后端开发差不多,测试和运维偏低的。人工智能对工作经验的要求普遍比其他岗位低,毕竟是新兴的岗位,这也符合我们的认知。招聘人工智能职位的公司平均规模比其他岗位小,说明新兴起的AI创业公司比较多,而测试和数据开发公司规模就大一些,毕竟小公司几乎不用测试,小公司也没有那么大体量的数据。

有一点需要提醒大家一下,除了职位数外,其他指标绝对值是有偏的,这是因为我们处理逻辑的原因。但不同职位使用的处理方式是相同的,所以不同职位之间指标是可比的,也就是说绝对值没有意义,但不同职位的偏序关系是有意义的。

2.3 多维钻取

当一个学生确定了城市、确定了岗位后,他还想了解的什么呢?比如他可能想了解在北京、人工智能岗位、在不同行业里薪资、工作经验要求、公司规模怎么样,或者北京、人工智能岗位、在不同规模的公司里薪资、工作经验要求怎么样。

这就涉及三个维度的交叉。理论上我们可以按照任何维度进行交叉分析,但维度越多我们视野就越小,关注的点就越聚焦。这种情况下,我们往往会固定某几个维度取值,去分析另外几个维度的情况。

以北京为例,我们看看不同岗位、不同工作经验要求下的薪资分布

tmp_df = py_jobs_2ndcat[(py_jobs_2ndcat['city'] == '北京')]
tmp_df = tmp_df.pivot_table(index='workYear', columns='p2ndCat', values='salary_no', aggfunc='mean').sort_values(by='人工智能')
tmp_df
复制代码

为了更直观的看数据,我们画一个二维散点图,点的大小代码薪资的多少的

[plt.scatter(job_name, wy, c='darkred', s=tmp_df[job_name][wy]*5) for wy in tmp_df.index.values for job_name in job_arr]
复制代码

这个数据我们既可以横向对比,也可以纵向对比。横向对比,我们可以看到,同样的工作经验,人工智能的薪资水平普遍比其他岗位要高;纵向对比,我们可以看到,人工智能岗位的薪资随着工作年限的增加薪资增幅比其他岗位要高很多(圆圈变得比其他更大)。

所以,入什么行很重要。

当然,你如果觉得不够聚焦,还可以继续钻取。比如,想看北京、人工智能岗位、电商行业、不同公司规模的薪资情况,处理逻辑上面讲的是一样。

我们继续介绍如何用文本挖掘的方式对Python职位进行分析。会包含一些数据挖掘算法,但我希望这篇文章面向的是算法小白,里面不会涉及算法原理,会用,能解决业务问题即可。

3.0 文本预处理

文本预处理的目的跟上篇介绍的数据清洗一样,都是为了将数据处理成我们需要的,这一步主要包含分词、去除停用词两步。

我们基于上篇处理好的py_jobs_finalDataFrame进行后续的处理,先来看下职位正文

py_jobs_final[['pId', 'pDetail']].head(2)
复制代码

职位正文是pDetail列,内容就是我们经常看到的“岗位职责”和“岗位要求”。上图我们发现职位要求里包含了html标签,如:<br>,这是因为pDetail本来是需要显示在网页上的,所以里面会有html标签,还好我们有爬虫的基础,使用BeautifulSoup模块就很容易处理掉了

from bs4 import BeautifulSoup# 使用BeautifulSoup 去掉html标签, 只保留正文内容,并转小写py_jobs_final['p_text'] = py_jobs_final['pDetail'].map(lambda x: BeautifulSoup(x, 'lxml').get_text().lower())py_jobs_final[['pId', 'pDetail', 'p_text']].head(2)
复制代码

去除html标签后,再用jieba模块对正文分词。jieba提供了三种模式进行分词,全模式、精确模式和搜索引擎模式。具体差异我们看一个例子就明白了。

import jieba
job_req = '熟悉面向对象编程,掌握java/c++/python/php中的至少一门语言;'

# 全模式
seg_list = jieba.cut(job_req, cut_all=True)
# 精确模式
seg_list = jieba.cut(job_req, cut_all=False)
# 搜索引擎模式
seg_list = jieba.cut_for_search(job_req)
复制代码

全模式

精确模式

搜索引擎模式

区别一目了然,对于本次分析,我采用的是精确模式。

py_jobs_final['p_text_cut'] = py_jobs_final['p_text'].map(lambda x: list(jieba.cut(x, cut_all=False)))

py_jobs_final[['pId', 'p_text', 'p_text_cut']].head()
复制代码

分词后,我们发现里面包含很多标点符号和和一些没有意义的虚词,这些对我们的分析没有帮助,所以接下来我们要做的就是去除停用词。

# stop_words.txt里包含1208个停用词
stop_words = [line.strip() for line in open('stop_words.txt',encoding='UTF-8').readlines()]

# 添加换行符
stop_words.append('\n')

# 去停用词
def remove_stop_word(p_text):
    if not p_text:
        return p_text
    
    new_p_txt = []
    for word in p_text:
        if word not in stop_words:
            new_p_txt.append(word)
    
    return new_p_txt

py_jobs_final['p_text_clean'] = py_jobs_final['p_text_cut'].map(remove_stop_word)
py_jobs_final[['pId', 'p_text_cut', 'p_text_clean']].head()
复制代码

经过上述三个步骤的处理,p_text_clean列已比较干净且可以用于后续分析。

3.1 FP-Growth挖掘关联关系

做的第一个文本分析就是挖掘关联关系,提到关联分析大家都能想到的例子就是“啤酒和尿布”,这里我也想借助这个思路,挖掘一下不同的Python职位,哪些词具有比较强的相关性。挖掘算法使用mlxtend模块的FP-GrowthFP-Growth实现关联规则的挖掘比Apriori更快。

from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import fpgrowth

# 构造fp-growth需要的输入数据
def get_fpgrowth_input_df(dataset):
    te = TransactionEncoder()
    te_ary = te.fit(dataset).transform(dataset)
    return pd.DataFrame(te_ary, columns=te.columns_)
复制代码

我们先来挖掘“人工智能”类别

ai_jobs = py_jobs_final[(py_jobs_final['p1stCat'] == '开发|测试|运维类') & (py_jobs_final['p2ndCat'] == '人工智能')]

ai_fpg_in_df = get_fpgrowth_input_df(ai_jobs['p_text_clean'].values)

ai_fpg_df = fpgrowth(ai_fpg_in_df, min_support=0.6, use_colnames=True)
复制代码

min_support参数是用来设置最小支持度,也保留频率大于该值的频繁项集。比如,在100份购物订单里,包含“啤酒”的订单有70个,“尿布”的订单75个,“苹果”的订单1个,在min_support=0.6的情况下,“啤酒”和“尿布”会留下,“苹果”就会丢掉,因为1/100 < 0.6

看下ai_fpg_df的结果

我这里只截取了一部分, itemsets列就是频繁项集,frozenset类型,它包含1个或多个元素。support是频繁项集出现的频率,这里都是大于0.6的。第0行(python)代表99.6%的职位里出现了python这个词,第16行代表93.8%的职位里python算法同时出现。

有了这些我们就可以根据贝叶斯公式计算相关性了,比如:我看到有c++,那么我就想看看出现python的职位里有多大的概率还要求会c++,根据条件概率公式p(c++|python) = p(c++,python) / p(python)进行以下计算

# python概率
p_python = ai_fpg_df[ai_fpg_df['itemsets'] == frozenset(['python'])]['support'].values[0]

# c++ 和 python 联合概率
p_python_cpp = ai_fpg_df[ai_fpg_df['itemsets'] == frozenset(['python', 'c++'])]['support'].values[0]

# 出现python的条件下,出现c++的概率
print('p(c++|python) = %f' % (p_python_cpp / p_python))
复制代码

结果是64%。也就是人工智能职位里要求使用python的职位,有64%的概率还需要用c++。同理我们还可以看python跟其他词的关联关系

python算法关联度94%,这是符合预期的,毕竟筛选的是人工智能岗位。出现python的职位里,出现机器学习深度学习的概率差不多,都是 69%,出现机器学习的概率稍微高一些,将近70%,看来这两岗位的需求没有差的特别多。还有就是对经验的要求看起来是挺硬性的,85%的概率会出现。

同样的,我们看看数据开发岗位的关联分析

明显看到的一个区别是,人工智能的分类里与python关联度高的偏技术类,机器学习深度学习以及c++。而数据开发里的词明显更偏业务,比如这里的业务分析。也就说如果一个职位提到了python那么有60%以上的概率会提到业务或者分析,毕竟做数据要紧贴业务。

关联规则更多的是词的粒度,有点太细了。接下来我们就将粒度上升的文档的分析。

3.2 主题模型分析

LDA(Latent Dirichlet Allocation)是一种文档主体生成模型。该模型假设文档的主题服从Dirichlet分布,某个主题里的词也服从Dirichlet分布,经过各种优化算法来解出这两个隐含的分布。

这里我们调用sklearn里面的LDA算法来完成

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation

def run_lda(corpus, k):
    cntvec = CountVectorizer(min_df=1, token_pattern='\w+')
    cnttf = cntvec.fit_transform(corpus)
    
    lda = LatentDirichletAllocation(n_components=k)
    docres = lda.fit_transform(cnttf)
    
    return cntvec, cnttf, docres, lda
复制代码

这里我们用CountVectorizer统计词频的方式生成词向量,作为LDA的输入。你也可以用深度学习的方式生成词向量,好处是可以学到词语词之间的关系。

LDA设置的参数只有一个n_components,也就是需要将职位分为多少个主题。

我们先来对人工智能职位分类,分为8个主题

cntvec, cnttf, docres, lda = run_lda(ai_jobs['p_corp'].values, 8)
复制代码

调用lda.components_返回的是一个二维数组,每行代表一个主题,每一行的数组代表该主题下词的分布。我们需要再定义一个函数,将每个主题出现概率最高的几个词输出出来

def get_topic_word(topics, words, topK=10):
    res = []
    
    for topic in topics:
        sorted_arr = np.argsort(-topic)[:topK]  # 逆序排取topK
        res.append(','.join(['%s:%.2f'% (words[i], topic[i]) for i in sorted_arr]))
        
    return '\n\n'.join(res)
复制代码

输出人工智能主题下,各个主题以及top词分布

print(get_topic_word(lda.components_ / lda.components_.sum(axis=1)[:, np.newaxis], cntvec.get_feature_names(), 20))
复制代码

lda.components_ / lda.components_.sum(axis=1)[:, np.newaxis]的目的是为了归一化。

可以看到第一个主题是自然语言相关的,第二个主题是语音相关的,第三个主题是金融量化投资,第四个主题是医疗相关的,第五个主题是机器学习算法相关,第六个主题是英文职位,第七个主题是计算机视觉,第八个主题是仿真、机器人相关。

感觉分的还可以, 起码一些大的方向都能分出来。并且每个类之前也有明显区分度。

同样的,我们看看数据开发职位的主题,这里分了6个主题

第一个主题是数仓、大数据技术相关,第二个主题是英文职位,第三个主题是数据库、云相关,第四个主题是算法相关,第五个主题是业务、分析相关,第六个主题是爬虫,也还行。

这里我比较感兴趣的人工智能数据开发的职位,之前我们关注的测试后端开发也可以做,思路是一样的。

至此,我们的文本分析就结束了,可以看到文本分析能够挖掘出统计分析里统计不到的信息,后续的分析中我们会经常用。

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

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

相关文章

用了那么久的Vue,你了解Vue的报错机制吗?

Vue的5种处理Vue异常的方法 相信大家对Vue都不陌生。在使用Vue的时候也会遇到报错&#xff0c;也会使用浏览器的F12 来查看报错信息。但是你知道Vue是如何进行异常抛出的吗&#xff1f;vue 是如何处理异常的呢&#xff1f;接下来和大家介绍介绍&#xff0c;Vue是如何处理这几种…

【数据结构】树以及二叉树的概念

作者&#xff1a;一个喜欢猫咪的的程序员 专栏&#xff1a;《数据结构》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 树的概念&#xff1a; 树的相关概念&#xff1a; 树如何表示&#xff…

Anaconda中Python虚拟环境的创建、使用与删除

本文介绍在Anaconda环境下&#xff0c;创建、使用与删除Python虚拟环境的方法。 在Python的使用过程中&#xff0c;我们常常由于不同Python版本以及不同第三方库版本的支持情况与相互之间的冲突情况&#xff0c;而需要创建不同的Python虚拟环境&#xff1b;在Anaconda的帮助下&…

如何使用Python构建Telegram机器人来生成随机引语

使用Python构建Telegram机器人以生成随机引语 聊天机器人是用于进行在线聊天对话的软件应用程序&#xff0c;通过文本或文本转语音的方式实现客户服务的自动化。[聊天机器人]可以用于提醒、预约等事情&#xff0c;也可以在社交媒体平台上使用。 在本教程中&#xff0c;我们将…

会自动化就能拿20K?不,你这顶多算会点皮毛···

前段时间公司要招2个自动化测试&#xff0c;同事面了几十个候选人&#xff0c;发现了一个很奇怪的现象&#xff0c;面试的时候&#xff0c;如果问的是框架api、脚本编写这些问题&#xff0c;基本上个个都能对答如流&#xff0c;等问到实际项目的时候&#xff0c;类似“怎么从0开…

如何实现一个基于WebRTC的音视频通信系统

文章有点长&#xff0c;推荐先收藏前言 目前市场上音视频技术方案大致分为以下几类&#xff0c;WebRTC因其超低延时、集成音视频采集传输等优点&#xff0c;是在线教育、远程会议等领域首选技术。 前言 目前市场上音视频技术方案大致分为以下几类&#xff0c;WebRTC因其超低延…

10年网安经验分享:一般人别瞎入网络安全行业

小白入门网络安全&#xff0c;如何选择方向&#xff1f; 如果你是一个新手小白&#xff0c;那么在最开始方向选择上面这一步是至关重要的&#xff0c;一旦你选错了那很可能就要和安全“saygoodbye”了。 很多小白刚开始的时候还没开始学会走就想着飞了&#xff0c;计算机功底…

四六级口语|考研复试口语|满满干货

目录 1.Which do you prefer to use, credit cards or cash?/Do you prefer the credit card or cash? 2.When you shop, do you prefer to go by yourself or with someone?

指针进阶(3)--玩转指针

指针进阶 内容不多&#xff0c;但面面俱到&#xff0c;都是精华 1.回调函数&#xff1a; 2.详解qsort函数参数&#xff1a; 回调函数就是&#xff0c;把一个函数的地址&#xff0c;放在函数指针中&#xff0c;然后将该指针作为一个参数&#xff0c;传到 另一个函数中&#x…

04.南瓜树低代码平台平台 分析后的感想

随着企业产品的不断完善&#xff0c;后续将有时间来推进产品转向低代码平台化。 低代码平台不是无代码平台&#xff0c;采用配置的方式完成UI/流程/报表的处理&#xff0c;有业务人员在完成基本的产品框架后&#xff0c;由研发人员完成业务规则代码固化&#xff0c;最终达到产…

MobSDK 封装MobSDK基础包

平台兼容性 Android Android CPU类型 iOS 适用版本区间&#xff1a;4.4 - 12.0 armeabi-v7a&#xff1a;支持&#xff0c;arm64-v8a&#xff1a;支持&#xff0c;x86&#xff1a;支持 原生插件通用使用流程&#xff1a; 购买插件&#xff0c;选择该插件绑定的项目。在HB…

3. 实例化Bean的三种方式

实例化Bean的三种方式 一、构造方法方式 1.1 BookDaoImpl package com.lin.dao.daoimpl;import com.lin.dao.BookDao;public class BookDaoImpl implements BookDao {public BookDaoImpl() {System.out.println("BookDao的无参构造器");}/*** 数据层实现*/public …

了解Linux 操作系统!开篇!!!

【推荐阅读】 Linux内核CPU调度域内容讲解 关于如何快速学好&#xff0c;学懂Linux内核。内含学习路线 一文了解Linux上TCP的几个内核参数调优 Linux 接口 Linux 系统是一种金字塔模型的系统&#xff0c;如下所示 应用程序发起系统调用把参数放在寄存器中(有时候放在栈中)…

Python解题 - CSDN周赛第15期 - 客栈的咖啡

本期遇上官方大放水&#xff0c;四道题里有三道都在每日一练里做过&#xff0c;再加上比赛时间不太友好&#xff0c;参与人数不多&#xff0c;问哥竟然混了个第一名&#xff0c;真是惭愧。。。就当是官方在奖励那些平时多多参加每日一练的童鞋们了。 第一题&#xff1a;求并集 …

Vue3响应式原理设计和实现

Vue3响应式原理设计和实现响应式什么是响应式手动响应式proxy代理对象响应式系统一个属性注册一个副作用函数一个属性注册多个副作用函数多个属性注册不同的副作用函数多个数据不同属性注册不同的副作用函数响应式 什么是响应式 响应式是一个过程&#xff0c;这个过程存在两个…

【MaixPy】:K210识别简例(简单二维码检测和双二维码检测)

实物图 俩二维码识别实物图 前言 这段时间接触了一下基于MaixPy的开发K210的摄像头设备,的确很有趣,运行速度很快,编程难度不大。很适合咱们视觉开发的同学们学习,以下是我玩设备的一些感悟,如有不妥之处,希望大家雅正,也希望能帮助初学者了解和学习,也可加bulidupup(…

java毕业设计——基于java+Socket+sqlserver的网络通讯系统设计与实现(毕业论文+程序源码)——网络通讯系统

基于javaSocketsqlserver的网络通讯系统设计与实现&#xff08;毕业论文程序源码&#xff09; 大家好&#xff0c;今天给大家介绍基于javaSocketsqlserver的网络通讯系统设计与实现&#xff0c;文章末尾附有本毕业设计的论文和源码下载地址哦。 文章目录&#xff1a; 基于jav…

LwIP源码分析(3):内存堆和内存池代码详解

文章目录1 内存堆1.1 mem_init1.2 mem_malloc1.3 mem_free2 内存池2.1 memp_init2.2 memp_malloc2.3 memp_free3 内存管理宏定义在嵌入式系统中&#xff0c;内存池有助于快速有效地分配内存。LwIP提供了两个灵活的方式来管理和组织内存池的大小&#xff1a;内存堆和内存池。当然…

电脑维修记录

记于2022年12月15日 今天把电脑修好了&#xff0c;总结这次经验&#xff1a; &#xff08;1&#xff09;无知者无畏&#xff0c;对任何事情都要抱有探索的精神&#xff0c;最遗憾的事情不是做错了&#xff0c;而是想做没去做 &#xff08;2&#xff09;将每次走错路的经历都…

Orcale数据表去重创建联合主键

分享一下最近遇到的一个问题&#xff0c;我们从一个数据表中将数据表中的数据同步到另一个数据库的表中&#xff0c;由于要同步的数据表中没有建主键&#xff0c;所以数据同步后发现同步的数据比原始数据表中的数据要多&#xff0c;有不少重复的数据。因此需要对数据表进行去重…