kivy部署移动端预测模型记录
之所以选择kivy作为移动端的语言,本人是先了解的python,然后才来学习kivy,是看中了python的数据处理能力和施行机器学习算法的能力,kivy与python无缝结合,或许是优于其他类似的语言。
架构(kv部分,python部分,APP部分如何组织
目前采用的一个架构是:
from kv.lang.builder import Builder
#第一部分: kv部分,其中构建了一个尖括号包裹的Widget, 尖括号包裹的widget在kv中被认为是'"root"widget.
Builder.load_string("""
<MenuScreen>:#主页
name:'menu'
BoxLayout:
orientation:'vertical'
ActionBar:
id:bar
ActionView:
ActionPrevious:
title:'慢性疾病'
font_name:"Droid"
markup:True
with_previous:False
app_icon:'logo.png'
ActionButton:
text:"遇病一测,防微杜渐"
font_name:"Droid"
Accordion:
orientation:'vertical'
AccordionItem:
title:"常见问题问答"
collapse:False
GridLayout:
cols:1
canvas:
Color:
rgb:1,1,0.8
Rectangle:
pos:self.pos
size:self.size
ScrollView:
do_scroll_x:False
do_scroll_y:True
Label:
size_hint_y:None
text:root.txt
font_name:"Droid"
color: 0,0.2,0.4,1
markup:True
height:self.texture_size[1]
text_size:self.width, None
line_height:1.2
# padding_x:2
valign: 'center'
AccordionItem:
title:"糖尿病、冠心病、卒中"
GridLayout:
cols:3
pos_hint: {"center_x": .5, "center_y": .5}
row_force_default:True
row_default_height:200
padding_y:10
canvas:
Color:
rgb:0.6,0.8,0.2
Rectangle:
pos:self.pos
size:self.size
Button:
text:'2型糖尿病肾病'
on_press:root.manager.current='screen1'
# background_normal:''
# background_color:(0,0.6,1,1)
Button:
text:"2型糖尿病脑卒中"
on_press:root.manager.current='screen2'
Button:
text:"2型糖尿病"
on_press:root.manager.current='screen4'
Button:
text:"冠心病"
on_press:root.manager.current='screen5'
Button:
text:"卒中"
on_press:root.manager.current='screen7'
Button:
text:'认知功能障碍'
on_press:root.manager.current='screen8'
<screen1>: #与主页并列
name:'screen1'
BoxLayout:
orientation:'vertical'
ActionBar:
id:bar
ActionView:
ActionPrevious:
title:'2型糖尿病肾病'
font_name:"Droid"
markup:True
app_icon:'logo.png'
with_previous:True
on_press:root.manager.current="menu"
TabbedPanel:
id:tp
do_default_tab:False
canvas.before:
Color:
rgb:0.4,0.4,0.6
Rectangle:
pos:self.pos
size:self.size
TabbedPanelItem:
text:"ID31865340"
font_name:"Droid"
# border:'off'
GridLayout:
cols:1
padding: '10dp'
spacing:'10dp'
canvas.before:
Color:
rgb:0.8,0.8,1
Rectangle:
pos:self.pos
size:self.size
GridLayout:
cols:3
panding:10
DarkLabel:
text:"性别"
ToggleButton:
id:female
text:'女'
group:'gender'
state:'down'
ToggleButton:
id:male
text:"男"
group:'gender'
GridLayout:
cols:4
spacing:10
DarkLabel:
text:"糖尿病病程"
ToggleButton:
id:<5year
text:'<5年'
group:'duration'
state:'down'
ToggleButton:
id:5-10year
text:"5-10年"
group:'duration'
ToggleButton:
id:>10year
text:">10年"
group:'duration'
GridLayout:
cols:3
DarkLabel:
text:"视网膜病变"
ToggleButton:
text:"无"
group:'dr'
state:"down"
ToggleButton:
id:dr_yes
text:'有'
group:'dr'
GridLayout:
cols:4
DarkLabel:
text:"血尿"
ToggleButton:
id:<5num
text:'<5个'
group:'hematuria'
state:'down'
ToggleButton:
id:5-10num
text:"5-10个"
group:'hematuria'
ToggleButton:
id:>10num
text:">10个"
group:'hematuria'
GridLayout:
cols:3
DarkLabel:
text:'贫血'
ToggleButton:
id:anemia_no
text:'否'
group:'anemia'
state:'down'
ToggleButton:
id:anemia_yes
text:'是'
group:'anemia'
GridLayout:
cols:3
DarkLabel:
text:'HbA1c'
ToggleButton:
id:HbA1c_no
text:'<7%'
group:'HbA1c'
state:'down'
ToggleButton:
id:HbA1c_yes
text:'≥7%'
group:'HbA1c'
GridLayout:
cols:3
DarkLabel:
text:'eGFR'
ToggleButton:
id:eGFR_high
text:'≥90ml/min/1.73m2'
group:'gfr'
state:'down'
ToggleButton:
id:eGFR_low
text:'<90ml/min/1.73m2'
group:'gfr'
GridLayout:
cols:4
DarkLabel:
text:"UPE"
ToggleButton:
id:<1g
text:'<1g/24h'
group:'upe'
state:'down'
ToggleButton:
id:1-3g
text:"1-3.5g/24h"
group:'upe'
ToggleButton:
id:>3g
text:">3.5g/24h"
group:'upe'
GridLayout:
cols:3
DarkLabel:
text:"高血压"
ToggleButton:
id:bp_normal
text:'SBP<140且DBP<90'
font_size:15
group:'bp'
state:'down'
ToggleButton:
id:bp_unnormal
text:'SBP≥140或DBP≥90'
font_size:15
group:'bp'
AButton:
text:'计算'
on_state: root.on_press_prob()
pos_hint:{'center_x':.5,'center_y':.5}
size_hint:(0.9,0.9)
Label:
id:prob_label
text:" "
color:(0.4,0.4,0.6,1)
GridLayout:
cols:4
spacing: '10dp'
AButton:
text:'模型信息表'
on_release:root.info_sheet()
pos_hint:{'center_x':.5,'center_y':.5}
AButton:
text:'评价星级:3星'
on_release:root.conclusion()
pos_hint:{'center_x':.5,'center_y':.5}
""")
#第二部分:python 部分, 与一般的python语言类似
class MenuScreen(Screen):
pass
class screen1(Screen):
def on_press_prob(self, *args):
duration1 = self.ids['5-10year'].state
if duration1=="down":
duration_5=1
else:
duration_5=0
duration2=self.ids['>10year'].state
if duration2=='down':
duration_10=1
else:
duration_10=0
sex = self.ids['female'].state
if sex == 'down':
sex_female = 1
else:
sex_female = 0
dr=self.ids['dr_yes'].state
if dr=='down':
dr_yes =1
else:
dr_yes=0
hematuria1=self.ids['>10num'].state
if hematuria1=='down':
hematuria_10 = 1
else:
hematuria_10 = 0
hematuria2=self.ids['5-10num'].state
if hematuria2=='down':
hematuria_5=1
else:
hematuria_5=0
anemia=self.ids['anemia_yes'].state
if anemia=='down':
anemia_yes=1
else:
anemia_yes=0
HbA1c=self.ids['HbA1c_yes'].state
if HbA1c=='down':
hba1c=1
else:
hba1c=0
gfr=self.ids['eGFR_low'].state
if gfr=='down':
egfr_90=1
else:
egfr_90=0
upe1=self.ids['>3g'].state
if upe1=='down':
upe_3=1
else:
upe_3=0
upe2=self.ids['1-3g'].state
if upe2=='down':
upe_1=1
else:
upe_1=0
bp=self.ids['bp_unnormal'].state
if bp=='down':
bp_unnormal=1
else:
bp_unnormal=0
list_or = [0.35, 7.46, 2.99, 8.27, 0.15,0.70,3.48,1.43,3.78,2.24,1.76,2.17]
list_para = [sex_female, duration_10, duration_5,dr_yes,hematuria_10,hematuria_5,anemia_yes,hba1c,bp_unnormal,upe_3,upe_1,egfr_90]
intercept = 0.017
model=ev.logistic(ls_or=list_or,ls_xvar=list_para,intercept=intercept)
prob = model.prob()
label = self.ids['prob_label']
label.text = "患者患糖尿病肾病的概率为: " + str(round(prob, 2) * 100) + '%'
#第三部分:APP部分,也是python语言的一部分,但是功能是与其它python部分有不同,可以独立出来作为一个特殊的功能块.
class MPDApp(App):
def build(self):
sm=ScreenManager() #通过这一部分将所有的widget整合整合在一起.
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(screen1(name='screen1'))
return sm
MPDApp().run()
个人认为这个架构比较清晰,当然我的经验还是有限。
遇到的问题及解决
首先是中文支持的问题,如果构建的是手机端的app,那就不要 用雅黑字体(开始用雅黑字体导致在手机上一直不能识别),因为手机不支持,我现在用的是‘Droid-Sans-Fallback.ttf’。
kivy.resources.resource_add_path("./") #字体文件放在了和main.py同样的目录下
# #通过labelBase
LabelBase.register("Droid","Droid-Sans-Fallback.ttf")
kivy.core.text.Label.register("Droid","Droid-Sans-Fallback.ttf")
widget模板
这一部分主要用kv语言来进行书写。
可以通过改写widget来个性化widget,我一般用来支持中文和调整各种背景颜色和大小。
暂时没有对应python 类,或许是因为没有用到复杂的函数功能,有相应心得随时更新。
<DarkLabel@Label>:
font_name:"Droid"#指定字体
color:(0.4,0.4,0.6,1)
size_hint_x: None
width:220
text_size:self.width, None
共同的函数可放在app类中
比如在主页和页面1,有同样一个按钮使用相似的函数,这个函数就可以放在app类中,不用在页面对应的class里面重复写。
buildozer构建APP
操作系统用的是ubuntu系统(windows7+虚拟机)
一定要安装adb。一是方便检查app不成功时哪里出错,个人有好几次app闪退的情况, 就是靠adb检查出的原因;二是builder构建app时,如果连有手机,可以将app直接推送到手机上安装。