Titantic乘客生还预测数据分析报告—基于python实现

  • 1. 问题提出
  • 2. 数据描述
  • 3. 特征独立分析
  • 4. 数据处理
  • 5. 模型评估

1. 问题提出

Titantic数据集是Kaggle(www.kaggle.com)上的一个非常基本的数据集,其中记录了泰坦尼克号沉船事件中部分乘客的信息和生还记录。虽然在生存和死亡面前人人应该享有平等权利,但实际上,当灾难来临时,一些乘客往往会有着更高的生存机会,比如妇女、小孩和富人阶级。乘客所携带的特征是否能够影响,以及如何影响他们的生存机会,可以通过机器学习进行数据分析。

2. 数据描述

Titantic数据集包括训练集和测试集,但测试集没有提供乘客生还的标签信息,我们将Kaggle提供的训练集视为初始数据进行分析。

#导入模块
impor numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import BernoulliNB
from sklearn.linear_model import LinearRegression,LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
data=pd.read_csv('E:/Kaggle数据集/Titantic/train.csv')
data.info()  #获取数据信息
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):#   Column       Non-Null Count  Dtype
---  ------       --------------  -----  0   PassengerId  891 non-null    int64  1   Survived     891 non-null    int64  2   Pclass       891 non-null    int64  3   Name         891 non-null    object 4   Sex          891 non-null    object 5   Age          714 non-null    float646   SibSp        891 non-null    int64  7   Parch        891 non-null    int64  8   Ticket       891 non-null    object 9   Fare         891 non-null    float6410  Cabin        204 non-null    object 11  Embarked     889 non-null    object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB

调用数据集的info方法,可知数据集中提供了12个字段,相关含义如下。

字段 含义
PassengerId 乘客Id
Survived 乘客生还情况,1表示生还,0表示死亡
Pclass 船舱等级
Name 姓名
Sex 性别
Age 年龄
SibSp 同乘兄弟姐妹/配偶数目
Parch 乘同父母/小孩数目
Ticket 票号
Fare 票价
Cabin 船舱编号
Embarked 登船港口

这12个字段中,Age有177个缺失值,Cabin有687个缺失值,Embarked有2个缺失值,其他字段的信息是完整的。我们再调用describe方法获取数据中数值字段的统计信息。

data.describe()
PassengerId Survived Pclass Age SibSp Parch Fare
count 891.000000 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000
mean 446.000000 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208
std 257.353842 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429
min 1.000000 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000
25% 223.500000 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400
50% 446.000000 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200
75% 668.500000 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000
max 891.000000 1.000000 3.000000 80.000000 8.000000 6.000000 512.329200

可以发现,乘客的生还率只有38%左右,绝大多数乘客在海难中丧生。乘客的平均年龄在30岁左右,最小不到1岁,最大的达到80岁,而且大部分乘客的年龄低于38岁。另外,超过一半的乘客没有和他们的兄弟姐妹或配偶同乘,超过3/4的乘客没有和他们的父母和小孩同乘。乘客们的平均票价为32.2,而且大部分乘客的票价低于31,表明少数购买高价票的乘客提高了整体的消费水平,而大多数乘客的消费水平是较低的。

3. 特征独立分析

生还情况Survived是目标变量,而其它的字段是与乘客相关的原始的特征变量,我们可以独立分析每个特征和Survived变量的关系,来选择出能够影响乘客生还率的特征作为模型的自变量。

- PassengerId, Name, Ticket
乘客Id和名字是关于乘客的标识,票号是关于船票的标识,直观上可以判断这些标识与乘客的生还率无明显关系,所以PassengerId, Name和Ticket不考虑作为自变量。

- Pclass
Pclass表示船舱等级,有1,2,3三种取值,不同取值的数量如下。

data.Pclass.value_counts()  #统计Pclass字段中不同取值的数目
3    491
1    216
2    184
Name: Pclass, dtype: int64

可知等级为3的船舱对应乘客数最多,利用交叉表获取Pclass中不同取值和Survived取值之间的对应关系。

pd.crosstab(data.Pclass,data.Survived,normalize='index')
Survived 0   1
Pclass
1   0.370370    0.629630
2   0.527174    0.472826
3   0.757637    0.242363

在图表中可以更直观的看到Pclass和Survived之间的关系。

可以发现在Pclass的不同取值下,乘客的存活率有着很大差别,当取1时,乘客的存货率最高,达到63.0%。船舱等级数字越小,相应的等级越高,这意味着富人阶级有更高的生存机会。所以Pclass可以s视为自变量来影响乘客的生还率。

- Sex
Sex分为男性和女性,不同性别对应的存活率和死亡率如下。

pd.crosstab(data.Sex,data.Survived,normalize='index')
Survived 0   1
Sex
female  0.257962    0.742038
male    0.811092    0.188908


女性的生还率明显高于男性,达到74.2%,体现了女士优先的原则。Sex可作为自变量来影响乘客的生还率。

- Age
Titantic数据集中的Age可以视为连续变量,我们对其进行离散化处理,分为[0,10),[10,20),[20,40),[40,60),[60,100)五个区域,并标记为child,teenager,adult,middle(中年),old(老年)五个标签,再观察这五个标签上乘客的生还率情况。

new_age=pd.cut(data.Age,bins=[0,10,20,40,60,100],labels=['child','teenager','adult','middle','old'])  #Age中存在缺失值,后面会处理
pd.crosstab(new_age,data.Survived,normalize='index').plot(kind='bar',stacked='True',color='rg')


可以看到child的生还率较高,体现小孩优先的原则;teenager,adult和middle的生还率差别不大,而且都偏低;老人的生还率是最低的,说明灾难来临时老人的生存机会很小。总体上来说,Age对乘客生还率有一定的影响,可以将其视为自变量进行分析。

- SibSp
Sibsp表示与乘客同乘的兄弟姐妹或配偶的数量,取值分布如下。

data.SibSp.value_counts().plot(kind='bar',color='g',title='SibSp分布')


可见SibSp有0,1,2,3,4,5,8七个取值,考虑到有些取值对应的乘客数目很小,将SibSp离散化为三个部分,0,{1,2},{3,4,5,8},观察这三种情况下的Survived的分布。

new_SibSp=pd.cut(data.SibSp,bins=[0,1,3,9],labels=['0','1-2','>=3'],include_lowest=True,right=False)  #分组
pd.crosstab(new_SibSp,data.Survived,normalize='index').plot(kind='bar',color='rg',stacked=1,width=0.4)


可见具有1至2名同乘的SibSp的乘客有更高的生还率,因为灾难来临时家人的互相帮助能够提高彼此的生存机会,但是大于2名SibSp的乘客生还率很低,可能是由于基数太小而导致的偏差。总体上,SibSp能够影响乘客的生还率,视为自变量特征。

- Parch
Parch表示与乘客同乘的父母或子女的数量,取值分布如下。

data.Parch.value_counts().plot(kind='bar',color='g',title='Parch分布')


可见Parch有0,1,2,3,4,5,6七个取值,考虑到有些取值对应的乘客数目很小,将Parch离散化为三个部分,0,{1,2},{3,4,5,6},观察这三种情况下的Survived的分布。

new_Parch=pd.cut(data.Parch,bins=[0,1,3,7],labels=['0','1-2','>=3'],include_lowest=True,right=False)  #分组
pd.crosstab(new_Parch,data.Survived,normalize='index').plot(kind='bar',color='rg',stacked=1,width=0.4)


可见具有1至2名同乘的Parch的乘客有更高的生还率,但是大于2名Parch的乘客生还率很低,理由和SibSp变量分析类似。总体上,Parch也能够影响乘客的生还率,可视为自变量特征。

- Fare
Fare表示乘客的票价,属于连续变量,利用箱线图分别观察生还和死亡的乘客相应的Fare分布。

sur_fare=data.Fare[data['Survived']==1]
dead_fare=data.Fare[data['Survived']==0]
plt.boxplot((sur_fare,dead_fare),labels=['survive_fare','dead_fare'])
plt.title('不同生存情况的票价分布')
plt.grid()
plt.show()


很明显生存的乘客的bin高于死亡的乘客的bin,说明生存乘客的票价分布在一个较高的水平,这也意味着高Fare的乘客比低Fare的乘客有更大的生存机会,即富人优先。所以,票价能够作为自变量影响乘客的Survived结果。
- Cabin
Cabin表示乘客所在的船舱,该字段中存在大量的缺失项,我们可以认为缺失项传达一种信息,即作为非缺失项(有船舱)的对立面,表示乘客无船舱的信息,这种情况下我们将Cabin离散化为2个值,inCabin表示乘客有船舱,outCabin表示无船舱。此时Cabin字段和Survived的关系如下。

data.Cabin[pd.notnull(data.Cabin)]='inCabin'
data.Cabin[pd.isnull(data.Cabin)]='outCabin'  #此时对原数据的Cabin字段进行了处理
pd.crosstab(data.Cabin,data.Survived,normalize='index')
Survived 0   1
Cabin
inCabin 0.333333    0.666667
outCabin    0.700146    0.299854


可见有船舱的乘客生还率很高,达到66.7%,这可能是因为船舱内的乘客通常是那些消费水平比较高的富人阶级,即体现了富人优先。所以,在考虑有无船舱时,Cabin可以视为自变量特征影响乘客的生还率。

- Embarked
Embarked表示乘客的登船港口,有S,C,Q三种取值,不同取值和Survived关系分布如下。

pd.crosstab(data.Embarked,data.Survived,normalize='index').plot(kind='bar',color='rg',stacked=True,width=0.4)


不同登船港口的生还率存在一定的差别,在C港登船的乘客有着更高的生存机会。实际上,Embarked特征对乘客的生还率不具备很好的解释性,我的理解是在C港登船的乘客之所以生还率高,可能是由于这些乘客中有着较多的小孩、女人或者富人阶级,也就是生还率的提高本质上是由其他特征所引起的,与登船港口并无明显关系。我们可以对该特征保留意见,后续通过模型来比较Embarked是否作为自变量的性能。

4. 数据处理

数据处理包括缺失值的填充,连续变量离散化,非数值变量数值化以及离散变量one_hot 编码。

- 缺失值填充
Age,Cabin和Embarked三个字段中存在缺失值。
对于Age,我们使用乘客年龄的平均值进行填充。

data.loc[pd.isnull(data.Age),'Age']=data.Age.mean()

对于Cabin,缺失值用‘outCabin’表示乘客不在不在船舱内,如第三部分所述。
对于Embarked,缺失值用众数进行填充。

data.Embarked.value_counts()
S    644
C    168
Q     77
Name: Embarked, dtype: int64
data.loc[pd.isnull(data.Embarked),'Embarked']='S'

- 连续变量离散化
实际上,除了对连续变量进行离散化之外,对于取值较多的离散变量我们也进行压缩取值范围的处理。
需要离散化的连续变量有Age和Fare。
对于Age,正如第三部分分析,我们将其分为child,teenager,adult,middle和old五个部分,代码如下:

data.Age=pd.cut(data.Age,bins=[0,10,20,40,60,100],labels=['child','teenager','adult','middle','old'])
data.Age.head(10)
0       adult
1       adult
2       adult
3       adult
4       adult
5       adult
6      middle
7       child
8       adult
9    teenager
Name: Age, dtype: category
Categories (5, object): [child < teenager < adult < middle < old]

对于Fare,我们以票价的平均值作为阈值分为lowFare和highFare两个部分,代码如下:

avefare=data.Fare.mean()
data.Fare=pd.cut(data.Fare,bins=[0,avefare,data['Fare'].max()],include_lowest=True,right=False,labels=['lowFare','highFare'])
data.Fare.head(10)
0     lowFare
1    highFare
2     lowFare
3    highFare
4     lowFare
5     lowFare
6    highFare
7     lowFare
8     lowFare
9     lowFare
Name: Fare, dtype: category
Categories (2, object): [lowFare < highFare]

另外,需要进一步划分的离散变量有SibSp和Parch,这在第三部分也进行了讨论。
对于SibSp,对于它的七个取值0,1,2,3,4,5,8,我们分成三个部分,0仍记为0,{1,2}记为1,其他的记为2,代码如下:

data.SibSp[(data['SibSp']>0)&(data['SibSp']<=2)]=1
data.SibSp[data['SibSp']>2]=2
data.SibSp.head(10)
0    1
1    1
2    0
3    1
4    0
5    0
6    0
7    2
8    0
9    1
Name: SibSp, dtype: int64

对于Parch,对于它的七个取值0,1,2,3,4,5,6,我们也分成三个部分,0仍记为0,{1,2}记为1,其他的记为2,代码如下:

data.Parch[(data['Parch']>0)&(data['Parch']<=2)]=1
data.Parch[data['Parch']>2]=2
data.Parch.head(10)
0    0
1    0
2    0
3    0
4    0
5    0
6    0
7    1
8    1
9    0
Name: Parch, dtype: int64

- 非数值变量数值化
非数值变量有Sex,Fare,Cabin和Embarked。
对于Sex,包括male和female,考虑到female的生还率高,我们用0和1来分别标记male和female。

data.Sex=data.Sex.map({'male':0,'female':1})
data.Sex.head()
0    0
1    1
2    1
3    1
4    0
Name: Sex, dtype: int64

对于Fare,包括lowFare和highFare,考虑到highFare相应的乘客的生还率高,我们用0和1分别标记lowFare和highFare。

data.Fare=data.Fare.map({'lowFare':0,'highFare':1})
data.Fare.head()
0    0
1    1
2    0
3    1
4    0
Name: Fare, dtype: category
Categories (2, int64): [0 < 1]

对于Cabin,包括inCabin和outCabin,考虑到inCabin相应的乘客生还率高,我们用0和1分别标记outCabin和inCabin。

data.Cabin=data.Cabin.map({'outCabin':0,'inCabin':1})
data.Cabin.head()
0    0
1    1
2    0
3    1
4    0
Name: Cabin, dtype: int64

对于Embarked,因为它有三个取值,无法进行0-1编码,我们会在下一步对它进行one_hot 编码实现数值化。

- 离散变量one_hot 编码
经过上述一系列处理后,被选择的特征均已实现离散化,对于取值超过两个的变量,我们通过one_hot 编码为这些变量创建虚拟变量,使得每个特征的取值仅为0和1。这些变量有Pclass,Age,SibSp,Parch和Embarked。

dummy_data=pd.get_dummies(data,columns=['Pclass','Age','SibSp','Parch','Embarked'])
dummy_data.columns
Index(['PassengerId', 'Survived', 'Name', 'Sex', 'Ticket', 'Fare', 'Cabin','Pclass_1', 'Pclass_2', 'Pclass_3', 'Age_child', 'Age_teenager','Age_adult', 'Age_middle', 'Age_old', 'SibSp_0', 'SibSp_1', 'SibSp_2','Parch_0', 'Parch_1', 'Parch_2', 'Embarked_C', 'Embarked_Q', 'Embarked_S'],dtype='object')

5. 模型评估

应用于乘客生还率分析的自变量字段有Pclass,Sex,Age,SibSp,Parch,Fare,Cabin以及Embarked(保留的特征,要通过模型验证其有效性),其中我们对Pclass,Age,SibSp,Parch和Embarked创建虚拟变量,另外,Survived是标签字段。我们可以将这些有效字段的数据提取出来,方便后续实验。

valid_data=dummy_data.loc[:,[ 'Sex', 'Fare', 'Cabin','Pclass_1', 'Pclass_2', 'Pclass_3', 'Age_child', 'Age_teenager','Age_adult', 'Age_middle', 'Age_old', 'SibSp_0', 'SibSp_1', 'SibSp_2','Parch_0', 'Parch_1', 'Parch_2', 'Embarked_C', 'Embarked_Q', 'Embarked_S','Survived']]

按照4:1的比例将有效数据分为训练集和测试集。

X=valid_data.iloc[:,:-1]   #特征信息
y=valid_data.iloc[:,-1]   #标签信息
x_train,x_test,y_train,y_test=train_test_split(X,y,test_size=0.2)

我们使用一些常见的分类模型在处理后的数据集上进行乘客生还预测,并通过模型得分比较不同模型的性能。这些分类模型包括最近邻算法(knn),线性回归(linearRegression),逻辑回归(logisticRegression),伯努利朴素贝叶斯(BernoulliNB),决策树(decisionTree),支持向量机(SVM)和随机森林(randomForest)。当然,这些模型能够在自身不同的参数水平下获得不同的得分,此处我们使用sklearn库中关于这些模型的参数默认值来进行分类,以了解不同模型的性能概况。

models=[('knn',KNeighborsClassifier()),('线性回归',LinearRegression()),('逻辑回归',LogisticRegression()),
('伯努利朴素贝叶斯',BernoulliNB()), ('决策树',DecisionTreeClassifier()),('SVM',SVC()),
('随机森林',RandomForestClassifier())]
for model,clf in models:clf.fit(x_train,y_train)score=clf.score(x_test,y_test)print(model,':',score)
knn : 0.8268156424581006
线性回归 : 0.34022115233339967
逻辑回归 : 0.8044692737430168
伯努利朴素贝叶斯 : 0.7486033519553073
决策树 : 0.7988826815642458
SVM : 0.8156424581005587
随机森林 : 0.8100558659217877

意外的是,最近邻算法knn在处理后的数据集上实现了最佳的预测性能,达到0.826。不考虑Embarked这个特征,我们再来测试一下各个模型的性能。
首先从训练集和测试集的特征数据中移除Embarkd相关的三个虚拟变量,即Embarked_C,Embarked_Q和Embarked_S,代码如下:

x_train=x_train.loc[:,[i for i in x_train.columns if i not in ['Embarked_C','Embarked_Q','Embarked_S']]]
x_test=x_test.loc[:,[i for i in x_train.columns if i not in ['Embarked_C','Embarked_Q','Embarked_S']]]
x_test.columns
Index(['Sex', 'Fare', 'Cabin', 'Pclass_1', 'Pclass_2', 'Pclass_3', 'Age_child','Age_teenager', 'Age_adult', 'Age_middle', 'Age_old', 'SibSp_0','SibSp_1', 'SibSp_2', 'Parch_0', 'Parch_1', 'Parch_2'],dtype='object')

此时再调用各个分类模型:

for model,clf in models:clf.fit(x_train,y_train)score=clf.score(x_test,y_test)print(model,':',score)
knn : 0.8268156424581006
线性回归 : 0.3560219278522567
逻辑回归 : 0.8156424581005587
伯努利朴素贝叶斯 : 0.7374301675977654
决策树 : 0.8100558659217877
SVM : 0.8156424581005587
随机森林 : 0.8379888268156425

最近邻算法knn仍然能够实现最高的预测准确性,而且相较于考虑Embarked这个特征时,预测性能得分没有发生改变,这种情况对于SVM也是如此。此外,在不考虑Embarked这个特征时,除了伯努利朴素贝叶斯的性能略有下降之外,线性回归、逻辑回归、决策树和随机森林模型的性能都有所提升。总的来说,Embarked作为一个解释性不足的特征,对于模型预测能力的提升没有太大改善,相反会干扰对乘客生还率的预测,应该舍弃该特征。
以上就是关于Titantic乘客生还率的一个比较基础的数据分析过程,当然无论是在特征的进一步提取和处理上,还是在模型参数的调整上,关于乘客生还预测性能的提高还有着很大的进步空间,值得我们去细致的探讨和分析。

Titantic乘客生还预测数据分析报告—基于python实现相关推荐

  1. 某策略游戏公测期运营情况分析报告-基于python

    某策略游戏测试阶段运营情况分析报告-基于python 背景 了解数据 字段含义 加载必要的库 读取数据 查看数据类型和数据结构 统计缺失值 删除重复数据 游戏总体情况 注册人数变化 活跃用户数变化 活 ...

  2. python 文件格式转换_数据分析:基于Python的自定义文件格式转换系统

    ( 白宁超 2018年7月16日14:47:41 ) 导读:随着大数据的快速发展,自然语言处理.数据挖掘.机器学习技术应用愈加广泛.针对大数据的预处理工作是一项庞杂.棘手的工作.首先数据采集和存储,尤 ...

  3. 基于python的房地产数据分析_基于Python的数据分析

    转载 | CSDN 编辑 | 雷课小雷 下面来介绍一下基于Python的数据分析,主要介绍数据分析的概念.数据分析流程.Python优势.常用模块的用途以及使用Python进行数据分析的学习方法及步骤 ...

  4. python毕业设计开题报告-基于python爬虫的影评情感分析研究开题报告

    论文(设计)题目 基于python爬虫的影评情感分析研究开题报告 选题的背景.意义及研究现状: 研究现状: 文本情感分析又称倾向性分析.情感挖掘,主观分析或评论挖掘,是对带有情感色彩的评论文本内容进行 ...

  5. Detecting Insults in Social Commentary 数据分析报告(python)

    文章目录 Detecting Insults in Social Commentary 数据分析报告 报告摘要 一.问题描述 二.数据加载 三.文本数据处理 3.1 数据清洗 3.2 停止词处理 3. ...

  6. python毕业设计开题报告-基于Python的教学互动系统的设计与实现开题报告

    基于Python的教学互动系统的设计与实现开题报告 背景: 在各种信息技术与课堂的不断探索中,我们一直在寻找一个能提高教学效率的方式,同时可以发现要提高教学效率,在课堂教学中必不可少的就是师生间的互动 ...

  7. 【数据分析】基于Python的一次职位招聘数据分析(入门参考)

    基于Python的一次职位招聘数据分析 1 Python数据分析常用的库和库函数 2 一次完整的数据分析过程 画图 工作地点处理 工资计量单位统一 公司类型 行业类型 参考 配套资源下载 职位信息分析 ...

  8. 基于python的房地产数据分析_基于Python的数据分析实战项目

    本文中项目资料来源于网易云课堂,代码为纯手工码字滴,请放心食用,不定期更新,欢迎对Python.数据分析以及编程感兴趣的同学留言沟通. 详细介绍了数十个数据分析相关的实战项目,大量使用pandas.n ...

  9. 基于python的数据分析毕业设计-基于python的Web大数据采集和数据分析

    肖乐 丛天伟 严卫 摘要:该设计使用python语言作为开发语言,主要采用了两个框架:Scrapy和Django,用Scrapy来实现数据的采集技术,让数据采集效率更高,错误率低等:用Django来实 ...

最新文章

  1. Tree Reconstruction UVA - 10410
  2. [numpy]random.choice()随机选取内容
  3. 非常精简的Linux线程池实现(一)——使用互斥锁和条件变量
  4. Linux 进程概念
  5. 新加坡推出人工智能计划AI.SG 迎战人工智能和数据科学关键难题
  6. gemm() 与 gesvd() 到矩阵求逆(inverse)(根据 SVD 分解和矩阵乘法求矩阵的逆)
  7. 大数据、云计算和物联网的关系
  8. 矩阵乘法的计算复杂度
  9. C/C++基于MFC的网速监控,一招教你实时监控网速!
  10. 练习3-8 查询水果价格 (15 分)
  11. 【Windows】网线直连实现两台电脑共享文件夹
  12. 基于GoLang的MMO游戏服务器(四)
  13. 某农商行用户画像项目——模型构建部分
  14. 高压蒸汽灭菌及验证相关知识
  15. 85.【Vue-细刷-01】
  16. PCA降维(主成分分析法)
  17. 【GBASE培训】GBase数据库2022年第6期培训圆满结束
  18. 决定转学运维了,JAVA学不下去了
  19. 看完就会使用Nacos-服务发现
  20. 乐趣无穷,用SQL语句给宝宝取名字(用电脑起名)

热门文章

  1. PMP VS MBA:为什么我劝你别浪费钱读MBA
  2. HR面/综合面系列:公司相关
  3. python破解zip压缩包密码
  4. UnRAR.dll解压rar文件
  5. 计算机怎么转换中文版,电脑转换中文是哪个键
  6. 如何使用命令行合成一句话图片木马
  7. [iOS Animation]-CALayer 变换-灭点
  8. STM32(CM3内核) 内存映射
  9. Java聊天室系统(三):图形界面窗口展示
  10. Caused by: java.lang.UnsatisfiedLinkError: No implementation found for void com.geoway.mobile.utils