信用卡欺诈检测

基于信用卡交易记录数据建立分类模型来预测哪些交易记录是异常的哪些是正常的。

任务流程:

  • 加载数据,观察问题
  • 针对问题给出解决方案
  • 数据集切分
  • 评估方法对比
  • 逻辑回归模型
  • 建模结果分析
  • 方案效果对比

主要解决问题:

(1)在此项目中,我们首选对数据进行了观察,发现了其中样本不均衡的问题,其实我们做任务工作之前都一定要先进行数据检查,看看数据有什么问题,针对这些问题来选择解决方案。

(2)这里我们提出了两种方法,下采样和过采样,两条路线来进行对比实验,任何实际问题来了之后,我们都不会一条路走到黑的,没有对比就没有伤害,通常都会得到一个基础模型,然后对各种方法进行对比,找到最合适的,所以在任务开始之前,一定得多动脑筋多一手准备,得到的结果才有可选择的余地。

(3)在建模之前,需要对数据进行各种预处理的操作,比如数据标准化,缺失值填充等,这些都是必要操作,由于数据本身已经给定了特征,此处我们还没有提到特征工程这个概念,后续实战中我们会逐步引入,其实数据预处理的工作是整个任务中最为最重也是最苦的一个阶段,数据处理的好不好对结果的影响是最大的。

(4)先选好评估方法,再进行建模。建模的目的就是为了得到结果,但是我们不可能一次就得到最好的结果,肯定要尝试很多次,所以一定得有一个合适的评估方法,可以用这些通用的,比如Recall,准确率等,也可以根据实际问题自己指定评估指标。

(5)选择合适的算法,这里我们使用的是逻辑回归,也详细分析了其中的细节,这是因为我们刚刚讲解完逻辑回归的原理就拿它来练手了,之后我们还会讲解其他算法,并不一定非要用逻辑回归来完成这个任务,其他算法可能效果会更好。但是有一点我希望大家能够理解就是在机器学习中并不是越复杂的算法越实用,恰恰相反,越简单的算法反而应用的越广泛。逻辑回归就是其中一个典型的代表了,简单实用,所以任何分类问题都可以把逻辑回归当做一个待比较的基础模型了。

(6)模型的调参也是很重要的,之前我们通过实验也发现了不同的参数可能会对结果产生较大的影响,这一步也是必须的,后续实战内容我们还会来强调调参的细节,这里就简单概述一下了。对于参数我建立大家在使用工具包的时候先看看其API文档,知道每一个参数的意义,再来实验选择合适的参数值。

(7)得到的结果一定要和实际任务结合在一起,有时候虽然得到的结果指标还不错,但是实际应用却成了问题,所以测试环节也是必不可少的。到此,这个项目就给大家介绍到这里了,在实践中学习才能成长的更快,建议大家一定使用提供的Notebook代码文件来自己完成一遍上述操作。
1.导入工具包并读取数据

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np%matplotlib inline
data = pd.read_csv("creditcard.csv")
data.head()


2.数据标签分布

count_classes = pd.value_counts(data['Class'],sort=True)
count_classes.plot(kind='bar')
plt.title('Fraud class histogram')
plt.xlabel('Class')
plt.ylabel('Frequency')


3.数据标准化处理

from sklearn.preprocessing import StandardScaler
data['normAmount'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1,1))
data = data.drop(['Time','Amount'],axis=1)
data.head()


4.下采样方案

X = data.iloc[:,data.columns != 'Class']
y = data.iloc[:,data.columns == 'Class']
# 得到所有异常样本的索引
number_records_fraud = len(data[data.Class==1])
fraud_indices = np.array(data[data.Class==1].index)
# 得到所有正样本的索引
normal_indices = data[data.Class == 0].index
# 在正常样本随机采样出指定个数的样本,取其索引
random_normal_indices = np.random.choice(normal_indices,number_records_fraud,replace=False)
random_normal_indices = np.array(random_normal_indices)
#有了正常和一场样本后把他们的索引都拿到手
under_sample_indices = np.concatenate([fraud_indices,random_normal_indices])
# 根据索引得到下采样所有样本点
under_sample_data = data.iloc[under_sample_indices,:]
X_undersample = under_sample_data.iloc[:,under_sample_data.columns != 'Class']
y_undersample = under_sample_data.iloc[:,under_sample_data.columns == 'Class']
下采样 样本比例
print("正常样本所占整体比例: ", len(under_sample_data[under_sample_data.Class == 0])/len(under_sample_data))
print("异常样本所占整体比例: ", len(under_sample_data[under_sample_data.Class == 1])/len(under_sample_data))
print("下采样策略总体样本数量: ", len(under_sample_data))

正常样本所占整体比例: 0.5
异常样本所占整体比例: 0.5
下采样策略总体样本数量: 984

5.数据集切分

from sklearn.model_selection import train_test_split
#整个数据集的划分
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3,random_state=0)
print('原始训练集包括样本数量:',len(X_train))
print('原始测试集包含样本数量:',len(X_test))
print('原始样本数量:',len(X_train)+len(X_test))
#下采样样本进行划分
X_train_undersample,X_test_undersample,y_train_undersample,y_test_undersample = train_test_split(X_undersample,y_undersample,test_size=0.3,random_state=0)
print()
print('下采样训练集包括样本数量:',len(X_train_undersample))
print('下采样测试集包括样本数量:',len(y_test_undersample))

原始训练集包括样本数量: 199364
原始测试集包含样本数量: 85443
原始样本数量: 284807

下采样训练集包括样本数量: 688
下采样测试集包括样本数量: 296

6.逻辑回归建模

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold,cross_val_score
from sklearn.metrics import confusion_matrix,recall_score,classification_report
from sklearn.model_selection import cross_val_predict
def printing_Kfold_scores(x_train_data,y_train_data):fold = KFold(5,shuffle=False)# 定义不同力度的正则化惩罚力度c_param_range = [0.01,0.1,1,10,100]# 展示结果用的表格results_table = pd.DataFrame(columns = ['C_parameter','Mean recall score'])results_table['C_parameter'] = c_param_range# K-fold表示K折的交叉验证,这里会得到两个索引集合,训练集 = indices[0],验证集 = indices[1]j = 0#循环遍历所有参数for c_param in c_param_range:print('---------------------------------------------')print('正则化力度:',c_param)print('---------------------------------------------')print('')recall_accs = []#一步步分解来执行交叉验证for iteration,indices in enumerate(fold.split(x_train_data)):# 指定算法模型,并且给定参数lr = LogisticRegression(C = c_param,penalty = 'l1',solver = 'liblinear')# 训练模型,注意索引不要给错了lr.fit(x_train_data.iloc[indices[0],:],y_train_data.iloc[indices[0],:].values.ravel())# 建立好模型后,预测模型结果,这里用的是验证集,索引为1y_pred_undersample = lr.predict(x_train_data.iloc[indices[1],:])# 有了预测结果之后就可以来评估了,这里recall_score需要传入预测值和真实值recall_acc = recall_score(y_train_data.iloc[indices[1],:].values,y_pred_undersample)# 一会还要算平均,把每一步的结果先保存下来recall_accs.append(recall_acc)print('Iteration',iteration,'召回率 = ',recall_acc)#当执行所有交叉验证后,计算平均结果results_table.loc[j,'Mean recall score'] = np.mean(recall_accs)j += 1print('')print('平均召回率 ',np.mean(recall_accs))#找到最好的参数,哪一个recall高自然就是最好的best_c = results_table.loc[np.argmax(results_table['Mean recall score'].astype('float32'))]['C_parameter']# 打印最好的结果print('*********************************************************************************')print('效果最好的模型所选参数 = ', best_c)print('*********************************************************************************')return best_c
best_c = printing_Kfold_scores(X_train_undersample,y_train_undersample)

正则化力度: 0.01

Iteration 0 召回率 = 0.9315068493150684
Iteration 1 召回率 = 0.9178082191780822
Iteration 2 召回率 = 0.9830508474576272
Iteration 3 召回率 = 0.9594594594594594
Iteration 4 召回率 = 0.9545454545454546

平均召回率 0.9492741659911385

正则化力度: 0.1

Iteration 0 召回率 = 0.8493150684931506
Iteration 1 召回率 = 0.863013698630137
Iteration 2 召回率 = 0.9491525423728814
Iteration 3 召回率 = 0.9459459459459459
Iteration 4 召回率 = 0.9090909090909091

平均召回率 0.9033036329066049

正则化力度: 1

Iteration 0 召回率 = 0.863013698630137
Iteration 1 召回率 = 0.9041095890410958
Iteration 2 召回率 = 0.9661016949152542
Iteration 3 召回率 = 0.9459459459459459
Iteration 4 召回率 = 0.9090909090909091

平均召回率 0.9176523675246685

正则化力度: 10

Iteration 0 召回率 = 0.863013698630137
Iteration 1 召回率 = 0.9041095890410958
Iteration 2 召回率 = 0.9661016949152542
Iteration 3 召回率 = 0.9459459459459459
Iteration 4 召回率 = 0.9090909090909091

平均召回率 0.9176523675246685

正则化力度: 100

Iteration 0 召回率 = 0.8767123287671232
Iteration 1 召回率 = 0.9178082191780822
Iteration 2 召回率 = 0.9661016949152542
Iteration 3 召回率 = 0.9459459459459459
Iteration 4 召回率 = 0.9090909090909091

平均召回率 0.923131819579463


效果最好的模型所选参数 = 0.01


7.混淆矩阵绘制

def plot_confusion_matrix(cm,classes,title='Confusion matrix',cmap = plt.cm.Blues):'''绘制混淆矩阵'''plt.imshow(cm,interpolation='nearest',cmap=cmap)plt.title(title)plt.colorbar()tick_marks = np.arange(len(classes))plt.xticks(tick_marks,classes,rotation=0)plt.yticks(tick_marks,classes)chresh = cm.max() / 2for i,j in itertools.product(range(cm.shape[0]),range(cm.shape[1])):plt.text(j,i,cm[i,j],horizontalalignment='center',color='white' if cm[i,j] > chresh else 'black')plt.tight_layout()plt.ylabel('True label')plt.xlabel('Predicted label')

8.下采样方案在下采样数据集中结果

import itertools
lr = LogisticRegression(C = best_c,penalty = 'l1',solver='liblinear')
lr.fit(X_train_undersample.values,y_train_undersample.values.ravel())
y_pred_undersample = lr.predict(X_test_undersample.values)
# 计算所需值
cnf_matrix = confusion_matrix(y_test_undersample,y_pred_undersample)
np.set_printoptions(precision=2)
print('召回率:',cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))
# 绘制
class_names = [0,1]
plt.figure()
plot_confusion_matrix(cnf_matrix,classes = class_names,title = 'Confusion matrix')
plt.show()


9.下采样方案在原始数据集中结果

lr = LogisticRegression(C = best_c,penalty = 'l1',solver = 'liblinear')
lr.fit(X_train_undersample,y_train_undersample.values.ravel())
y_pred = lr.predict(X_test.values)
#计算所需值
cnf_matrix = confusion_matrix(y_test,y_pred)
np.set_printoptions(precision=2)
print('召回率:',cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))
# 绘制
class_name = [0,1]
plt.figure()
plot_confusion_matrix(cnf_matrix,classes = class_name,title = 'Confusion matrix')


10.原始数据直接建模

best_c = printing_Kfold_scores(X_train,y_train)

正则化惩罚力度: 0.01

Iteration 0 : 召回率 = 0.4925373134328358
Iteration 1 : 召回率 = 0.6027397260273972
Iteration 2 : 召回率 = 0.6833333333333333
Iteration 3 : 召回率 = 0.5692307692307692
Iteration 4 : 召回率 = 0.45

平均召回率 0.5595682284048672


正则化惩罚力度: 0.1

Iteration 0 : 召回率 = 0.5671641791044776
Iteration 1 : 召回率 = 0.6164383561643836
Iteration 2 : 召回率 = 0.6833333333333333
Iteration 3 : 召回率 = 0.5846153846153846
Iteration 4 : 召回率 = 0.525

平均召回率 0.5953102506435158


正则化惩罚力度: 1

Iteration 0 : 召回率 = 0.5522388059701493
Iteration 1 : 召回率 = 0.6164383561643836
Iteration 2 : 召回率 = 0.7166666666666667
Iteration 3 : 召回率 = 0.6153846153846154
Iteration 4 : 召回率 = 0.5625

平均召回率 0.612645688837163


正则化惩罚力度: 10

Iteration 0 : 召回率 = 0.5522388059701493
Iteration 1 : 召回率 = 0.6164383561643836
Iteration 2 : 召回率 = 0.7333333333333333
Iteration 3 : 召回率 = 0.6153846153846154
Iteration 4 : 召回率 = 0.575

平均召回率 0.6184790221704963


正则化惩罚力度: 100

Iteration 0 : 召回率 = 0.5522388059701493
Iteration 1 : 召回率 = 0.6164383561643836
Iteration 2 : 召回率 = 0.7333333333333333
Iteration 3 : 召回率 = 0.6153846153846154
Iteration 4 : 召回率 = 0.575

平均召回率 0.6184790221704963


效果最好的模型所选参数 = 10.0


11.原始数据建模结果

lr = LogisticRegression(C = best_c,penalty = 'l1',solver = 'liblinear')
lr.fit(X_train,y_train.values.ravel())
y_pred_undersample = lr.predict(X_test)
cnf_matrix = confusion_matrix(y_test,y_pred_undersample)
np.set_printoptions(precision=2)
print('Recall metric in the testing dataset:',cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))
class_names = [0,1]
plt.figure()
plot_confusion_matrix(cnf_matrix,classes = class_name,title = 'Confusion matrix')
plt.show()


12.阈值对结果的影响

# 用之前最好的参数来进行建模
lr = LogisticRegression(C = 0.01,penalty = 'l1',solver = 'liblinear')
# 训练模型,还是下采样的数据集
lr.fit(X_train_undersample,y_train_undersample.values.ravel())
#得到预测结果的概率值
y_pred_undersample_proba = lr.predict_proba(X_test_undersample.values)
#指定不同的阈值
thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
plt.figure(figsize=(10,10))
j = 1
# 用混淆矩阵展示
y_pred_undersample_proba
for i in thresholds:y_test_predictions_high_recall = y_pred_undersample_proba[:,1] > iplt.subplot(3,3,j)j += 1cnf_matrix = confusion_matrix(y_test_undersample,y_test_predictions_high_recall)np.set_printoptions(precision=2)print('给定阈值:',i,'时召回率:',cnf_matrix[1][1]/(cnf_matrix[1][1]+cnf_matrix[1][0]))class_names = [0,1]plot_confusion_matrix(cnf_matrix, classes=class_names, title='Threshold >= %s'%i)

给定阈值: 0.1 时召回率: 1.0
给定阈值: 0.2 时召回率: 1.0
给定阈值: 0.3 时召回率: 1.0
给定阈值: 0.4 时召回率: 0.9727891156462585
给定阈值: 0.5 时召回率: 0.9183673469387755
给定阈值: 0.6 时召回率: 0.891156462585034
给定阈值: 0.7 时召回率: 0.8299319727891157
给定阈值: 0.8 时召回率: 0.782312925170068
给定阈值: 0.9 时召回率: 0.5782312925170068

13.SMOTE过采样方案

import pandas as pd
from imblearn.over_sampling import SMOTE
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
credit_cards = pd.read_csv('creditcard.csv')
columns = credit_cards.columns
# 在特征中删掉标签
features_columns = columns.delete(len(columns)-1)
features = credit_cards[features_columns]
labels = credit_cards['Class']
features_train,features_test,labels_train,labels_test = train_test_split(features,labels,test_size=0.3,random_state=0)
oversampler = SMOTE(random_state=0)
os_features,os_labels = oversampler.fit_sample(features_train,labels_train)
os_features = pd.DataFrame(os_features)
os_labels = pd.DataFrame(os_labels)
best_c = printing_Kfold_scores(os_features,os_labels)

正则化力度: 0.01

Iteration 0 召回率 = 0.9142857142857143
Iteration 1 召回率 = 0.88
Iteration 2 召回率 = 0.9716742539200809
Iteration 3 召回率 = 0.9622520632607685
Iteration 4 召回率 = 0.9619380205258331

平均召回率 0.9380300103984794

正则化力度: 0.1

Iteration 0 召回率 = 0.9142857142857143
Iteration 1 召回率 = 0.88
Iteration 2 召回率 = 0.9729135053110773
Iteration 3 召回率 = 0.9640986345421885
Iteration 4 召回率 = 0.9640483877045989

平均召回率 0.9390692483687157

正则化力度: 1

Iteration 0 召回率 = 0.9142857142857143
Iteration 1 召回率 = 0.88
Iteration 2 召回率 = 0.9730146686899342
Iteration 3 召回率 = 0.9643749921489316
Iteration 4 召回率 = 0.9643121836019446

平均召回率 0.9391975117453051

正则化力度: 10

Iteration 0 召回率 = 0.9142857142857143
Iteration 1 召回率 = 0.88
Iteration 2 召回率 = 0.9730652503793626
Iteration 3 召回率 = 0.9641111962515859
Iteration 4 召回率 = 0.9642116899267652

平均召回率 0.9391347701686857

正则化力度: 100

Iteration 0 召回率 = 0.9142857142857143
Iteration 1 召回率 = 0.88
Iteration 2 召回率 = 0.97298937784522
Iteration 3 召回率 = 0.9644252389865213
Iteration 4 召回率 = 0.9608828369364503

平均召回率 0.9385166336107812


效果最好的模型所选参数 = 1.0


14.过采样结果

lr = LogisticRegression(C = best_c,penalty = 'l1',solver='liblinear')
lr.fit(os_features,os_labels.values.ravel())
y_pred = lr.predict(features_test.values)
# 计算混淆矩阵
cnf_matrix = confusion_matrix(labels_test,y_pred)
np.set_printoptions(precision=2)
print('召回率: ',cnf_matrix[1,1]/(cnf_matrix[1,0]+cnf_matrix[1,1]))
# 绘制
class_names = [0,1]
plt.figure()
plot_confusion_matrix(cnf_matrix,classes = class_names,title = 'Confusion matrix')

召回率: 0.8843537414965986

15.项目总结
项目总结
(1)在此项目中,我们首选对数据进行了观察,发现了其中样本不均衡的问题,其实我们做任务工作之前都一定要先进行数据检查,看看数据有什么问题,针对这些问题来选择解决方案。

(2)这里我们提出了两种方法,下采样和过采样,两条路线来进行对比实验,任何实际问题来了之后,我们都不会一条路走到黑的,没有对比就没有伤害,通常都会得到一个基础模型,然后对各种方法进行对比,找到最合适的,所以在任务开始之前,一定得多动脑筋多一手准备,得到的结果才有可选择的余地。

(3)在建模之前,需要对数据进行各种预处理的操作,比如数据标准化,缺失值填充等,这些都是必要操作,由于数据本身已经给定了特征,此处我们还没有提到特征工程这个概念,后续实战中我们会逐步引入,其实数据预处理的工作是整个任务中最为最重也是最苦的一个阶段,数据处理的好不好对结果的影响是最大的。

(4)先选好评估方法,再进行建模。建模的目的就是为了得到结果,但是我们不可能一次就得到最好的结果,肯定要尝试很多次,所以一定得有一个合适的评估方法,可以用这些通用的,比如Recall,准确率等,也可以根据实际问题自己指定评估指标。

(5)选择合适的算法,这里我们使用的是逻辑回归,也详细分析了其中的细节,这是因为我们刚刚讲解完逻辑回归的原理就拿它来练手了,之后我们还会讲解其他算法,并不一定非要用逻辑回归来完成这个任务,其他算法可能效果会更好。但是有一点我希望大家能够理解就是在机器学习中并不是越复杂的算法越实用,恰恰相反,越简单的算法反而应用的越广泛。逻辑回归就是其中一个典型的代表了,简单实用,所以任何分类问题都可以把逻辑回归当做一个待比较的基础模型了。

(6)模型的调参也是很重要的,之前我们通过实验也发现了不同的参数可能会对结果产生较大的影响,这一步也是必须的,后续实战内容我们还会来强调调参的细节,这里就简单概述一下了。对于参数我建立大家在使用工具包的时候先看看其API文档,知道每一个参数的意义,再来实验选择合适的参数值。

(7)得到的结果一定要和实际任务结合在一起,有时候虽然得到的结果指标还不错,但是实际应用却成了问题,所以测试环节也是必不可少的。到此,这个项目就给大家介绍到这里了,在实践中学习才能成长的更快,建议大家一定使用提供的Notebook代码文件来自己完成一遍上述操作。

声明:代码notebook来自唐宇迪机器学习课程,由于sklearn版本问题,可能有些不一致。

唐宇迪机器学习课程笔记:逻辑回归之信用卡检测任务相关推荐

  1. 唐宇迪机器学习课程数据集_最受欢迎的数据科学和机器学习课程-2020年8月

    唐宇迪机器学习课程数据集 There are a lot of great online resources and websites on data science and machine lear ...

  2. 唐宇迪机器学习之离职预测

    最近在看唐宇迪机器学习视频,这个视频我觉得很不错,可是我资源有限,有的视频没有配套的资料.数据集或者是代码,但还是可以看视频了解其中的一些知识点. 项目介绍 该项目是通过员工对公司的满意程度.公司对员 ...

  3. 唐宇迪机器学习实战课程笔记(全)

    1. 线性回归 1.1线性回归理论 1.2线性回归实战 2.训练调参基本功(线性回归.岭回归.Lasso回归) 2.1 线性回归模型实现 2.2不同GD策略对比 2.3多项式曲线回归 2.4过拟合和欠 ...

  4. 唐宇迪​​机器学习实战——梯度下降求解逻辑回归(理论基础+源代码实现)

    问题的提出 符号问题,这里的lg就是指log2,你的理解是正确的!在计算机科学中有些符号的使用跟我们在数学中使用的有区别.比如有时候log用来表示自然对数(以e为底数).希望对你有帮助! 首先计算机科 ...

  5. python画一片树叶的故事_《Python数据分析与机器学习实战-唐宇迪》读书笔记第7章--决策树...

    第7章决策树 决策树算法是机器学习中最经典的算法之一.大家可能听过一些高深的算法,例如在竞赛中大杀四方的Xgboost.各种集成策略等,其实它们都是基于树模型来建立的,掌握基本的树模型后,再去理解集成 ...

  6. python数据项目分析实战技法_《Python数据分析与机器学习实战-唐宇迪》读书笔记第9章--随机森林项目实战——气温预测(1/2)...

    第9章--随机森林项目实战--气温预测(1/2) 第8章已经讲解过随机森林的基本原理,本章将从实战的角度出发,借助Python工具包完成气温预测任务,其中涉及多个模块,主要包含随机森林建模.特征选择. ...

  7. python天气数据分析论文_《Python数据分析与机器学习实战-唐宇迪》读书笔记第9章--随机森林项目实战——气温预测(2/2)...

    第9章--随机森林项目实战--气温预测(2/2) 第8章已经讲解过随机森林的基本原理,本章将从实战的角度出发,借助Python工具包完成气温预测任务,其中涉及多个模块,主要包含随机森林建模.特征选择. ...

  8. YOLO-V4 论文学习+唐宇迪博士课程学习笔记

    论文主要贡献: 1.利用单GPU即可训练一个目标检测器. 2.验证了Bag-of-Freebies 和 Bag-of-Specials方法在训练目标检测器当中的作用. 3.对包括CBN.PAN.SAM ...

  9. B站 唐宇迪 深度学习笔记

    笔记请移步深度学习 飞书笔记

最新文章

  1. 中国首篇Science机器人子刊!北航软体机器人实验室四年成果登上封面长篇
  2. 软件工程项目组Z.XML会议记录 2013/09/18
  3. 阿里mysql数据库同步_如何对MySQL数据库中的数据进行实时同步-阿里云开发者社区...
  4. 小学计算机课程表说课稿,小学信息技术《制作课程表》说课稿.doc
  5. draw graph using gnuplot
  6. POJ1015-Jury Compromise【01背包,dp】
  7. 1200兆路由器网速_如何选购路由器才能发挥宽带的网速?
  8. Java Long类shortValue()方法与示例
  9. wav文件头损坏_Dex文件结构学习
  10. 蛮力法在查找算法中的应用(JAVA)--顺序查找
  11. 哈希表取模选择素数分析
  12. 陕西卫视《关中男人》观后感--女人之后是男人?
  13. kafka的版本问题
  14. ASP.NET实现数据采集
  15. CPU为什么不做成圆的而是方的?
  16. 第四十七节,random 随机数模块
  17. 单点登录sso原理及代码实现
  18. CC2500模块移植说明
  19. SpringBoot接入Ueditor编辑器
  20. 保存numpy数组到excel

热门文章

  1. 【程序人生】 看到商汤集团的招聘简章,感觉自己弱爆了
  2. 浅谈分布式、SOA与微服务
  3. 超级网管员——网络应用
  4. Bliface借区块链定义视频网站3.0
  5. 使用mapinfo软件的在线地图插件运行错误解决
  6. lombok 基础注解之 @NonNull
  7. [附源码]JAVA+ssm计算机毕业设计餐厅订餐系统(程序+Lw)
  8. 一文读懂Spring Cloud底层原理
  9. mkstemp函数应用
  10. 计算机网络老师评语,计算机老师给学生的评语