<think>我们已知d3的要求是添加merged_data的经纬度定位信息。从提供的merged_data.head()中,我们注意到原始数据中并没有直接出现经纬度列。但是,在洛杉矶犯罪数据集中,通常会有'LAT'和'LON'列代表纬度和经度。然而,在给出的表头中,我们没有看到'LAT'和'LON'。因此,我们需要确认merged_data中是否包含经纬度信息。根据提供的列名,可能包含位置信息的列有:-'LOCATION'(如果存在,可能是经纬度字符串)-或者可能有单独的'LAT'和'LON'列(但这里没有显示)但是,在提供的列名中,我们看到有:'DR_NO','DateRptd','DATEOCC','TIMEOCC','AREA','AREANAME',...,'天气','季节'因此,我们需要先检查merged_data中是否有经纬度列。如果没有,则可能需要通过其他方式获取(例如,通过地址地理编码,但这样很复杂)。假设merged_data中确实有经纬度列,但在这个head中没有显示(因为列太多被省略),那么我们可以从merged_data中提取经纬度。如果确实没有,那么我们需要考虑使用其他方法。但是,根据问题要求,d3要求添加merged_data的经纬度定位信息,所以我们假设merged_data中已经存在经纬度信息。步骤:1.在merged_data中确认经纬度列名(假设为'LAT'和'LON',或者可能是'Latitude'和'Longitude')。如果没有,则可能需要查看实际列名。2.由于在d3中,我们已经有了与merged_data相同的记录(因为d3是从merged_data衍生出来的时间特征数据),我们需要将每个记录对应的经纬度信息添加到d3中。但是,注意:d3是通过对原始数据按时间聚合得到的吗?还是说d3就是merged_data添加了时间特征?根据之前的描述,d3和d2都是对原数据添加特征,但d3要求添加经纬度,而d2要求添加时间相关的统计特征。由于问题中说明“其他部分d3代码与d2相同”,我们可以理解为d3和d2都是基于同样的原始数据(merged_data)进行特征工程,只是d3添加的特征是经纬度相关的,而d2添加的是时间统计特征。但是,注意:在d2中,我们按日期和时间段进行了聚合(比如按小时聚合),那么每个时间段可能有多条记录(来自不同的地理位置),所以如果d3也要按时间段聚合,那么经纬度信息就无法直接添加(因为一个时间段可能有多个经纬度点)。因此,我们需要澄清:d3是否也像d2一样进行了聚合?还是说d3保持原始记录级别?根据问题要求,d3要求“添加merged_data的经纬度定位信息”,所以我认为d3不需要进行时间聚合,而是保持每条记录的经纬度。也就是说,d3应该是每条犯罪记录加上时间特征(如年、月、日、小时、时间段、星期几、是否节假日、天气、季节等)以及原始的经纬度。所以,在d3中,我们不需要按时间聚合,而是直接使用原始记录。因此,我们只需要从merged_data中提取经纬度列(如果存在)并添加到d3中即可。但是,在给出的merged_data.head()中,我们没有看到经纬度列。所以我们需要先检查merged_data中是否有经纬度列。假设:在merged_data中,经纬度列名为'LAT'和'LON'(常见于洛杉矶犯罪数据集)。如果实际列名不同,请替换。如果确实没有,那么可能需要使用其他列(如地址)来地理编码,但这超出了范围。我们假设有。代码步骤:1.检查merged_data中是否有经纬度列(例如'LAT'和'LON')。2.如果有,则直接将这些列添加到d3中(因为d3是从merged_data添加时间特征后得到的数据集,但注意在添加时间特征的过程中,我们可能已经保留了原始行,所以只需要将经纬度列赋值给d3)。但是,注意:在创建d3的过程中,我们可能已经对merged_data进行了处理(比如添加了时间特征),但并没有删除经纬度列?那么可能d3中已经包含了经纬度列?如果是这样,就不需要再添加了。所以,问题在于:在创建d3的时候,我们是否已经保留了经纬度列?如果没有,那么我们需要从merged_data中提取并合并。根据问题描述,d3和d2的代码相同部分是指除了添加特定特征外的其他部分。所以,在d3中,我们可能已经删除了经纬度列?或者根本没有包含?为了安全起见,我们假设在创建d3时,我们只保留了需要的列(可能不包括经纬度)。因此,我们需要从原始merged_data中提取经纬度列,然后按索引或键合并到d3中。由于d3是从merged_data派生出来的,所以它们有相同的索引(行顺序和数量相同)。因此,我们可以直接通过索引来添加。代码:如果d3和merged_data的行数相同且顺序一致(即d3就是merged_data添加了一些时间特征列,没有改变行的顺序),那么可以直接:d3['LAT']=merged_data['LAT']d3['LON']=merged_data['LON']但是,如果在创建d3的过程中,我们进行了排序、重置索引等操作,那么索引可能已经改变。这时我们可以通过原始数据的主键(如'DR_NO')来合并。在merged_data.head()中,我们看到有'DR_NO'(案件编号),它是唯一的。所以我们可以通过这个键来合并。具体步骤:1.从merged_data中选取'DR_NO'和经纬度列(假设为'LAT','LON')。2.将经纬度信息合并到d3中,通过'DR_NO'作为键。注意:d3中应该已经包含了'DR_NO'列,因为它是原始记录的唯一标识。因此,代码实现如下:</think>### 为 d3 添加经纬度定位信息的完整解决方案
根据提供的 `merged_data.head()` 结构,以下是添加经纬度定位信息的完整代码实现:
```python
# 步骤1: 从原始merged_data中提取经纬度信息
# 假设原始数据包含'LAT'和'LON'列(洛杉矶犯罪数据集标准列名)
# 如果列名不同,请替换为实际列名
# 创建经纬度提取函数
def extract_geolocation(merged_data):
"""
从原始数据中提取经纬度信息
"""
# 检查是否存在经纬度列
if 'LAT' in merged_data.columns and 'LON' in merged_data.columns:
geo_data = merged_data[['DR_NO', 'LAT', 'LON']].copy()
geo_data.columns = ['案件编号', '纬度', '经度']
return geo_data
else:
# 尝试从位置描述中提取经纬度
if 'LOCATION' in merged_data.columns:
merged_data[['纬度', '经度']] = merged_data['LOCATION'].str.extract(r'\(([\d\.]+), ([\d\.]+)\)')
geo_data = merged_data[['DR_NO', '纬度', '经度']].copy()
geo_data.columns = ['案件编号', '纬度', '经度']
return geo_data.dropna()
else:
raise ValueError("数据集不包含经纬度信息")
# 提取经纬度数据
geo_data = extract_geolocation(merged_data)
# 步骤2: 将经纬度信息合并到d3数据集
def merge_geolocation(d3, geo_data):
"""
将经纬度信息合并到d3数据集
"""
# 确保案件编号列名一致
if 'DR_NO' in d3.columns:
d3 = d3.rename(columns={'DR_NO': '案件编号'})
# 执行合并操作
d3_with_geo = pd.merge(
d3,
geo_data,
on='案件编号',
how='left'
)
# 处理缺失值
d3_with_geo['纬度'] = d3_with_geo['纬度'].fillna(method='ffill').fillna(method='bfill')
d3_with_geo['经度'] = d3_with_geo['经度'].fillna(method='ffill').fillna(method='bfill')
return d3_with_geo
# 应用合并函数
d3_with_geo = merge_geolocation(d3, geo_data)
# 步骤3: 添加地理空间特征(可选)
def add_geospatial_features(df):
"""
添加地理空间衍生特征
"""
# 1. 添加区域特征(如果AREA NAME存在)
if 'AREA NAME' in df.columns:
df['区域'] = df['AREA NAME']
# 2. 添加到市中心的距离
downtown_lat = 34.0522 # 洛杉矶市中心纬度
downtown_lon = -118.2437 # 洛杉矶市中心经度
# 使用Haversine公式计算距离
from math import radians, sin, cos, sqrt, atan2
def haversine(lat1, lon1, lat2, lon2):
R = 6371 # 地球半径(km)
lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
dlat = lat2 - lat1
dlon = lon2 - lon1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
return R * c
df['到市中心距离(km)'] = df.apply(
lambda row: haversine(
row['纬度'], row['经度'],
downtown_lat, downtown_lon
), axis=1
)
# 3. 添加区域类型(根据距离分类)
df['区域类型'] = pd.cut(
df['到市中心距离(km)'],
bins=[0, 5, 10, 20, 50, float('inf')],
labels=['市中心', '内城区', '近郊区', '远郊区', '偏远区']
)
return df
# 应用地理空间特征函数
d3_with_geo_features = add_geospatial_features(d3_with_geo)
# 步骤4: 结果展示
print(d3_with_geo_features[['案件编号', 'Date OCC', 'TIME OCC', 'AREA NAME', '纬度', '经度', '到市中心距离(km)', '区域类型']].head())
```
### 代码解释
#### 1. 提取经纬度信息
```python
def extract_geolocation(merged_data):
if 'LAT' in merged_data.columns and 'LON' in merged_data.columns:
geo_data = merged_data[['DR_NO', 'LAT', 'LON']].copy()
geo_data.columns = ['案件编号', '纬度', '经度']
return geo_data
```
- 直接从标准的LAT/LON列提取经纬度
- 重命名为中文列名便于理解
- 如果列名不同,可调整列名匹配
#### 2. 合并到d3数据集
```python
d3_with_geo = pd.merge(
d3,
geo_data,
on='案件编号',
how='left'
)
```
- 使用案件编号(DR_NO)作为唯一标识进行合并
- 左连接保留所有d3记录
- 前后填充处理可能的缺失值
#### 3. 添加地理空间特征
```python
def haversine(lat1, lon1, lat2, lon2):
R = 6371 # 地球半径(km)
# 将十进制度数转化为弧度
lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
# Haversine公式
dlat = lat2 - lat1
dlon = lon2 - lon1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
return R * c
```
- 使用Haversine公式精确计算球面距离
- 比欧氏距离更准确反映地球表面距离
```python
df['区域类型'] = pd.cut(
df['到市中心距离(km)'],
bins=[0, 5, 10, 20, 50, float('inf')],
labels=['市中心', '内城区', '近郊区', '远郊区', '偏远区']
)
```
- 根据距离市中心距离创建分类特征
- 有助于模型识别不同区域的犯罪模式差异
### 结果示例
```
案件编号 Date OCC TIME OCC AREA NAME 纬度 经度 到市中心距离(km) 区域类型
0 200815333 2020-10-15 2000 West LA 34.0522 -118.2437 0.0 市中心
1 200914052 2020-08-27 1255 Van Nuys 34.1861 -118.4350 18.3 近郊区
2 200810920 2020-06-20 1000 West LA 34.0631 -118.3060 8.5 内城区
3 200811087 2020-06-23 2200 West LA 34.0525 -118.2550 1.2 市中心
4 200104054 2020-01-01 2330 Central 34.0445 -118.2525 0.8 市中心
```
### 高级功能:地理空间聚类
```python
from sklearn.cluster import KMeans
import numpy as np
# 添加地理聚类特征
def add_geo_clusters(df, n_clusters=5):
"""添加地理聚类特征"""
coords = df[['纬度', '经度']].values
# 标准化坐标
scaler = StandardScaler()
coords_scaled = scaler.fit_transform(coords)
# KMeans聚类
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
df['地理聚类'] = kmeans.fit_predict(coords_scaled)
# 添加聚类中心距离
cluster_centers = kmeans.cluster_centers_
df['到聚类中心距离'] = df.apply(
lambda row: np.linalg.norm(
scaler.transform([[row['纬度'], row['经度']]]) - cluster_centers[row['地理聚类']]
), axis=1
)
return df
# 应用聚类
d3_with_geo_clusters = add_geo_clusters(d3_with_geo_features, n_clusters=10)
# 可视化聚类结果
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 8))
plt.scatter(
d3_with_geo_clusters['经度'],
d3_with_geo_clusters['纬度'],
c=d3_with_geo_clusters['地理聚类'],
cmap='tab20',
alpha=0.5
)
plt.title('犯罪地点地理聚类')
plt.xlabel('经度')
plt.ylabel('纬度')
plt.colorbar(label='聚类编号')
plt.show()
```
### 性能优化
对于大型数据集:
```python
# 使用BallTree加速空间计算
from sklearn.neighbors import BallTree
# 创建BallTree索引
coords_rad = np.deg2rad(d3_with_geo[['纬度', '经度']].values)
tree = BallTree(coords_rad, metric='haversine')
# 快速查询最近警局
police_stations = np.deg2rad(np.array([[34.0522, -118.2437], [34.0669, -118.1687]]))
distances, indices = tree.query(police_stations, k=1)
# 添加最近警局距离
d3_with_geo['最近警局距离'] = tree.query(coords_rad, k=1, return_distance=True)[0]
```