一文梳理金融风控建模全流程(Python)-程序员宅基地

技术标签: python  数据分析  机器学习  人工智能  大数据  

一、信贷风控简介

信贷风控是数据挖掘算法最成功的应用之一,这在于金融信贷行业的数据量很充足,需求场景清晰及丰富。

信贷风控简单来说就是判断一个人借了钱后面(如下个月的还款日)会不会按期还钱。更专业来说,信贷风控是还款能力及还款意愿的综合考量,根据这预先的判断为信任依据进行放贷,以此大大提高了金融业务效率。d0e967ea2c246a413b3d88bf1f1bbe2e.png

与其他机器学习的工业场景不同,金融是极其厌恶风险的领域,其特殊性在于非常侧重模型的解释性及稳定性。业界通常的做法是基于挖掘多维度的特征建立一套可解释及效果稳定的规则及风控模型对每笔订单/用户/行为做出判断决策。

其中,对于(贷前)申请前的风控模型,也称为申请评分卡--A卡。A卡是风控的关键模型,业界共识是申请评分卡可以覆盖80%的信用风险。此外还有贷中行为评分卡B卡、催收评分卡C卡,以及反欺诈模型等等。

A卡(Application score card)。目的在于预测申请时(申请信用卡、申请贷款)对申请人进行量化评估。B卡(Behavior score card)。目的在于预测使用时点(获得贷款、信用卡的使用期间)未来一定时间内逾期的概率。C卡(Collection score card)。目的在于预测已经逾期并进入催收阶段后未来一定时间内还款的概率。f3760aeabfc2954bff7c298ac4a6c3ea.png

一个好的特征,对于模型和规则都是至关重要的。像申请评分卡--A卡,主要可以归到以下3方面特征:

  • 1、信贷历史类:信贷交易次数及额度、收入负债比、查询征信次数、信贷历史长度、新开信贷账户数、额度使用率、逾期次数及额度、信贷产品类型、被追偿信息。(信贷交易类的特征重要程度往往是最高的,少了这部分历史还款能力及意愿的信息,风控模型通常直接就废了。)

  • 2、基本资料及交易记录类:年龄、婚姻状况、学历、工作类型及年薪、工资收入、存款AUM、资产情况、公积金及缴税、非信贷交易流水等记录(这类主要是从还款能力上面综合考量的。还可以结合多方核验资料的真伪以及共用像手机号、身份证号等团伙欺诈信息,用来鉴别欺诈风险。需要注意的,像性别、肤色、地域、种族、宗教信仰等类型特征使用要谨慎,可能模型会有效果,但也会导致算法歧视问题。)

  • 3、公共负面记录类:如破产负债、民事判决、行政处罚、法院强制执行、涉赌涉诈黑名单等(这类特征不一定能拿得到数据,且通常缺失度比较高,对模型贡献一般,更多的是从还款意愿/欺诈维度的考虑)

二、申请评分卡(A卡)全流程

实战部分我们以经典的申请评分卡为例,使用的中原银行个人贷款违约预测比赛的数据集,使用信用评分python库--toad、树模型Lightgbm及逻辑回归LR做申请评分模型。(注:文中所涉及的一些金融术语,由于篇幅就不展开解释了,疑问之处 可以谷歌了解下哈。)

2.1 模型定义

申请评分模型定义主要是通过一系列的数据分析确定建模的样本及标签。

首先,补几个金融风控的术语的说明。概念模糊的话,可以回查再理解下: 

逾期期数(M) :指实际还款日与应还款日之间的逾期天数,并按区间划分后的逾期状态。M取自Month on Book的第一个单词。(注:不同机构所定义的区间划分可能存在差异) M0:当前未逾期(或用C表示,取自Current) M1:逾期1-30日 M2:逾期31-60日 M3:逾期61-90日 M4:逾期91-120日 M5:逾期121-150日 M6:逾期151-180日 M7+:逾期180日以上

观察点:样本层面的时间窗口。 用于构建样本集的时间点(如2010年10月申请贷款的用户),不同环节定义不同,比较抽象,这里举例说明:如果是申请模型,观察点定义为用户申贷时间,取19年1-12月所有的申贷订单作为构建样本集;如果是贷中行为模型,观察点定义为某个具体日期,如取19年6月15日在贷、没有发生逾期的申贷订单构建样本集。

观察期:特征层面的时间窗口。构造特征的相对时间窗口,例如用户申请贷款订前12个月内(2009年10月截至到2010年10月申请贷款前的数据都可以用, 可以有用户平均消费金额、次数、贷款次数等数据特征)。设定观察期是为了每个样本的特征对齐,长度一般根据数据决定。一个需要注意的点是,只能用此次申请前的特征数据,不然就会数据泄露(时间穿越,用未来预测过去的现象)。

表现期:标签层面的时间窗口。定义好坏标签Y的时间窗口,信贷风险具有天然的滞后性,因为用户借款后一个月(第一期)才开始还钱,有得可能还了好几期才发生逾期。

932ae7d8e3c5ed6856fc8654c75d7552.png

对于现成的比赛数据,数据特征的时间跨度(观察期)、数据样本、标签定义都是已经提前分析确定下来的。但对于实际的业务来说,数据样本及模型定义其实也是申请评分卡的关键之处。毕竟实际场景里面可能没有人扔给你现成的数据及标签(好坏定义,有些公司的业务会提前分析好给建模人员),然后只是跑个分类模型那么简单。

确定建模的样本量及标签,也就是模型从多少的数据样本中学习如何分辨其中的好、坏标签样本。如果样本量稀少、标签定义有问题,那学习的结果可想而知也会是差的。

对于建模样本量的确定,经验上肯定是满足建模条件的样本越多越好,一个类别最好有几千以上的样本数。但对于标签的定义,可能我们直观感觉是比较简单,比如“好用户就是没有逾期的用户, 坏用户就是在逾期的用户”,但具体做量化起来会发现并不简单,有两个方面的主要因素需要考量:

  • 【坏的定义】逾期多少天算是坏客户。比如:只逾期2天算是建模的坏客户?

根据巴塞尔协议的指导,一般逾期超过90天(M4+)的客户,即定义为坏客户。更为通用的,可以使用“滚动率”分析方法(Roll Rate Analysis)确定多少天算是“坏”,基本方法是统计分析出逾期M期的客户多大概率会逾期M+1期(同样的,我们不太可能等着所有客户都逾期一年才最终确定他就是坏客户。一来时间成本太高,二来这数据样本会少的可怜)。如下示例,我们通过滚动率分析各期逾期的变坏概率。当前未逾期(M0)下个月保持未逾期的概率99.71%;当前逾期M1,下个月继续逾期概率为54.34%;当前M2下个月继续逾期概率就高达*90.04%*。我们可以看出M2是个比较明显的变坏拐点,可以以M2+作为坏样本的定义。59fbb5999e8993adaacf8ab65fa0c957.png

  • 【表现期】借贷申请的时间点(即:观察点)之后要在多久的时间暴露表现下,才能比较彻底的确定客户是否逾期。比如:借贷后观察了一个客户借贷后60天的那几个分期的表现都是按时还款,就可以判断他是好/坏客户?

这也就是确定表现期,常用的分析方法是Vintage分析(Vintage在信贷领域不仅可以用它来评估客户好坏充分暴露所需的时间,即成熟期,还可以用它分析不同时期风控策略的差异等),通过分析历史累计坏用户暴露增加的趋势,来确定至少要多少期可以比较全面的暴露出大部分的坏客户。如下示例的坏定义是M4+,我们可以看出各期的M4+坏客户经过9或者10个月左右的表现,基本上可以都暴露出来,后面坏客户的总量就比较平稳了。这里我们就可以将表现期定位9或者10个月~73aa4501960266a59d64f225815f495b.png

确定了坏的定义以及需要的表现期,我们就可以确定样本的标签,最终划定的建模样本:

  • 好用户:表现期(如9个月)内无逾期的用户样本。

  • 坏用户:表现期(如9个月)内逾期(如M2+)的用户样本。

  • 灰用户:表现期内有过逾期行为,但不到坏定义(如M2+)的样本。注:实践中经常会把只逾期3天内的用户也归为好用户。

比如现在的时间是2022-10月底,表现期9个月的话,就可以取2022-01月份及之前申请的样本(这也称为 观察点),打上好坏标签,建模。

通过上面信用评分的介绍,很明显的好用户通常远大于坏用户的,这是一个类别极不均衡的典型场景,不均衡处理方法下文会谈到。4f8e3118f721afb0c647eac85b1fa1d5.png

2.2 读取数据及预处理

本数据集的数据字典文档、比赛介绍及本文代码,可以到https://github.com/aialgorithm/Blog项目相应的代码目录下载2ca8a42527832d17a42c266af1a7d549.png

该数据集为中原银行的个人贷款违约预测数据集,个别字段有做了脱敏(金融的数据大都涉及机密)。主要的特征字段有个人基本信息、经济能力、贷款历史信息等等91e815422e0a7bc72853484bf6c7954f.png数据有10000条样本,38维原始特征,其中isDefault为标签,是否逾期违约。

c977709fc3bc9c9b40844925b59dfc65.png
import pandas as pd
pd.set_option("display.max_columns",50)

train_bank = pd.read_csv('./train_public.csv')

print(train_bank.shape)
train_bank.head()

数据预处理主要是对日期信息、噪音数据做下处理,并划分下类别、数值类型的特征。

# 日期类型:issueDate 转换为pandas中的日期类型,加工出数值特征
train_bank['issue_date'] = pd.to_datetime(train_bank['issue_date'])
# 提取多尺度特征
train_bank['issue_date_y'] = train_bank['issue_date'].dt.year
train_bank['issue_date_m'] = train_bank['issue_date'].dt.month
# 提取时间diff # 转换为天为单位
base_time = datetime.datetime.strptime('2000-01-01', '%Y-%m-%d')   # 随机设置初始的基准时间
train_bank['issue_date_diff'] = train_bank['issue_date'].apply(lambda x: x-base_time).dt.days
# 可以发现earlies_credit_mon应该是年份-月的格式,这里简单提取年份
train_bank['earlies_credit_mon'] = train_bank['earlies_credit_mon'].map(lambda x:int(sorted(x.split('-'))[0]))
train_bank.head()


# 工作年限处理
train_bank['work_year'].fillna('10+ years', inplace=True)

work_year_map = {'10+ years': 10, '2 years': 2, '< 1 year': 0, '3 years': 3, '1 year': 1,
     '5 years': 5, '4 years': 4, '6 years': 6, '8 years': 8, '7 years': 7, '9 years': 9}
train_bank['work_year']  = train_bank['work_year'].map(work_year_map)

train_bank['class'] = train_bank['class'].map({'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6})

# 缺失值处理
train_bank = train_bank.fillna('9999')

# 区分 数值 或类别特征

drop_list = ['isDefault','earlies_credit_mon','loan_id','user_id','issue_date']
num_feas = []
cate_feas = []

for col in train_bank.columns:
    if col not in drop_list:
        try:
            train_bank[col] = pd.to_numeric(train_bank[col]) # 转为数值
            num_feas.append(col)
        except:
            train_bank[col] = train_bank[col].astype('category')
            cate_feas.append(col)
            
print(cate_feas)
print(num_feas)

2.3 lightgbm评分卡建模

如果是用Lightgbm建模做违约预测,简单的数据处理,基本上代码就结束了。lgb树模型是集成学习的强模型,自带缺失、类别变量的处理,特征上面不用做很多处理,建模非常方便,模型效果通常不错,还可以输出特征的重要性。

(By the way,申请评分卡业界用逻辑回归LR会比较多,因为模型简单,解释性也比较好)。

def model_metrics(model, x, y):
    """ 评估 """
    yhat = model.predict(x)
    yprob = model.predict_proba(x)[:,1]
    fpr,tpr,_ = roc_curve(y, yprob,pos_label=1)
    metrics = {'AUC':auc(fpr, tpr),'KS':max(tpr-fpr),
               'f1':f1_score(y,yhat),'P':precision_score(y,yhat),'R':recall_score(y,yhat)}
    
    roc_auc = auc(fpr, tpr)

    plt.plot(fpr, tpr, 'k--', label='ROC (area = {0:.2f})'.format(roc_auc), lw=2)

    plt.xlim([-0.05, 1.05])  # 设置x、y轴的上下限,以免和边缘重合,更好的观察图像的整体
    plt.ylim([-0.05, 1.05])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')  # 可以使用中文,但需要导入一些库即字体
    plt.title('ROC Curve')
    plt.legend(loc="lower right")


    return metrics
# 划分数据集:训练集和测试集
train_x, test_x, train_y, test_y = train_test_split(train_bank[num_feas + cate_feas], train_bank.isDefault,test_size=0.3, random_state=0)

# 训练模型
lgb=lightgbm.LGBMClassifier(n_estimators=5,leaves=5, class_weight= 'balanced',metric = 'AUC')
lgb.fit(train_x, train_y)
print('train ',model_metrics(lgb,train_x, train_y))
print('test ',model_metrics(lgb,test_x,test_y))
4414def077588a501eee938584af00ce.png
from lightgbm import plot_importance
plot_importance(lgb)
6198fa03d54ca2f80651f024bd9997da.png

2.4 LR评分卡建模

LR即逻辑回归,是一种广义线性模型,因为其模型简单、解释性良好,在金融行业是最常用的。

也正因为LR过于简单,没有非线性能力,所以我们往往需要通过比较复杂的特征工程,如分箱WOE编码的方法,提高模型的非线性能力。关于LR的原理及优化方法,强烈推荐阅读下:

下面我们通过toad实现特征分析、特征选择、特征分箱及WOE编码

2.4.1 特征选择
# 数据EDA分析
toad.detector.detect(train_bank)

# 特征选择,根据相关性 缺失率、IV 等指标
train_selected, dropped = toad.selection.select(train_bank,target = 'isDefault', empty = 0.5, iv = 0.05, corr = 0.7, return_drop=True, exclude=['earlies_credit_mon','loan_id','user_id','issue_date'])
print(dropped)
print(train_selected.shape)

# 划分训练集 测试集
train_x, test_x, train_y, test_y = train_test_split(train_selected.drop(['loan_id','user_id','isDefault','issue_date','earlies_credit_mon'],axis=1), train_selected.isDefault,test_size=0.3, random_state=0)

2.4.2 卡方分箱

# 特征的卡方分箱
combiner = toad.transform.Combiner()

# 训练数据并指定分箱方法

combiner.fit(pd.concat([train_x,train_y], axis=1), y='isDefault',method= 'chi',min_samples = 0.05,exclude=[])

# 以字典形式保存分箱结果

bins = combiner.export()

bins

通过特征分箱,每一个特征被离散化为各个分箱。67dad28a09411812c3bda66344c23e95.png

接下来就是LR特征工程的特色处理了--手动调整分箱的单调性。

这一步的意义更多在于特征的业务解释性的约束,对于模型的拟合效果影响不一定是正面的。这里我们主观认为大多数特征的不同分箱的坏账率badrate应该是满足某种单调关系的,而起起伏伏是不太好理解的。如征信查询次数这个特征,应该是分箱数值越高,坏账率越大。(注:如年龄特征可能就不满足这种单调关系)

我们可以查看下ebt_loan_ratio这个变量的分箱情况,根据bad_rate趋势图,并保证单个分箱的样本占比不低于0.05,去调整分箱,达到单调性。(其他的特征可以按照这个方法继续调整,单调性调整还是挺耗时的)

adj_var = 'scoring_low'
#调整前原来的分箱 [560.4545455, 621.8181818, 660.0, 690.9090909, 730.0, 775.0]
adj_bin = {adj_var: [ 660.0, 700.9090909, 730.0, 775.0]}

c2 = toad.transform.Combiner()
c2.set_rules(adj_bin)

data_ = pd.concat([train_x,train_y], axis=1)
data_['type'] = 'train'
temp_data = c2.transform(data_[[adj_var,'isDefault','type']], labels=True)

from toad.plot import badrate_plot, proportion_plot
# badrate_plot(temp_data, target = 'isDefault', x = 'type', by = adj_var)
# proportion_plot(temp_data[adj_var])
from toad.plot import  bin_plot,badrate_plot
bin_plot(temp_data, target = 'isDefault',x=adj_var)
  • 调整前8799e92ba2df97931129de0968b312f0.png

  • 调整后92eb45243175c677fb82fd65f3857d00.png

# 更新调整后的分箱
combiner.set_rules(adj_bin)
combiner.export()
fd58f8ce6806520728be753528293576.png
2.4.3 WOE编码

接下来就是对各个特征的分箱做WOE编码,通过WOE编码给各个分箱不同的权重,提升LR模型的非线性。

#计算WOE,仅在训练集计算WOE,不然会标签泄露
transer = toad.transform.WOETransformer()
binned_data = combiner.transform(pd.concat([train_x,train_y], axis=1))

#对WOE的值进行转化,映射到原数据集上。对训练集用fit_transform,测试集用transform.
data_tr_woe = transer.fit_transform(binned_data, binned_data['isDefault'],  exclude=['isDefault'])
data_tr_woe.head()

## test woe

# 先分箱
binned_data = combiner.transform(test_x)
#对WOE的值进行转化,映射到原数据集上。测试集用transform.
data_test_woe = transer.transform(binned_data)
data_test_woe.head()
2.4.4 训练LR

使用woe编码后的train数据训练模型。对于金融风控这种极不平衡的数据集,比较常用的做法是做下极少类的正采样或者使用代价敏感学习class_weight='balanced',以增加极少类的学习权重。可见:《一文解决样本不均衡(全)》

对于LR等弱模型,通常会发现训练集与测试集的指标差异(gap)是比较少的,即很少过拟合现象。88ba88a9eba3c053fe120fc398a51fd4.png

# 训练LR模型
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression(class_weight='balanced')
lr.fit(data_tr_woe.drop(['isDefault'],axis=1), data_tr_woe['isDefault'])

print('train ',model_metrics(lr,data_tr_woe.drop(['isDefault'],axis=1), data_tr_woe['isDefault']))
print('test ',model_metrics(lr,data_test_woe,test_y))
2.4.5 评分卡应用

利用训练好的LR模型,输出(概率)分数分布表,结合误杀率、召回率以及业务需要可以确定一个合适分数阈值cutoff (注:在实际场景中,通常还会将概率非线性转化为更为直观的整数分score=A-B*ln(odds),方便评分卡更直观、统一的应用。)

train_prob = lr.predict_proba(data_tr_woe.drop(['isDefault'],axis=1))[:,1]
test_prob = lr.predict_proba(data_test_woe)[:,1]


# Group the predicted scores in bins with same number of samples in each (i.e. "quantile" binning)
toad.metrics.KS_bucket(train_prob, data_tr_woe['isDefault'], bucket=10, method = 'quantile')

当预测这用户的概率大于设定阈值,意味这个用户的违约概率很高,就可以拒绝他的贷款申请。c67d30321858a0875ef6edda208b90b9.png

- END -






往期精彩回顾




适合初学者入门人工智能的路线及资料下载(图文+视频)机器学习入门系列下载中国大学慕课《机器学习》(黄海广主讲)机器学习及深度学习笔记等资料打印《统计学习方法》的代码复现专辑机器学习交流qq群955171419,加入微信群请扫码

c6d94f434f64a7969277f5a215d8930a.png

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/fengdu78/article/details/125353724

智能推荐

jsp数据库中文乱码处理_jsp数据库中检索中文乱码的问题-程序员宅基地

文章浏览阅读1k次。从服务器中JSP文件到浏览器显示页面的步骤为:服务器JSP------>>(告诉服务器JSP文件本身编码)服务器Servlet------>>(告诉out输出流,输出内容的类型是html,并且内容编码是GBK)服务器HTML文件------>>(告诉浏览器,接受到的这个文件是html类型的,并且文件内容的编码是GBK)浏览器HTML文件------>>浏览器解析并显_jsp数据库中检索中文乱码的问题

Redis事务失效的三种场景_redis事务失败怎么处理-程序员宅基地

文章浏览阅读2.2k次。如果发生这种类型的错误,Redis将向客户端返回包含错误提示信息的响应,同时Redis会清空队列中的命令并取消事务。watch 监控 key 所起的作用实际上是一个乐观锁,它所监控的是在事务期间有没有其他客户端对所监控的值进行修改。在事务提交之前,客户端执行的命令缓存(队列)失败,比如命令的语法错误(命令参数个数错误,不支持的命令等等)。事务提交后开始顺序执行命令,之前缓存在队列中的命令有可能执行失败。由于乐观锁失败,事务提交时将丢弃之前缓存的所有命令序列。最后发现事务里语句失效。最后发现事务里语句失效。_redis事务失败怎么处理

Shell脚本中获取uci配置文件参数_config_foreach-程序员宅基地

文章浏览阅读3.3k次。/lib/function.sh函数其中定义的主要函数功能如下:_config_foreach

vue路由中设置滚动行为(scrollBehavior)_vue 路由 scrollbehavior-程序员宅基地

文章浏览阅读1.6w次,点赞5次,收藏27次。 在文档页面(http://localhost:8080/document)拉动滚动条,然后刷新浏览器会发现滚动条依然在原来的位置,这是浏览器的默认行为,会记录浏览器滚动条默认位置。 但是点击浏览器“前进/后退”按钮,会发现当初那个页面的滚动条从0开始了,没有记录上一次滚动条的位置。现在要求点击浏览器“前进/后退”按钮,页面滚动条要记录上一次的位置,这时需要设置它的的滚动行为。 ..._vue 路由 scrollbehavior

CodeForces - 1401D - Maximum Distributed Tree (贪心 + 树上dfs)_codeforces maximum distributed tree-程序员宅基地

文章浏览阅读3.2k次。Maximum Distributed Tree题意为一棵树的边添加权值 要求如下权值大于 000所有边权值之积等于 kkk边权值中 111 的个数尽可能少kkk 以质因数分解的形式给出求∑i=1n−1∑j=i+1nf(i,j)\sum\limits_{i=1}^{n-1} \sum\limits_{j=i+1}^n f(i,j)i=1∑n−1​j=i+1∑n​f(i,j)的值最大是多少 其中 f(u,v)f(u,v)f(u,v) 表示从 uuu 到 vvv 的简单路径上边的权值之和思路_codeforces maximum distributed tree

JavaScript 图片时间效果_js时间图片-程序员宅基地

文章浏览阅读484次。<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>pic timer</title></head><body><!-- 图片路径改成自己的路径 --><img src="../images/0.png" id="h_pic1"><img src="../images._js时间图片

随便推点

AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation Framework-程序员宅基地

文章浏览阅读556次。本技术报告介绍了一种新的框架AutoGen,它可以使用多个代理来开发LLM应用程序,这些代理可以相互对话以解决任务。AutoGen代理是可定制的、可对话的,并且无缝地允许人类参与。它们可以在各种模式下运行,这些模式采用LLM、人工输入和工具的组合。AutoGen的设计提供了多种优势:a)它优雅地驾驭了这些LLM强大但不完美的生成和推理能力;b) 它利用人类的理解和智慧,同时通过代理之间的对话提供有价值的自动化;c) 它简化并统一了作为自动化代理聊天的复杂LLM工作流的实现。_autogen: enabling next-gen llm applications via multi-agent conversation

C语言实现文件字符替换_文件中的字符替换代码c-程序员宅基地

文章浏览阅读5.7k次,点赞4次,收藏8次。C语言标准路为我们提供了文件操作函数:包含:fopen()/fclose() //文件打开与关闭函数;(参数与返回类型省略) fgetc()/fputc() //从流中获取字符,向文件流中写入字符; getc()/putc() //与fgetc()/fputc()等价,不同_文件中的字符替换代码c

pandas datetime数据类型_parse_dates=['timestamp']是什么类型-程序员宅基地

文章浏览阅读2.6k次。datetime 数据类型学习目标应用Pandas来处理日期时间类型数据1 Python的datetime对象Python内置了datetime对象,可以在datetime库中找到from datetime import datetimenow = datetime.now()now显示结果:datetime.datetime(2020, 6, 17, 19, 47, 56, 965416)还可以手动创建datetimet1 = datetime.now()t2 _parse_dates=['timestamp']是什么类型

Handler总结常用方法及常见问题_handler常见方法-程序员宅基地

文章浏览阅读1k次。先庆祝一下终于放假啦,要升大三啦,痛苦的期末考试过去啦。。。。。 一、handler可以发送Message对象和Runnable对象到线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程), Handler中分发消息的一些方法 post(Runnable) postAtTime(Runnable,long) postDelayed(Runnab_handler常见方法

ubuntu20.04 安装pcl Vtk步骤和ERROR等问题_ubuntu安装vtk和pcl-程序员宅基地

文章浏览阅读405次,点赞8次,收藏9次。但是安装完还是有问题,是因为上面安装qt少安了一个叫X11EXtra的库,然后再configure,就可以了。1.ERROR CONFIG:因为要安装qt5;_ubuntu安装vtk和pcl

黑马程序员 – 开始报名! -- 2013.1.16_黑马程序员怎么报名-程序员宅基地

文章浏览阅读338次。----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------复习完正则表达式,终于要开始走黑马报名的流程了,好激动!学过一遍反过来思索,有些知识点已经忘记了,这几天把毕老师的重点视频看了一遍,希望入学能顺利!2013年1月17日,终于把基础测试提交上去了,看过毕老师的视屏后,基础测试做起来不算吃力,加油!第六道测试题_黑马程序员怎么报名

推荐文章

热门文章

相关标签