遗传进化算法进行高效特征选择

news2024/11/18 15:48:17

在构建机器学习模型时,特征选择是一个关键的预处理步骤。使用全部特征往往会导致过拟合、增加计算复杂度等问题。因此,我们需要从原始特征集中选择一个最优子集,以提高模型的泛化性能和效率。

特征选择的目标是找到一个二元掩码向量,对应每个特征的保留(1)或剔除(0)。例如,对于10个特征,这个掩码向量可能是[1,0,1,1,0,0,1,0,1,0]。我们需要通过某种优化方法,寻找一个使目标函数(如模型的贝叶斯信息准则BIC)最小化的最优掩码。

当特征数量较小时,我们可以使用暴力搜索等枚举方法。但随着特征数量的增加,搜索空间将呈指数级增长,枚举搜索将变得无法承受。这时我们需要借助启发式优化算法,例如遗传算法、模拟退火等,在有限时间内找到一个近似最优解。

本文以Kaggle房价数据集(213个特征)为例,比较了经典的序贯特征选择算法(SFS)和一种称为进化策略(CMA-ES)的启发式优化算法在特征选择任务上的表现。实验结果表明,CMA-ES相比SFS能更快地converge到更优的特征子集,从而获得更小的BIC值和更佳的模型泛化性能

GA - 遗传算法

遗传算法是一种启发式优化算法,其灵感源自达尔文的进化论和自然选择理论。在自然界中,生物个体通过基因遗传,携带有利于生存和繁衍的特征,经过漫长的自然选择过程,适者生存,不断进化。类似地,遗传算法也是通过模拟这一自然进化过程,对问题的潜在解决方案(个体)进行遗传、变异和选择,最终得到满足目标条件的最优或近似最优解。

以特征选择为例,假设我们有N个特征,需要确定一个长度为N的二进制向量[1, 0, 0, 1, 1, 1, ...]来表示选择(1)或剔除(0)每个特征,目标是找到一个使成本函数或目标函数最小化的最优特征组合。我们可以将每个这样的二进制向量看作一个"个体",每个位置上的0或1就是该个体的一个"基因"。

遗传算法基本步骤:

  1. 评估:计算每个个体的适应度(目标函数值)。

  2. 选择:根据适应度挑选出若干个体作为父代。

  3. 交叉:随机选择两个父代个体,按一定交叉方式组合它们的基因,产生新的个体(子代)。

  4. 变异:以一定的小概率改变子代个体中的某些基因值。

  5. 替换:用新产生的子代个体替换种群中适应度较低的个体。

通过不断迭代上述过程,种群中个体的平均适应度就会不断提高,最终可以得到满足要求的最优或近似最优解。

一些关键概念和组件:

  1. 个体(Individual):表示种群中的一个候选解,通常用染色体(一串数字或字符)来表示。

  2. 种群(Population):包含多个个体的集合。

  3. 适应度函数(Fitness Function):用于评估每个个体的优劣程度。

  4. 选择(Selection):根据适应度函数的结果,从当前种群中选择部分个体作为父代,用于产生下一代种群。

  5. 交叉(Crossover):将两个父代个体的染色体进行组合,产生一个或多个新的子代个体。

  6. 变异(Mutation):通过改变个体染色体上的某些位,增加种群的多样性。

  7. 最佳个体(Hall of Fame):用于保存迄今为止找到的最佳个体,防止在进化过程中被淘汰或丢失。

  8. 优秀个体(Elitism):在每一代中,直接将当前种群中的优秀个体传递到下一代,而不需要经过选择、交叉和变异等操作。

遗传算法首先随机生成一组这样的个体,构成初始种群。比如,如果N=12,种群数量为8,那么初始种群可能包含8个长度为12的随机二进制向量。

遗传算法-种群

群体创建后,通过目标函数对每个个体进行评估。

接下来是选择阶段,旨在保留具有良好特征的个体,淘汰表现不佳的个体。这一过程有多种策略可供选择,从简单的排序法到更加复杂的随机锦标赛选择等。选择策略需要权衡探索(尝试新的解决方案)和利用(保留已知的良好解决方案)之间的平衡。遗传算法的核心在于通过有效探索来寻找最优解。常见的选择技术包括:锦标赛选择、轮盘赌选择、等级选择等。

经过选择后,遗传算法会在保留的优秀个体基因库中引入变异,以产生新的候选解。主要有两种变异技术:交叉和突变。

交叉是模仿生物交配过程,将两个亲代个体的部分基因随机组合,产生新的子代个体。这一过程能够将亲代的良好特征组合在一起,有望产生更优秀的后代。

突变则是对个体的基因做出少量随机改变,以引入新的多样性,避免群体过早收敛于局部最优解。

遗传算法-交叉

变异,同样是指自然界中遗传物质发生随机突变,基因库中引入新的价值,从而增加其多样性。

遗传算法-变异

之后,算法循环往复:再次通过目标函数评估个体,进行选择,然后是交叉、变异等。

可以使用各种停止标准:如果目标函数在一定代数内停止改进,循环就会中断。或者你也可以设定一个硬性的停止条件,即已评估的总代数。或者以时间为基础,或者观察外部信号等。无论如何,具有最佳目标值的个体都应被视为问题的解决方案。

在遗传算法(GA)中,随机选择技术有时可能会由于偶然因素而放弃当代种群中最优秀的个体。尽管发生概率不高,但这种情况确实存在。这就是引入"精英主义"策略的目的,它确保无论如何,种群中的优秀个体都会被保留下来。然而,过度使用精英主义也可能导致算法陷入局部最优解,从而错失全局最优解。GA本质上是一种探索性算法,根据我有限的经验,为其引入过多偏见并不利于寻找最优解。GA本身就提供了大量的算法变体可供尝试和探索。

在GA中,我们可以调整以下几个超参数:

  • 种群规模(个体数量)

  • 基因突变概率

  • 个体交叉概率

  • 个体选择策略等

手动尝试不同超参数组合是寻找最优参数的一种方式。另一种高级方法是将GA封装到优化框架(如Optuna)中,利用框架自动搜索最佳超参数,但这种方式计算代价较高。

无论采用何种方式,GA都为我们提供了一种灵活有趣的优化探索方式,让我们可以充分发挥创意。

特征选择的GA代码

下面是一个可用于特征选择的简单 GA 代码。它使用了功能强大的 deap 库,但学习曲线可能比较陡峭。不过,这个简单的版本应该足够清晰。

 

上下滑动查看更多源码

# to maximize the objective
# fitness_weights = 1.0
# to minimize the objective
fitness_weights = -1.0

# copy the original dataframes into local copies, once
X_ga = X.copy()
y_ga = y.copy()

# 'const' (the first column) is not an actual feature, do not include it
X_features = X_ga.columns.to_list()[1:]

try:
del creator.FitnessMax
del creator.Individual
except Exception as e:
pass

creator.create("FitnessMax", base.Fitness, weights=(fitness_weights,))
creator.create(
"Individual", array.array, typecode='b', fitness=creator.FitnessMax
)

try:
del toolbox
except Exception as e:
pass

toolbox = base.Toolbox()
# Attribute generator
toolbox.register("attr_bool", random.randint, 0, 1)
# Structure initializers
toolbox.register(
"individual",
 tools.initRepeat,
 creator.Individual,
 toolbox.attr_bool,
 len(X_features),
)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)


def evalOneMax(individual):
# objective function
# create True/False selector list for features
# and add True at the start for 'const'
 cols_select = [True] + [i == 1 for i in list(individual)]
# fit model using the features selected from the individual
 lin_mod = sm.OLS(y_ga, X_ga.loc[:, cols_select], hasconst=True).fit()
return (lin_mod.bic,)


toolbox.register("evaluate", evalOneMax)
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutFlipBit, indpb=0.05)
toolbox.register("select", tools.selTournament, tournsize=3)

random.seed(0)
pop = toolbox.population(n=300)
hof = tools.HallOfFame(1)
pop, log = algorithms.eaSimple(
 pop, toolbox, cxpb=0.5, mutpb=0.2, ngen=10, halloffame=hof, verbose=True
)

best_individual_ga_small = list(hof[0])
best_features_ga_small = [
 X_features[i] for i, val in enumerate(best_individual_ga_small) if val == 1
]
best_objective_ga_small = (
 sm.OLS(y_ga, X_ga[['const'] + best_features_ga_small], hasconst=True)
 .fit()
 .bic
)
print(f'best objective: {best_objective_ga_small}')
print(f'best features: {best_features_ga_small}')

代码使用对象来定义个体和整个种群,并采取评估(目标函数)、交叉/交配、突变和选择的策略。起初,代码从包含 300 个个体的种群开始,然后调用 eaSimple() 函数(该函数包含了交叉、变异和选择的预设序列),并且仅运行 10 代以简化过程。名人堂的规模为 1,它会保留绝对最优秀的个体,以防它们在选择等过程中被意外变异或跳过。

名人堂并非精英主义,而是从群体中复制最优秀的个体,并仅在锡罐中保留一个非活动副本。精英主义则是将活跃种群中最优秀的个体一代一代地保留下来。

这个简单的代码很容易理解,但效率很低。下面有更复杂版本的 GA 代码,更复杂、更优化的代码 1000 代后。

 

上下滑动查看更多源码

# to maximize the objective
# fitness_weights = 1.0
# to minimize the objective
fitness_weights = -1.0

# copy the original dataframes into local copies, once
X_ga = X.astype(float).copy()
y_ga = y.astype(float).copy()

# 'const' (the first column) is not an actual feature, do not include it
X_features = X_ga.columns.to_list()[1:]

try:
del creator.FitnessMax
del creator.Individual
except Exception as e:
pass

creator.create("FitnessMax", base.Fitness, weights=(fitness_weights,))
creator.create(
"Individual", array.array, typecode='b', fitness=creator.FitnessMax
)

try:
del toolbox
except Exception as e:
pass

toolbox = base.Toolbox()
# Attribute generator
toolbox.register("attr_bool", random.randint, 0, 1)
# Structure initializers
toolbox.register(
"individual",
 tools.initRepeat,
 creator.Individual,
 toolbox.attr_bool,
 len(X_features),
)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)


def evalMany(individuals):
# individuals is an array of shape (n_individuals, n_features)
# transform it into a list of lists:
# - a list of individuals
# - each individual is a list of feature selectors
 ind_list = [list(i) for i in list(individuals)]
 ret = []
for ind in ind_list:
# create a list of True/False feature selectors from each individual
# pre-pend True to always select the 'const' feature
 cols_select = [True] + [i == 1for i in list(ind)]
# fit model using the features selected from the individual
 lin_mod = sm.OLS(y_ga, X_ga.loc[:, cols_select], hasconst=True).fit()
 ret.append((lin_mod.bic,))
return ret


# multiprocess pool to evaluate individuals
def joblib_map(f, njobs, *iters):
return Parallel(n_jobs=njobs)(delayed(f)(*args) for args in zip(*iters))


def selElitistAndTournament(
 individuals, k_tournament, k_elitist=0, tournsize=3
):
# elitist tournament
# in addition to the regular tournament, ensure the top #k_elistist individuals are preserved
return tools.selBest(individuals, k_elitist) + tools.selTournament(
 individuals, k_tournament, tournsize
 )


# Hyperparameters
population_size = 1000
crossover_probability = 0.5
individual_mutation_probability = 0.2
gene_mutation_probability = 0.1
tournament_size = 3
elite_size = 0

n_jobs = os.cpu_count()

# register the pool as the mapper
# and the custom function as the evaluator
toolbox.register("map_multi", joblib_map)
toolbox.register("evaluate", evalMany)

toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutFlipBit, indpb=gene_mutation_probability)
# toolbox.register("select", tools.selTournament, tournsize=tournament_size)
# selection with tournament and optional elitism
toolbox.register(
"select",
 selElitistAndTournament,
 k_tournament=population_size - elite_size,
 k_elitist=elite_size,
 tournsize=tournament_size,
)

random.seed(0)
population = toolbox.population(n=population_size)
hall_of_fame = tools.HallOfFame(1)
objective_runs_ga = 0

# Evaluate the individuals with an invalid fitness
invalid_ind = [ind for ind in population if not ind.fitness.valid]
# split the population in a list with n_jobs elements
# each element is an array containing multiple individuals
# send individuals to the evaluator
fitnesses_nested = toolbox.map_multi(
 toolbox.evaluate, n_jobs, np.array_split(invalid_ind, n_jobs)
)
objective_runs_ga += len(invalid_ind)
fitnesses = []
for l in fitnesses_nested:
 fitnesses += l
for ind, fit in zip(invalid_ind, fitnesses):
 ind.fitness.values = fit

hall_of_fame.update(population)

n_gen = 1000
best_objective_per_gen_ga = np.full(n_gen, np.nan)
best_objective_ga = np.nan
best_generation_ga = 0
gene_values_mean = np.zeros((n_gen, len(X_features)))
gene_maes = np.full(n_gen, np.nan)
time_to_best_ga = np.inf
# Begin the generational process
iterator = tqdm(range(1, n_gen + 1), desc='generation')
t_start = time.time()
for gen in iterator:
 t_start_loop = time.time()

# Select the next generation of individuals
 offspring = toolbox.select(population)
# Vary the pool of individuals via cross-over and mutation
 offspring = algorithms.varAnd(
 offspring,
 toolbox,
 crossover_probability,
 individual_mutation_probability,
 )
# Evaluate the individuals with an invalid fitness
 invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
# split the population in a list with n_jobs elements
# each element is an array containing multiple individuals
# send list to the evaluator pool
 fitnesses_nested = toolbox.map_multi(
 toolbox.evaluate, n_jobs, np.array_split(invalid_ind, n_jobs)
 )
 objective_runs_ga += len(invalid_ind)
 fitnesses = []
for l in fitnesses_nested:
 fitnesses += l
for ind, fit in zip(invalid_ind, fitnesses):
 ind.fitness.values = fit
# Update the hall of fame with the generated individuals
 hall_of_fame.update(offspring)
# Replace the current population by the offspring
 population[:] = offspring

 t_end_loop = time.time()

# record the mean gene values across the population
 gene_values_mean[gen - 1, :] = np.array(population).mean(axis=0)
if gen >= 2:
 gene_maes[gen - 1] = mean_absolute_error(
 gene_values_mean[gen - 2, :], gene_values_mean[gen - 1, :]
 )
# pick best individual for stats recording
 best_individual_ga = tools.selBest(population, 1)[0]
 best_objective_per_gen_ga[gen - 1] = best_individual_ga.fitness.values[0]
if (
 best_objective_ga is np.nan
or fitness_weights * best_individual_ga.fitness.values[0]
 > fitness_weights * best_objective_ga
 ):
 best_objective_ga = best_individual_ga.fitness.values[0]
 best_generation_ga = gen
 time_to_best_ga = t_end_loop - t_start
 print(
f'gen: {gen:4n}, curr/prev gene MAE: {gene_maes[gen - 1]:.4f}, new best objective: {best_objective_ga:.4f}, time to best: {time_to_best_ga:.4f}'
 )

if os.path.isfile('break'):
# to gracefully break the loop, manually create a file called 'break'
 print(f'Found break file, stopping now.')
 iterator.close()
break
g_completed_ga = gen

best_individual_ga = list(hall_of_fame[0])
best_features_ga = [
 X_features[i] for i, val in enumerate(best_individual_ga) if val == 1
]
best_objective_ga = (
 sm.OLS(y_ga, X_ga[['const'] + best_features_ga], hasconst=True).fit().bic
) 

## 强烈建议关注#公众号:数据STUDIO 更多优质内容每日更新!
bestobjective: 33705.569572544795
bestgeneration: 787
objectiveruns: 600525
timetobest: 158.027sec

同样,在选择任何特征之前的基准 BIC 计算:

 

上下滑动查看更多源码

print(f'best objective: {best_objective_ga}')
print(f'best generation: {best_generation_ga}')
print(f'objective runs: {objective_runs_ga}')
print(f'time to best: {time_to_best_ga:.3f} sec')
print(f'best features: {best_features_ga}')

gvm_df = (
 pd.DataFrame(
 gene_values_mean,
 columns=X_features,
 index=range(1, gene_values_mean.shape[0] + 1),
 )
 .sort_index(axis=1)
 .iloc[:g_completed_ga]
)
if g_completed_ga > 20:
 x_ticks = list(range(1, g_completed_ga + 1, round(g_completed_ga / 20)))
else:
 x_ticks = list(range(1, g_completed_ga + 1))
if x_ticks[-1] != g_completed_ga:
 x_ticks.append(g_completed_ga)

fig, ax = plt.subplots(
3,
1,
 sharex=True,
 height_ratios=[24, 1, 1],
 figsize=(12, 48),
 layout='constrained',
)

sns.heatmap(
 gvm_df.sort_index(axis=1).T,
 vmin=0.0,
 vmax=1.0,
 cmap='viridis',
 cbar=True,
 cbar_kws={'fraction': 0.01, 'anchor': (0.0, 1.0)},
 ax=ax[0],
)
ax[0].set_title('Population average of gene values after each generation')
ax[0].axvline(x=best_generation_ga, color='C7')
ax[0].set_xlabel('generation')
ax[0].tick_params(axis='both', reset=True)
ax[0].set_xticks(x_ticks)
ax[0].set_xticklabels(x_ticks)

ax[1].set_xlabel('generation')
ax[1].plot(list(range(2, g_completed_ga + 1)), gene_maes[1:g_completed_ga])
ax[1].vlines(
 x=best_generation_ga,
 ymin=gene_maes[1:g_completed_ga].min(),
 ymax=gene_maes[1:g_completed_ga].max(),
 colors='C7',
)
ax[1].set_xlabel('generation')
ax[1].set_ylabel('MAE')
ax[1].set_title(
'Mean absolute error of average gene values between current generation and previous generation'
)
ax[1].tick_params(axis='both', reset=True)

ax[2].set_xlabel('generation')
ax[2].plot(
 list(range(1, g_completed_ga + 1)),
 best_objective_per_gen_ga[:g_completed_ga],
)
ax[2].vlines(
 x=best_generation_ga,
 ymin=min(best_objective_per_gen_ga[:g_completed_ga]),
 ymax=max(best_objective_per_gen_ga[:g_completed_ga]),
 colors='C7',
)
ax[2].set_xlabel('generation')
ax[2].set_ylabel('best objective')
ax[2].set_title('Best objective')

fig.suptitle('Genetic algorithm')
fig.savefig('ga-performance.png')
fig.show()

best objective: 33705.569572544795

bestgeneration: 787
objectiveruns: 600525
timetobest: 158.027sec
bestfeatures: ['BedroomAbvGr', 'BldgType_1Fam', 'BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF', 'Condition1_Norm', 'Condition2_PosN', 'ExterQual_Ex', 'Exterior1st_BrkFace', 'Functional_Sev', 'Functional_Typ', 'GarageArea', 'GrLivArea', 'HeatingQC_Ex', 'KitchenQual_Ex', 'LandContour_HLS', 'LotArea', 'LotConfig_CulDSac', 'LowQualFinSF', 'Neighborhood_BrkSide', 'Neighborhood_Crawfor', 'Neighborhood_NWAmes', 'Neighborhood_NoRidge', 'Neighborhood_NridgHt', 'Neighborhood_Somerst', 'Neighborhood_StoneBr', 'OverallCond', 'OverallQual', 'PoolArea', 'RoofMatl_WdShngl', 'SaleCondition_Normal', 'SaleType_New', 'TotalBsmtSF', 'WoodDeckSF', 'YearBuilt']

 

上下滑动查看更多

遗传算法-优化历史
上面是一段优化算法的描述,该算法用于在1000代进化过程中寻找最佳特征组合。进化过程将特征的受欢迎程度用热图可视化表示,横向代表不同特征,纵向代表进化代数。热图上颜色越深,代表该特征在该代群体中越受欢迎。从热图可以看出,一些特征在整个进化过程中保持较高受欢迎度;另一些特征则很快被淘汰;还有些特征的受欢迎程度随着进化代数的增加而有所波动。该可视化展示了进化算法在特征选择过程中的动态变化,有助于了解算法的工作原理和特征的重要性。

各种方法之间的比较

我们尝试了三种不同的技术:SFS、CMA-ES 和 GA。就找到的最佳目标和找到目标所花费的时间而言,它们之间的比较如何?

这些测试是在一台安装了Ubuntu 22.04和Python 3.11.7的AMD Ryzen 7 5800X3D(8/16核)机器上进行的。SFS和GA分别通过一个包含16个Worker的多进程池来运行目标函数。CMA-ES是单进程的,多进程运行似乎没有明显的改进,但我相信如果有更多的工作来使算法并行化,情况会有所改善。

这些是执行时间。对SFS来说,是总执行时间。对于CMA-ES和GA,这是达到最佳解决方案所需的时间。时间越短越好。

SFS: 42.448sec
GA: 158.027sec
CMA-ES: 48.326sec

目标函数被调用的次数--越少越好:

SFS: 22791
GA: 600525
CMA-ES: 20000

为目标函数找到的最佳值,与基准值相比——越少越好:

baselineBIC: 34570.1662
SFS: 33708.9860
GA: 33705.5696
CMA-ES: 33703.0705

在目标函数方面,遗传算法(GA)能够取得比序列前向选择(SFS)更好的结果,因为它能够利用尽可能多的CPU内核来并行运行目标函数,但代价是它的运行速度是所有算法中最慢的。GA调用目标函数的次数远远超过其他方法。对超参数进行进一步优化可能会提高GA的性能。

相比之下,SFS的运行速度很快(能够在所有CPU内核上并行运行),但其性能一般。SFS是所有算法中最简单的。

如果你只是想快速估算出近似最优的特征集,而不太在意精度,SFS是一个不错的选择。

然而,如果你追求最优目标值,无约束进化策略(CMA-ES)似乎是最好的选择。

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

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

相关文章

液相色谱仪仪器校准怎么做?具体校准方法是什么?

液相色谱法概述 液相色谱仪是由输液系统、进样系统、分离系统、检测系统和数据处理系统等部分组成的分析仪器。液相色谱仪是根据样品之中各组分在色谱柱中的固定相和流动相间的分布或吸附特性的差异,流动相将样品带入色谱柱进行分离。由检测器检测,并由…

Java 和 .NET Core 在企业级应用开发中各有什么优势和劣势?看看AI是怎么回答的

Java 和 .NET Core 在企业级应用开发中各有什么优势和劣势?看看AI是怎么回答的 1.kimi 网址:https://kimi.moonshot.cn/ Kimi是北京月之暗面科技有限公司于2023年10月9日推出的一款智能助手,主要应用场景为专业学术论文的翻译和理解、辅助分析…

python基础语法 010 类和对象-6-1 继承定义

前提: 在真实世界中,类型之间可能存在范围包含关系,比如:人这个类型和亚洲人这个类型。 人是包括了亚洲人的,如果某人是员工亚洲人,那么它必定是一个人 这种关系,在编程语言中称为继承关系 比如…

Java Web|day5.MyBatis

MyBatis 定义 它是一款半自动的ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低 **ORM: **Object Relation Mapping,…

数据库调优的流程及参考参数

1.数据库调优的流程: 1.1.调优思考流程: 1.对数据库进行调优的时候,我们可以依据以下步骤进行思考: 整个流程划分成了观察 (Show status) 和行动 (Action) 两个部分。字母 S 的部分代表观察(会使用相应的分析工具&am…

全自由度控制八极电磁铁-吴贤铭智能工程学院案例

根据客户需求,上海天端实业有限公司设计八极电磁铁方案 八极电磁铁产品说明 八极电磁铁可在空间内部产生方向及强度可控的均匀磁场或梯度磁场,八组磁极以空间极轴布置,每组磁极可独立控制,磁场空间300mm直径球域。 八极电磁铁电…

electron 官网速通

前言:参考Electron 中文网。 核心知识点:有哪些进程,进程之间的通信,electron API 分类及怎么调用。 一、快速开始 1. 新建一个 my-electron 的文件夹。 2. 运行 npm init 创建 package.json 文件。 3. 填写 author 和 descr…

【Python-办公自动化】1秒提取多个word表格汇总至1个excel内

欢迎来到"花花 Show Python",一名热爱编程和分享知识的技术博主。在这里,我将与您一同探索Python的奥秘,分享编程技巧、项目实践和学习心得。无论您是编程新手还是资深开发者,都能在这里找到有价值的信息和灵感。 自我介绍: 我热衷于将复杂的技术概念以简单易懂…

苹果上架没有iphone、没有ipad也可以生成截屏

使用flutter、uniapp或其他跨平台框架开发ios的APP,上架的时候都会遇到一个问题,上架的时候需要各种尺寸的设备来做ios截屏。 比如目前最新的要求是,iphone需要三种不同尺寸的设备的截屏,假如支持ipad则还需要使用ipad 2代和ipad…

linux常用命令学习-ls命令

1.1 ls 命令 命令功能:查看文件信息。 在 ubuntu 上,一般都使用 ls 命令来查看文件信息,ls ,是 list 这个单词的缩写。在当前目录下输入 ls 命令,这样就会列出当前路径下的全部文件,例如我们要查看桌面上的文件&#x…

什么是硬件在环仿真?

硬件在环Hardware-in-the-loop(HIL)仿真是一种实时仿真。您可以使用HIL模拟来测试您的控制器设计。HIL模拟显示了控制器如何实时响应逼真的虚拟刺激。您还可以使用HIL来确定您的物理系统(设备)模型是否有效。 在HIL模拟中&#xf…

代码随想录训练营 Day34打卡 动态规划 part02 62. 不同路径 63. 不同路径 II 343. 整数拆分 96. 不同的二叉搜索树

代码随想录训练营 Day34打卡 动态规划 part02 一、力扣62. 不同路径 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Fini…

5.vue中axios封装工程化

vue工程化中axios封装 视频演示地址:https://www.bilibili.com/video/BV121egeQEHg/?vd_source0f4eae2845bd3b24b877e4586ffda69a 通常我们封装需要封装request.js基础的发送请求工具类,再根据业务封装service类,service类是具体业务的接口…

Ps:首选项 - 暂存盘

Ps菜单:编辑/首选项 Edit/Preferences 快捷键:Ctrl K Photoshop 首选项中的“暂存盘” Scratch Disks选项卡通过合理配置和管理暂存盘,可以显著提高 Photoshop 的运行性能,特别是在处理复杂的设计项目或大型图像文件时。选择合适…

Conformer解析

文章目录 前言Conformer encoder model architectureConvolution SubsamplingLinear & DropoutConformer BlocksFeed Forward ModuleMulti-Headed Self-Attention ModuleConvolution Module 前言 Conformer encoder model architecture 对于语音来说,整个架构…

内核链表的实现

内核链表和普通链表的区别: 1. 普通链表当中数据域和指针域,没有做到区分,数据与指针形成了一个整体,而内核链表数据与指针是完全剥离的没有直接的关系。 2. 在普通链表当中所有节点的数据都是一样的类型,而内核链表…

vmware安装openEuler操作系统

文章目录 vmware安装openEuler操作系统官网地址下载方式 新建虚拟机新建虚拟机新建虚拟机向导输入新建的虚拟机名称预览安装虚拟机的操作系统开始安装语言选项基础配置 网络配置关机拍快照克隆模板机 vmware安装openEuler操作系统 官网地址 https://www.openeuler.org/zh/dow…

6.4 MySQL 常见查询优化案例分析

欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏: 工💗重💗hao💗:野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题.…

Python 函数参数介绍

目录 函数 -- 普通参数 函数 -- 参数进一步 -- 指定参数 函数 -- 参数带 * -- 将传入的参数打包成元组 函数 -- 参数带 ** -- 关键字传参 -- 将传入的参数打包成字典 综合使用 函数 -- 普通参数 函数 -- 参数进一步 -- 指定参数 函数调用时,未指定的参数需要写…

风清扬/基于Java语言的光伏监控系统+光伏发电预测+光伏项目+光伏运维+光伏储能项目

基于Java语言的光伏监控系统光伏发电预测光伏项目光伏运维光伏储能项目 介绍 基于Java语言的光伏监控系统光伏发电系统光伏软件系统光伏监控系统源码光伏发电系统源码 基于Java语言的光伏监控系统光伏发电预测光伏项目光伏运维光伏储能项目 安装教程 参与贡献 Fork 本仓库新…