将 Python 中的两个电子表格与 Pandas 合并,按“时间”列中最近的“时间”,XX:XX:XX 格式的值
Posted
技术标签:
【中文标题】将 Python 中的两个电子表格与 Pandas 合并,按“时间”列中最近的“时间”,XX:XX:XX 格式的值【英文标题】:Merge two spreadsheets in Python with Pandas, by nearest 'Time' in 'Time' Column, values in XX:XX:XX format 【发布时间】:2021-02-18 15:54:21 【问题描述】:编写我的第一个程序来组织一些数据,已经练习 python 几个月了。这个小程序将在不久的将来与我正在开发的 RFID 阅读器原型一起使用。我已经成功获取了 .txt 和 .xls,提取了相关信息,现在我想根据 XX:XX:XX 格式的时间戳来匹配它们。 .txt 是来自我的 GPS 的读数,.xls 包含来自 RFID 标签的标签信息。
我只需要根据最近的时间戳将 GPS 位置与标签 ID 配对。
请看看我到目前为止所拥有的一切,并为您提供任何指导或建议。
import numpy as np
import pandas as pd
import xlrd
filename_xls = '11_4_TAG.xls'
df = pd.read_excel(filename_xls)
tag_data=(df[['Time', 'TagID']])
#print(tag_data)
filename = '11_4_GPS.txt'
df_gps = pd.read_csv(filename, delimiter=r"\s+", skiprows=17, skipfooter=3, engine='python', encoding="unicode_escape")
gps_data=(df_gps[['Latitude', 'Longitude', 'Time']])
#print(gps_data)
pd.merge_asof(tag_data, gps_data, on='Time', direction='nearest')
#print(pd.merge_asof)
我尝试了很多“on”、“direction”和“by”的变体
这是我的两个新数据集的输出:
标签数据
WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero
Time TagID
0 10:18:32 E280116060000207A633DAB6
1 10:18:57 A15427AABB00112233445566
2 10:19:07 E280116060000207A6336C96
3 10:19:09 E280116060000207A6341969
4 10:19:34 E280116060000207A633E5B9
5 10:19:40 E280116060000207A633A846
6 10:19:56 A94439112233445566778899
7 10:20:01 E200001D52120136069068C0
8 10:20:05 E280116060000207A633DA16
9 10:20:07 A63367112233445566778899
10 10:20:12 E280116060000207A633A836
11 10:20:15 E280116060000207A633CBD9
12 10:20:18 E200001D5212006106702126
13 10:20:20 A39223112233445566778899
14 10:20:28 E280116060000207A633DCC6
15 10:20:50 A02257AABB00112233445566
16 10:22:24 E280116060000207A633DA26
17 10:22:44 E280116060000207A6336AC6
18 10:23:43 E280116060000207A633DA46
19 10:24:03 E280116060000207A6336CA6
20 10:24:22 E280116060000207A633DC96
21 10:28:01 C10002AABB00112233445566
22 10:28:05 013193AABB00112233445566
23 10:28:12 017072AABB00112233445566
24 10:28:22 023764AABB00112233445566
25 10:28:42 A15800AABB00112233445566
26 10:28:49 E280116060000207A6336CC6
27 10:28:51 E280116060000207A6344236
28 10:29:00 E280116060000207A6336CB6
29 10:29:01 E280116060000207A633CBB9
30 10:29:08 E280116060000207A6341959
31 10:29:11 A72546AABB00112233445566
32 10:29:15 A93853112233445566778899
33 10:29:15 A93853AABB00112233445566
34 10:30:46 A13832AABB00112233445566
35 10:30:52 A02533AABB00112233445566
36 10:30:58 00111160600002078899CBA9
37 10:31:23 A83503AABB00112206906A73
[Finished in 0.8s]
gps_data
WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero
Latitude Longitude Time
0 N43°03.6205' W085°57.5513' 10:17:46
1 N43°03.6205' W085°57.5512' 10:17:49
2 N43°03.6203' W085°57.5514' 10:17:51
3 N43°03.6202' W085°57.5511' 10:17:54
4 N43°03.6199' W085°57.5518' 10:17:57
.. ... ... ...
342 N43°03.6162' W085°57.5477' 10:33:03
343 N43°03.6163' W085°57.5472' 10:33:06
344 N43°03.6168' W085°57.5477' 10:33:09
345 N43°03.6167' W085°57.5477' 10:33:11
346 N43°03.6163' W085°57.5486' 10:33:14
[347 rows x 3 columns]
[Finished in 0.8s]
错误代码:
WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero
Traceback (most recent call last):
File "C:\Users\Owner\Documents\Software\Python Programs\Data_parse\data_parse_xls.py", line 15, in <module>
pd.merge_asof(tag_data, gps_data, on='Time', direction='nearest')
File "C:\Users\Owner\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\pandas\core\reshape\merge.py", line 563, in merge_asof
return op.get_result()
File "C:\Users\Owner\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\pandas\core\reshape\merge.py", line 1483, in get_result
join_index, left_indexer, right_indexer = self._get_join_info()
File "C:\Users\Owner\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\pandas\core\reshape\merge.py", line 884, in _get_join_info
(left_indexer, right_indexer) = self._get_join_indexers()
File "C:\Users\Owner\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\pandas\core\reshape\merge.py", line 1789, in _get_join_indexers
return func(left_values, right_values, self.allow_exact_matches, tolerance)
File "pandas\_libs\join.pyx", line 966, in pandas._libs.join.__pyx_fused_cpdef
TypeError: No matching signature found
[Finished in 0.8s]
【问题讨论】:
您确定要按时合并吗?因为这些时间必须完全匹配才能合并 这是我目前仅有的两个电子表格共有的两个数据点。我正在捕获 GPS 数据同时还捕获标签数据,我正在开发的原型将在标签读取时捕获 GPS 信息。我想那时我不再需要这个软件了。阅读“熊猫”,他们谈论找到最接近的整数,我相信它可以是日期时间、时间戳或整数。我无法让它工作。 【参考方案1】:正如@MhDG7 所说,您只能合并完全匹配的值。因此,您的第一个任务是为 gps_data 中的每个时间戳找到 tag_data 中的时间戳之间最接近的匹配项。下面的关键行是这个
tag_secs_for_gps_secs = [min(tag_data['Secs'], key = lambda tag_secs: abs(tag_secs - gps_secs)) for gps_secs in gps_data['Secs'] ]
正是这样做的。在这里,对于以秒表示的每个 gps 时间(见下文),我们在 tag_data 时间戳(也以秒表示)中找到一个元素,该元素最小化两者之间的绝对距离
这是完整的脚本 首先我们创建玩具数据
import sys
import pandas as pd
from io import StringIO
from datetime import datetime
gps_data_raw = StringIO(
"""
Latitude,Longitude,Time
N43°03.6162',W085°57.5477',10:33:03
N43°03.6163',W085°57.5472',10:33:06
N43°03.6168',W085°57.5477',10:33:09
N43°03.6167',W085°57.5477',10:33:11
N43°03.6163',W085°57.5486',10:33:14
""")
gps_data = pd.read_csv(gps_data_raw)
tag_data_raw = StringIO(
"""
Time,TagID
10:33:01,C10002AABB00112233445566
10:33:05,013193AABB00112233445566
10:33:12,017072AABB00112233445566
10:33:22,023764AABB00112233445566
10:33:42,A15800AABB00112233445566
10:33:49,E280116060000207A6336CC6
10:33:51,E280116060000207A6344236
""")
tag_data = pd.read_csv(tag_data_raw)
然后我们将时间戳转换为日期时间对象,并最终转换为从 base_date 开始的(整数)秒
base_date = datetime(1900, 1, 1, 0, 0, 0)
gps_data['Time'] = pd.to_datetime(gps_data['Time'], format='%H:%M:%S')
tag_data['Time'] = pd.to_datetime(tag_data['Time'], format='%H:%M:%S')
gps_data['Secs'] = gps_data['Time'].apply(lambda t: int((t-base_date).total_seconds()))
tag_data['Secs'] = tag_data['Time'].apply(lambda t: int((t-base_date).total_seconds()))
然后我们匹配时间戳,将它们粘贴到数据框中,并在该列上合并
tag_secs_for_gps_secs = [min(tag_data['Secs'], key = lambda tag_secs: abs(tag_secs - gps_secs)) for gps_secs in gps_data['Secs'] ]
gps_data['Nearest_tag_secs'] = tag_secs_for_gps_secs
merged_data = gps_data.merge(tag_data, left_on = 'Nearest_tag_secs', right_on = 'Secs')
resultimg 数据框merged_data
可以进行一些清理,但在这里完整复制,以便您查看发生了什么
| | Latitude | Longitude | Time_x | Secs_x | Nearest_tag_secs | Time_y | TagID | Secs_y |
|---:|:-------------|:--------------|:--------------------|---------:|-------------------:|:--------------------|:-------------------------|---------:|
| 0 | N43°03.6162' | W085°57.5477' | 1900-01-01 10:33:03 | 37983 | 37981 | 1900-01-01 10:33:01 | C10002AABB00112233445566 | 37981 |
| 1 | N43°03.6163' | W085°57.5472' | 1900-01-01 10:33:06 | 37986 | 37985 | 1900-01-01 10:33:05 | 013193AABB00112233445566 | 37985 |
| 2 | N43°03.6168' | W085°57.5477' | 1900-01-01 10:33:09 | 37989 | 37992 | 1900-01-01 10:33:12 | 017072AABB00112233445566 | 37992 |
| 3 | N43°03.6167' | W085°57.5477' | 1900-01-01 10:33:11 | 37991 | 37992 | 1900-01-01 10:33:12 | 017072AABB00112233445566 | 37992 |
| 4 | N43°03.6163' | W085°57.5486' | 1900-01-01 10:33:14 | 37994 | 37992 | 1900-01-01 10:33:12 | 017072AABB00112233445566 | 37992 |
【讨论】:
非常感谢。我今天将深入研究并玩弄。我明白你们现在所说的关于合并相同值的内容。当我在我的露营者周围走动并阅读标签数据时,读数会持续几分钟。我也需要在几分钟内比赛,但我现在肯定可以看到实现这一目标的途径。我从来没有意识到你必须有多么有创意才能编写代码,真的很享受它。谢谢你们。 没问题。要清楚我的代码匹配自基准日期以来的 total 秒(因此任何时间戳的唯一数字),而不仅仅是时间戳的最后两位数 哦,太棒了,我尝试将“时间戳”转换为某种整数,但没有成功,很高兴看到我昨晚走在了正确的轨道上。我稍后会更新进度。 谢谢你,这很好!我将研究/谷歌搜索此代码的部分内容以完全理解,但我会鸟瞰正在发生的事情。我首先复制并粘贴了一小部分原始数据以使其正确,现在我将按照您所描绘的方式将我的两个电子表格填充到 StringIO 中。 @Beasmazter,SrtingIO
东西只有一个独立的示例,它不依赖于任何文件,并且您在最终解决方案中并不真正需要该部分。您的 df = pd.read_excel(filename_xls)
应该可以正常工作(好吧,您可能需要注意值周围的空白,但除此之外应该没有问题)。以上是关于将 Python 中的两个电子表格与 Pandas 合并,按“时间”列中最近的“时间”,XX:XX:XX 格式的值的主要内容,如果未能解决你的问题,请参考以下文章
Pandas与openpyxl库的超强结合,再见,Excel!
Pandas与openpyxl库的超强结合,再见,Excel!
如何在 pandas/python 中查看 excel 电子表格的公式?
从 Pandas/Python 中的选定单元格访问索引/行/列