利用R分析OBD数据

背景介绍

为了分析自己的驾驶行为,最近斥巨资35元在PDD上买了2个OBD盒子。结合Car Scanner得到了CSV格式的数据。在此基础上,计划利用R进行分析。

参考资料

  1. R语言教程 ,北京大学出品,适合快速上手。

  2. R语言中变量命名规则与反引号的使用 ,阐述了R中变量名的自动转换问题。

将数据从CSV文件导入R

1
data <- read.csv("2022-05-17+08-26-13.csv", header=TRUE, as.is=TRUE, check.names=FALSE)

程序中的选项header=TRUE指明第一行作为变量名行, 选项as.is=TRUE说明字符型列要原样读入而不是转换为因子(factor),check.names=FALSE禁止变量名检查与自动转换。如果不禁用变量名检查,导入R的列名如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
> colnames(data)
[1] "time"
[2] "发动机转速..rpm."
[3] "已耗燃油..L."
[4] "已耗燃油.总计...L."
[5] "平均速度..km.h."
[6] "平均速度..GPS...km.h."
[7] "气压..kPa."
[8] "氧传感器1宽范围.电流.mA...mA."
[9] "氧传感器1宽范围.等价比..."
[10] "燃料价格...."
[11] "燃料价格.总计....."
[12] "燃油平均消耗.升.100公里...L.100km."
[13] "燃油平均消耗.升.100公里..10.sec..L.100km."
[14] "燃油平均消耗.升.100公里..总计...L.100km."
[15] "燃油瞬时消耗.升.100公里...L.100km."
[16] "省油器.基于燃油系统状态和油门位置...."
[17] "瞬时发动机功率.根据燃油消耗...kW."
[18] "瞬时燃油消耗.升.小时...L.h."
[19] "节气门位置...."
[20] "计算增压..bar."
[21] "路程..km."
[22] "路程.总计...km."
[23] "车辆加速..g."
[24] "车速..km.h."
[25] "进气歧管绝对压力..kPa."
[26] "进气温度...."
[27] "速度..GPS...km.h."
[28] "高度..GPS...m."
[29] "Latitude"
[30] "Longtitude"
[31] "X"

禁用检查后,结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
> colnames(data)
[1] "time"
[2] "发动机转速 (rpm)"
[3] "已耗燃油 (L)"
[4] "已耗燃油(总计) (L)"
[5] "平均速度 (km/h)"
[6] "平均速度 (GPS) (km/h)"
[7] "气压 (kPa)"
[8] "氧传感器1宽范围 电流(mA) (mA)"
[9] "氧传感器1宽范围 等价比 ()"
[10] "燃料价格 (¥)"
[11] "燃料价格(总计) (¥)"
[12] "燃油平均消耗(升/100公里) (L/100km)"
[13] "燃油平均消耗(升/100公里) 10 sec (L/100km)"
[14] "燃油平均消耗(升/100公里)(总计) (L/100km)"
[15] "燃油瞬时消耗(升/100公里) (L/100km)"
[16] "省油器(基于燃油系统状态和油门位置) ()"
[17] "瞬时发动机功率(根据燃油消耗) (kW)"
[18] "瞬时燃油消耗(升/小时) (L/h)"
[19] "节气门位置 (%)"
[20] "计算增压 (bar)"
[21] "路程 (km)"
[22] "路程(总计) (km)"
[23] "车辆加速 (g)"
[24] "车速 (km/h)"
[25] "进气歧管绝对压力 (kPa)"
[26] "进气温度 (℃)"
[27] "速度 (GPS) (km/h)"
[28] "高度 (GPS) (m)"
[29] "Latitude"
[30] "Longtitude"
[31] ""

禁用变量检查与转换后,可以不加考虑地通过列名调用指定列:

1
2
3
4
5
6
7
8
9
10
> data$"发动机转速 (rpm)"
[1] NA NA NA 911 910 NA NA 907 908 902 909 899 895 895
[15] 896 895 895 902 910 910 898 910 902 898 902 896 897 897
[29] 895 903 907 902 903 903 901 905 900 900 900 898 904 905
[43] 905 902 899 899 901 900 905 898 897 900 900 898 905 902
[57] 899 897 897 896 906 897 903 904 899 904 908 908 901 898
[71] 899 893 893 903 902 909 904 897 891 891 903 902 903 892
[85] 889 895 892 892 882 886 889 896 892 887 887 890 896 893
[99] 893 893 884 895 890 893 891 880 880 883 890 889 886 889
[113] 892 892 886 890 900 890 886 895 895 886 887 895 889 891

(数据为节选)

绘制折线图

字符串转时间

分析某一变量随时间变化趋势,首先尝试绘制折线图。这里有一个小小的问题:数据中的时间格式如下:

1
2
3
4
> data$time
[1] "08:26:19.571" "08:26:19.573" "08:26:19.575" "08:26:20.597"
[5] "08:26:20.771" "08:26:20.933" "08:26:21.100" "08:26:21.266"
[9] "08:26:21.424" "08:26:21.612" "08:26:21.769" "08:26:21.938"

这种格式的数据R不能直接使用,需要进行转换,即将字符串转换为R可以理解的时间。

显而易见,原始数据中的时间格式为hms格式,R提供了一个同名的第三方包:

1
install.packages("hms")

如果没用用户权限,包就会安装在home下某一个目录内。

然后加载这个包:

1
library(hms)

进行类型转换:

1
x <- as_hms(data$time)

缺失值处理

OBD通过采样读取数据流,受采样率限制,不可能在同一时间读取到全部参数,所以值缺失现象在样本数据中随处可见。为了绘制折线图,需要对缺失值进行适当处理。

发动机转速随时间变化折线图

1
2
3
4
library(hms)
rpm <- data.frame(x = data$time, y = data$"发动机转速 (rpm)")
rpm <- rpm[!is.na(rpm$y),]
plot(as_hms(rpm$x), rpm$y, type = "b")

然后就得到了一个比较简陋的发动机转速随时间变化折线图。由于数据采样比较频繁,不显示标点的”l”类型更合适。添加主标题,xy轴标题,得到的折线图好看了一些:

1
plot(as_hms(rpm$x), rpm$y, type = "l", main = "远景x3 pro cvt 发动机转速随时间变化折线图", xlab = "时间", ylab = "发动机转速(rpm)")

最大值、最小值、平均值、分位数

1
2
3
4
5
6
7
8
9
> max(data$"发动机转速 (rpm)", na.rm=TRUE)
[1] 1837
> min(data$"发动机转速 (rpm)", na.rm=TRUE)
[1] 724
> mean(data$"发动机转速 (rpm)", na.rm=TRUE)
[1] 1199.271
> quantile(data$"燃油平均消耗(升/100公里) (L/100km)", na.rm=TRUE)
0% 25% 50% 75% 100%
10.43989 11.06329 13.97581 31.61916 57746.89340

summary提供了更快捷的数据摘要:

1
2
3
4
> summary(data$"发动机转速 (rpm)")
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
724 895 1251 1199 1460 1837 1002
>

异常值处理

将异常值标记为NA

在整体数据的summary中,发现 高度 (GPS) (m) 的最小值为零:

1
2
3
4
5
6
7
8
高度 (GPS) (m)
Min. : 0.0
1st Qu.:144.4
Median :147.3
Mean :134.1
3rd Qu.:149.8
Max. :176.3
NA's :2690

结合实际,显然这些零值是错误的,应当视为缺失值一并处理:

1
2
3
4
> data$"高度 (GPS) (m)"[data$"高度 (GPS) (m)"==0] <- NA
> summary(data$"高度 (GPS) (m)")
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
140.3 145.2 147.8 148.6 150.0 176.3 2780

剔除零值后数据变得更有意义了。

拓展阅读:如何理解R中因子(factor)的概念?,猴子的回答同时阐明了 因子 的概念。

library(hms)
rpm <- data.frame(x = data$time, y = data$”高度 (GPS) (m)”)
rpm <- rpm[!is.na(rpm$y),]
plot(as_hms(rpm$x), rpm$y, type = “l”, main = “高度随时间变化折线图”, xlab = “时间”, ylab = “高度”)

library(hms)
rpm <- data.frame(x = data$time, y = data$”燃油平均消耗(升/100公里) (L/100km)”)
rpm <- rpm[!is.na(rpm$y),]
rpm <- rpm[!is.na(quantile(rpm$y,probs=c(.3, .75),na.rm=TRUE)),]
plot(as_hms(rpm$x), rpm$y, type = “l”, main = “燃油平均消耗(升/100公里) (L/100km)”, xlab = “时间”, ylab = “燃油平均消耗(升/100公里) (L/100km)”)

y=log2(x)
x=2^y


利用R分析OBD数据
http://xiaofami.github.io/2022/05/17/R-obd/
作者
tccmu
发布于
2022年5月17日
许可协议