文章目錄
- 1 前言
- 2 Python + ElasticSearch的環境搭建
- 3 數據下載與解析
- 4 數據清洗與入庫
- 5 數據分析與可視化
- 5.1 數據分析與可視化源碼
- 5.2 公元1000年至今全球5級以上地震熱力圖(CEA)
- 5.3 公元1900年至今全球7級以上地震熱力圖(USGS)
- 5.4 公元1900年至今全球7級以上地震熱力圖(CEA)
- 5.5 公元1000年至今中國5級以上地震熱力圖(CEA)
- 5.6 公元1000年至今中國7級以上地震熱力圖(CEA)
- 5.7 公元1900年至今中國7級以上地震熱力圖(CEA)
- 5.8 公元1900年至今中國部分省區地震次數柱狀圖(CEA)
- 5.9 最強地震TOP10(USGS, 公元1900年至今)
- 5.10 最強地震TOP10(CEA, 公元1000年至今)
- 6 結語
1 前言
2020年2月18日17時許,濟南市長清區發生了4.1級地震,震源深度10千米。其後的兩天裏又連續發生了多次餘震。一直以爲,濟南是一個lucky-bargee,無論是自然災害,還是人禍戰亂,幾乎從沒有傷害過她。但是,這次發生在長清區的地震動搖了我的觀念。那麼,濟南在歷史上究竟有沒有發生過更高震級的地震呢?
帶着這個疑問,我在網上搜集了古今中外230萬條地震數據,藉助於 Python 和 ElasticSearch,分析了全球和中國的地震分佈,並對中國多個省區的歷史地震數據做了對比分析。所有源碼和示例數據已上傳至GitHub,有興趣的讀者可以下載源碼後,使用下載代碼自行下載全部數據。
2 Python + ElasticSearch的環境搭建
2.1 安裝和啓動ElasticSearch
ElasticSearch是一個分佈式、高擴展、高實時的搜索與數據分析引擎。它能很方便的使大量數據具有搜索、分析和探索的能力。充分利用ElasticSearch的水平伸縮性,能使數據在生產環境變得更有價值。
ElasticSearch採用的是NoSql數據庫,其基本概念與傳統的關係型數據庫的概念有所不同。我們先了解一下這兩個概念:
-
文檔
NoSql數據庫又叫做文檔型數據庫。文檔就相當於關係型數據庫的記錄(行)。 -
索引
在關係數據庫中的索引,是爲了加速查詢設置的一種數據結構。不同於關係數據庫的索引,Elasticsearch會爲每個字段創建這個含義的索引,而且Elasticsearch中的索引是透明的,因此Elasticsearch不再談論這個含義的索引,而是賦予索引兩個含義:- 名詞:一個索引類似於傳統關係數據庫中的一個數據庫,是一個存儲關係型文檔的地方
- 動詞:索引一個文檔,就是存儲一個文檔到一個索引(名詞)中以便它可以被檢索和查詢到,相當於關係數據庫的insert
ElasticSearch是使用java編寫的,安裝ElasticSearch之前,首先要安裝java運行環境。爲了減輕電腦的負擔,可以不安裝JDK,只安裝JRE即可。
安裝完成後,需要設置環境變量。我安裝的是jre1.8.0_241,安裝路徑在C:\Program Files\Java\,如果你安裝的版本路和路徑有所不同,請根據實際安裝情況填寫:
- JAVAHOME:C:\Program Files\Java\jre1.8.0_241
- CLASSPATH:.;%JAVA_HOME%\lib
- PATH: %JAVA_HOME%\bin
環境變量設置好後,就可以安裝ElasticSearch了。ElasticSearch安裝很簡單,從官方網站下載下載以後解壓, 在其解壓路徑下的bin文件中運行elasticsearch.bat,即可啓動ElasticSearch服務。比如,我的ElasticSearch解壓路徑是D:\Tools\elasticsearch-7.6.0,啓動命令是這樣的:
PS D:\Tools\elasticsearch-7.6.0\bin> .\elasticsearch.bat
2.3 安裝Python的Elasticsearch客戶端
萬能的pip:
pip install elasticsearch
安裝成功後,即可使用該客戶端連接Elasticsearch服務器。
>>> from elasticsearch import Elasticsearch
>>> es = Elasticsearch()
>>> es.info()
{'name': 'LAPTOP-FN4A44A5', 'cluster_name': 'elasticsearch', 'cluster_uuid': 'FUBGxHB4QC2dMccTlAvphg', 'version': {'number': '7.6.0', 'build_flavor': 'default', 'build_type': 'zip', 'build_hash': '7f634e9f44834fbc12724506cc1da681b0c3b1e3', 'build_date': '2020-02-06T00:09:00.449973Z', 'build_snapshot': False, 'lucene_version': '8.4.0', 'minimum_wire_compatibility_version': '6.8.0', 'minimum_index_compatibility_version': '6.0.0-beta1'}, 'tagline': 'You Know, for Search'}
3 數據下載與解析
3.1 數據源
最初打算從中國地震局官方網站下載數據,後來發現地震局官網數據遠沒有全球地震歷史數據查詢網站數據豐富。該網站包含來自中國地震局(CEA)和美國地質勘探局(USGS)兩個來源的數據。中國地震局(CEA)有感地震數據從2012年開始,而5級以上地震數據最早可以追溯到公元1000年。中國地震局(CEA)數據偏重中國境內地震信息,國外震級較小的已經去除。美國地質勘探局(USGS)數據始於1900年,偏重美國境內,在美國之外的國家,大抵只包含震級較大的地震數據。
3.2 下載與解析
全球地震歷史數據查詢網站的數據下載非常簡單,無需註冊,使用GET方法就可以輕鬆下載。URL有兩個參數,dizhen_ly表示數據源,page表示頁碼。dizhen_ly=china表示下載中國地震局(CEA)數據,dizhen_ly=usa表示下載美國地質勘探局(USGS)數據。以下是數據下載與解析源碼,下載後的數據保存爲.csv文件。
import time, re, requests
from bs4 import BeautifulSoup
def Crawl_data(url, csv_file):
'''抓取地震數據'''
resp = requests.get(url)
r = re.compile('查詢到 (\d+) 條記錄,分 (\d+) 頁顯示')
pcount = int(r.findall(resp.text)[0][1]) # 獲取總頁數
# 取得每頁數據表格,並寫到csv文件中
with open(csv_file, 'w', encoding='utf-8') as fp:
fp.write('發震時刻, 震級(M), 經度(°), 緯度(°), 深度(千米), 參考位置, \n')
for page in range(1, pcount+1):
#for page in range(2):
print('第%d頁/共%d頁' % (page, pcount), '...', end='')
try_count = 0
resp = requests.get(url+'&page=%d'%page)
while not resp.ok and try_count < 2:
try_count += 1
time.sleep(try_count*1)
resp = requests.get(url+'&page=%d'%page)
if not resp.ok:
print('Error:', url+'&page=%d'%page)
continue
soup = BeautifulSoup(resp.text, 'lxml')
for tr in soup.find_all('tr')[1:]:
tds = tr.find_all('td')
dt = tds[0].text
level = tds[1].text
lon = tds[2].text
lat = tds[3].text
deep = tds[4].text
location = tds[5].find('a').text
fp.write('%s, %s, %s, %s, %s, %s\n'%(dt, level, lon, lat, deep, location))
print('Done')
調用Crawl_data()函數,給出下載地址和數據文件名,即可完成數據的下載和解析。
Crawl_data('http://ditu.92cha.com/dizhen.php?dizhen_ly=china', 'earthQuake_china.csv')
Crawl_data('http://ditu.92cha.com/dizhen.php?dizhen_ly=usa', 'earthQuake_usa.csv')
友情提示:抓取中國地震局數據大約需要1分鐘,抓取美國地質勘探局數據則可能需要10個小時,甚至更長時間,請對此做好足夠的心理準備,並妥善安排下載時間。
4 數據清洗與入庫
4.1 數據清洗策略
由於數據的時間跨度超過了1000年,很多歷史地震數據的日期、時間、地點等信息都不夠精準,在處理時會導致異常。爲此,我們約定:
- 若數據缺少時間,則按00:00:00計
- 若數據的日期不完整,缺少月份則按1月計,缺少日期,則按1日計
- 若震級、經緯度、震源深度不能轉爲浮點數,則視爲無效數據
4.2 創建索引(建庫)
Elasticsearch功能很強,但很多概念搞得莫名其妙,最不能忍受的是,亂用索引(index)這個詞。比如,關係型數據庫中的建庫或者建表操作,MongoDB中的創建集合(collection)操作,到了Elasticsearch這裏,居然變成了創建索引。這還不算完,關係型數據庫中的插入(insert)操作,到了Elasticsearch這裏,竟然還是index操作。算了,不吐槽了,誰讓人家功能強呢,有點脾氣也是應該的嘛。
from elasticsearch import Elasticsearch, client
def create_index():
"""創建索引"""
es = Elasticsearch()
ic = client.IndicesClient(es)
# 如果索引存在則刪除
try:
ic.delete(index="earthquake")
except:
pass
# 創建索引
ic.create(
index="earthquake",
body={
"mappings": {
"properties": {
"time": {"type": "date"}, # 發震時間
"level": {"type": "float"}, # 震級
"geo": {"type": "geo_point"}, # 地理位置
"deep": {"type": "float"}, # 深度
"location": {"type": "text"}, # 位置
"source": {"type": "keyword"} # 數據來源
}
}
}
)
針對每一條地震數據,我們設計了6個屬相項:時間、震級、經緯度、震源深度、地址、數據來源。調用create_index()函數,即可在Elasticsearch數據庫中完成索引創建。請注意,創建索引之前,會先刪除同名的索引。
4.3 數據清洗與入庫
from datetime import datetime
from elasticsearch import Elasticsearch
def insert_doc(csv_file, source):
"""數據入庫"""
with open(csv_file, "r", encoding="utf-8") as fp:
lines = fp.readlines()
total = len(lines)-1 # 文件內數據總量
success, failure = 0, 0 # 累計成功和失敗數量
section = 10000 # 分批插入,每批次數量
rank = list(range(1, len(lines), section))
rank.append(len(lines))
for i in range(len(rank)-1):
print(rank[i], rank[i+1])
docs = []
fail = 0 # 本批次失敗數量
for line in lines[rank[i]:rank[i+1]]:
data = line.split(",")
try:
dt = datetime.strptime(data[0], "%Y-%m-%d %H:%M:%S").isoformat()
except:
try:
d, t = data[0].split()
yy, mm, dd = d.split('-')
if mm == '00':
mm = '01'
if dd == '00':
dd = '01'
#print("Data Clearing:", data[0])
data[0] = '%s-%s-%s %s'%(yy, mm, dd, t)
dt = datetime.strptime(data[0], "%Y-%m-%d %H:%M:%S").isoformat()
except:
print("Error:", i, data[0])
fail += 1
continue
try:
cmd = {"index":{"_index":"earthquake"}}
doc = {
"time": dt,
"level": float(data[1]),
"geo": [float(data[2]), float(data[3])],
"deep": float(data[4]),
"location": data[5],
"source": source
}
docs.append(cmd)
docs.append(doc)
except:
print("Error:", line)
fail += 1
es = Elasticsearch()
ret = es.bulk(index='earthquake', body=docs)
success += len(docs)/2 - fail
failure += fail
print("%s共計%d條數據,累計入庫%d條,累計失敗%d條"%(csv_file, total, success, failure))
下面兩行代碼,分別把下載下來的中國地震局(CEA)數據文件和美國地質勘探局(USGS)數據文件導入到Elasticsearch數據庫中。共計約230萬條記錄,耗時大約3分鐘。
insert_doc("earthQuake_china.csv", 'CEA')
insert_doc("earthQuake_usa.csv", 'USGS')
5 數據分析與可視化
5.1 數據分析與可視化源碼
數據已經備好,激動人心的時刻終於開始了。直接上源碼:
#!/usr/bin/env python
# coding:utf-8
from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.globals import ChartType
from datetime import datetime
from elasticsearch import Elasticsearch
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['FangSong'] # 指定默認字體
plt.rcParams['axes.unicode_minus'] = False # 解決保存圖像時'-'顯示爲方塊的問題
def get_data(level, year, source):
'''獲取地震等級不小於level的地震數據'''
es = Elasticsearch()
dt = datetime.strptime(str(year), '%Y').isoformat()
condition = {
'size': 0,
'track_total_hits': True,
'query': {
'bool': {
'must': [
{
'range': {
'level': {
'gte': level
}
}
},
{
'range': {
'time': {
'gt': dt
}
},
}
]
}
},
'aggregations': {
'heatmap': {
'geohash_grid': {
'field': 'geo',
'precision': 5
},
'aggs': {
'centroid': {
'geo_centroid': {
'field': 'geo'
}
}
}
}
}
}
if source == 'CEA' or source == 'USGS':
condition['query']['bool']['must'].append({'term':{'source':source}})
return es.search(index='earthquake', body=condition)
def plot_heatmap(level, maptype, source, year=1900, cb=(0,10)):
'''繪製地震熱力圖
level - 僅繪製不小於level等級的地震數據
maptype - 地圖類型:china|world
source - 數據源:CEA|USGS
year - year:起始年份
cb - ColorBar顯示的最小值和最大值
'''
zone = '中國' if maptype == 'china' else '全球'
subject = '公元%d年至今%s%d級以上地震熱力圖(%s)'%(year, zone, level, source)
data = get_data(level, year, source)
#print(data['hits']['total']['value'])
c = Geo(init_opts={'width':'1700px', 'height':'800px'})
c.add_schema(maptype=maptype)
values = []
for bucket in data['aggregations']['heatmap']['buckets']:
c.add_coordinate(bucket['key'], bucket['centroid']['location']['lon'], bucket['centroid']['location']['lat'])
values.append((bucket['key'], bucket['doc_count']))
c.add(subject, values, type_=ChartType.HEATMAP)
c.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
c.set_global_opts(
visualmap_opts=opts.VisualMapOpts(min_=cb[0], max_=cb[1], is_calculable=True, orient='horizontal', pos_left='center'),
title_opts=opts.TitleOpts(title='Geo-HeatMap'),
)
c.render('%s.html'%subject)
def top_10(year, source):
"""條件檢索"""
dt = datetime.strptime(str(year), '%Y').isoformat()
condition = {
'size': 10,
'query': {
'bool': {
'must': [
{
'range': {
'time': {
'gt': dt
}
},
},
{
'term': {
'source': source
}
}
]
}
},
'sort': {
'level': {
'order': 'desc'
}
},
'highlight': {
'fields': {
'time': {},
'level': {},
'location': {}
}
}
}
es = Elasticsearch()
ret = es.search(index='earthquake', body=condition)
result = list()
for item in ret['hits']['hits']:
result.append((item['_source']['time'], item['_source']['level'], item['_source']['location'].strip()))
return result
def search_by_condition(location, level, year=1900, source='CEA', size=200):
"""條件檢索"""
dt = datetime.strptime(str(year), '%Y').isoformat()
condition = {
'size': size,
'query': {
'bool': {
'must': [
{
'range': {
'level': {
'gte': level
}
}
},
{
'range': {
'time': {
'gt': dt
}
},
},
{
'match_phrase': {
'location': {
'query': location,
'slop': 0
}
}
},
{
'term': {
'source': source
}
}
]
}
},
'sort': {
'time': {
'order': 'desc'
}
},
'highlight': {
'fields': {
'time': {},
'level': {},
'location': {}
}
}
}
es = Elasticsearch()
ret = es.search(index='earthquake', body=condition)
result = list()
for item in ret['hits']['hits']:
result.append((item['_source']['time'], item['_source']['level'], item['_source']['location'].strip()))
return result
def plot_bar(city_list, level_list, year=1900, source='CEA', size=200):
"""繪製城市分級地震柱狀圖"""
title = '公元%d年至今中國部分省區地震次數柱狀圖(%s)'%(year, source)
fig, ax = plt.subplots()
fig.set_size_inches(12, 6)
for level in level_list:
data = list()
for city in city_list:
data.append(len(search_by_condition(city, level, year=year, source=source, size=size)))
#print(level, data)
ax.bar(city_list, data, 0.35, label='%d級及以上'%level)
ax.legend(loc='upper left')
ax.set_ylabel('地震次數')
ax.set_title(title)
fig.savefig('%s.png'%title)
if __name__ == '__main__':
# 公元1000年至今全球5級以上地震熱力圖(CEA)
plot_heatmap(5, 'world', source='CEA', year=1000, cb=(0,10))
# 公元1900年至今全球7級以上地震熱力圖(USGS)
plot_heatmap(7, 'world', source='USGS', year=1900, cb=(0,5))
# 公元1900年至今全球7級以上地震熱力圖(CEA)
plot_heatmap(7, 'world', source='CEA', year=1900, cb=(0,5))
# 公元1000年至今中國5級以上地震熱力圖(CEA)
plot_heatmap(5, 'china', source='CEA', year=1000, cb=(0,20))
# 公元1000年至今中國7級以上地震熱力圖(CEA)
plot_heatmap(7, 'china', source='CEA', year=1000, cb=(0,3))
# 公元1900年至今中國7級以上地震熱力圖(CEA)
plot_heatmap(7, 'china', source='CEA', year=1900, cb=(0,1))
# 公元1900年至今中國部分省區地震次數柱狀圖(CEA)
city_list = ['北京', '上海', '廣東', '江蘇', '浙江', '山東', '臺灣', '河南', '安徽', '雲南', '貴州', '四川', '湖北', '陝西', '新疆', '河北', '甘肅', '江西', '吉林', '遼寧']
level_list = [6, 7]
plot_bar(city_list, level_list, year=1900, source='CEA', size=2000)
# 最強地震TOP10
for year, source in [(1900, 'USGS'), (1900, 'CEA'), (1000, 'CEA')]:
top = top_10(year=year, source=source)
print('自公元%d年以來最強地震TOP10(%s)'%(year, source))
for i, item in enumerate(top):
print('|%d|%s|%.1f|%s|'%((i+1), *item))
print('----------------------------------')
# 公元1000年以來濟南地震史
print('公元1000年以來濟南地震史:')
res = search_by_condition('濟南', 0, 1000)
for i, item in enumerate(res):
print('%d. %s %.1f %s'%((i+1), *item))
5.2 公元1000年至今全球5級以上地震熱力圖(CEA)
這是基於中國地震局(CEA)數據繪製的公元1000年至今全球5級以上地震熱力圖,紅色表示5級以上地震等於或超過10次。
5.3 公元1900年至今全球7級以上地震熱力圖(USGS)
這是基於美國地質勘探局(USGS)數據繪製的公元1900年至今全球7級以上地震熱力圖,紅色表示7級以上地震等於或超過5次。
5.4 公元1900年至今全球7級以上地震熱力圖(CEA)
這是基於中國地震局(CEA)數據繪製的公元1900年至今全球7級以上地震熱力圖,紅色表示7級以上地震等於或超過5次。和上一張圖相比,CEA的數據明顯比USGS少很多。
5.5 公元1000年至今中國5級以上地震熱力圖(CEA)
這是基於中國地震局(CEA)數據繪製的公元1000年至今中國5級以上地震熱力圖,紅色表示5級以上地震等於或超過20次。
5.6 公元1000年至今中國7級以上地震熱力圖(CEA)
這是基於中國地震局(CEA)數據繪製的公元1000年至今中國7級以上地震熱力圖,紅色表示7級以上地震等於或超過3次。
5.7 公元1900年至今中國7級以上地震熱力圖(CEA)
這是基於中國地震局(CEA)數據繪製的公元1900年至今中國7級以上地震熱力圖,紅色表示7級以上地震等於或超過1次。
5.8 公元1900年至今中國部分省區地震次數柱狀圖(CEA)
這是從公元1900年至今中國部分省區地震次數柱狀圖。百餘年來,臺灣居然有近50次超過7級的地震,真得是觸目驚心啊!
5.9 最強地震TOP10(USGS, 公元1900年至今)
No. | 時間 | 震級 | 地點 |
---|---|---|---|
1 | 1960-05-22T19:11:20 | 9.5 | Bio-Bio(智利大地震) |
2 | 1964-03-28T03:36:16 | 9.2 | Southern Alaska |
3 | 2011-03-11T05:46:24 | 9.1 | near the east coast of Honshu |
4 | 2004-12-26T00:58:53 | 9.1 | off the west coast of northern Sumatra |
5 | 1952-11-04T16:58:30 | 9.0 | off the east coast of the Kamchatka Peninsula |
6 | 2010-02-27T06:34:11 | 8.8 | offshore Bio-Bio |
7 | 1965-02-04T05:01:22 | 8.7 | Rat Islands |
8 | 2012-04-11T08:38:36 | 8.6 | off the west coast of northern Sumatra |
9 | 2005-03-28T16:09:36 | 8.6 | northern Sumatra |
10 | 1957-03-09T14:22:33 | 8.6 | Andreanof Islands |
5.10 最強地震TOP10(CEA, 公元1000年至今)
No. | 時間 | 震級 | 地點 |
---|---|---|---|
1 | 2012-04-11T16:38:36 | 8.6 | 蘇門答臘北部附近海域 |
2 | 1950-08-15T22:09:34 | 8.6 | 西藏察隅、墨脫>Ⅹ |
3 | 1920-12-16T20:05:53 | 8.5 | 寧夏海原Ⅻ |
4 | 1668-07-25T00:00:00 | 8.5 | 山東郯城≥Ⅺ |
5 | 1902-08-22T11:00:00 | 8.3 | 新疆阿圖什北>Ⅹ |
6 | 1556-02-02T00:00:00 | 8.3 | 陝西華縣Ⅺ |
7 | 2017-09-08T12:49:15 | 8.2 | 墨西哥沿岸近海 |
8 | 2015-09-17T06:54:31 | 8.2 | 智利中部沿岸近海 |
9 | 2013-05-24T13:44:49 | 8.2 | 鄂霍次克海 |
10 | 2012-04-11T18:43:12 | 8.2 | 蘇門答臘北部附近海域 |
CEA的數據看起來有點不科學,排名第一的,居然不是1960年的智利大地震。好在,CEA數據讓我們看到了中國歷史上的兩次大地震:山東郯城大地震和陝西華縣大地震,也算是找回了一點顏面吧。
6 結語
6.1 濟南地震史
是時候回答我的問題了:濟南在歷史上究竟有沒有發生過更高震級的地震呢?檢索公元1000年以來地震地點包含“濟南”的所有地震數據:
# 公元1000年以來濟南地震史
print(公元1000年以來濟南地震史)
res = search_by_condition('濟南', 0, 1000)
for i, item in enumerate(res):
print(i+1, *item)
結果顯示,最近1000年來,濟南竟然真的只有剛剛發生的兩次地震!
公元1000年以來濟南地震史:
- 2020-02-20T04:44:34 3.1 山東濟南市長清區
- 2020-02-18T17:07:16 4.1 山東濟南市長清區
6.2 郯城地震
歷史上,發生在山東的地震雖然屈指可數,但有史以來我國東部破壞最爲強烈的地震卻發生在山東。公元1668年7月25日,山東南部發生了一次曠古未有特大的地震,震級爲8.5級,極震區位於山東省郯城、臨沭、莒縣一帶,震中位置爲北緯34.8°、東經118.5°(臨沭縣乾溝淵村),極震區烈度達Ⅻ度。由於極震區大部分位於郯城縣境內,故稱爲郯城地震。這次地震是我國大陸東部板塊內部一次最強烈的地震,造成了重大的人口傷亡和經濟損失。
蒲松齡先生在《聊齋》中如此描述這次大地震:康熙七年六月十七日戌時,地大震。餘適客稷下(齊國古都,今臨淄,距離我老家很近),方與表兄李篤之對燭飲。忽聞有聲如雷,自東南來,向西北去。衆駭異,不解其故。俄而几案擺簸,酒杯傾覆,屋樑椽柱,錯折有聲。相顧失色。久之,方知地震,各疾趨出。見樓閣房舍,僕而復起,牆傾屋塌之聲,與兒啼女號,喧如鼎沸。人眩暈不能立,坐地上隨地轉側。河水傾潑丈餘,雞鳴犬吠滿城中。逾一時許始稍定。視街上,則男女裸體相聚,競相告語,並忘其未衣也。
6.3 智利大地震
1960年5月21日下午3時,智利發生9.5級地震。從這一天到5月30日,該國連續遭受數次地震襲擊,地震期間,6座死火山重新噴發,3座新火山出現。5月21日的9.5級大地震造成了20世紀最大的一次海嘯。這是有儀器記錄以來最大的一次地震。地震造成智利2000多人死亡。幾天之後,地震的能量穿過太平洋,在太平洋西岸掀起了海嘯,又給日本和菲律賓的東部沿海地區造成了嚴重的損害。