【问题标题】:Trouble optimizing python interpolation script优化python插值脚本时遇到问题
【发布时间】:2014-12-13 00:44:44
【问题描述】:

我正在为我拥有的一些公共交通数据插入到达时间。我有一个工作脚本,但它似乎在二次时间运行。这是脚本:

import pandas as pd

#read the txt file
st = pd.read_csv('interpolated_test.csv')

# sort first by trip_id, then by stop_sequence
sorted_st = st.sort(['trip_id','stop_sequence'], ascending=[False,True])

# reset the index values in prep. for iteration
reindexed = sorted_st.reset_index(drop=True)

# for each row in 'arrival_time' that has a value of hh:mm:ss
for i in reindexed['arrival_time']:
# for i in range(len(reindexed['arrival_time'])):
    if pd.isnull(i) == False:
        # splice hh:mm:ss
        hour = int(i[:2])
        minute = int(i[3:5])
        # assign hh:mm:ss to numeric value
        minute_value = (hour * 60) + minute

        # replace current string with int value
        # takes ~655s to execute on Macbook Pro w/ entire stop_times.txt
        # runs in quadratic time
        reindexed = reindexed.replace(i,minute_value)

# interpolate and write out
new = reindexed.apply(pd.Series.interpolate)
print(new)

这里是 csv 的链接:https://gist.github.com/adampitchie/0192933ed0eba122ba7e

我缩短了 csv,这样您就可以运行该文件而无需等待它完成。

对于任何熟悉熊猫的人来说,这应该是唾手可得的成果,但我被困住了,我们将不胜感激。

[更新] 所以我尝试用FULL CSV FILE 运行相同的代码,我得到了这个错误:

Traceback (most recent call last):
  File "/Users/tester/Desktop/ETL/interpolate.py", line 49, in <module>
    reindexed[col].dt.hour * 60
  File "pandas/src/properties.pyx", line 34, in pandas.lib.cache_readonly.__get__ (pandas/lib.c:40664)
  File "/Library/Python/2.7/site-packages/pandas/core/series.py", line 2513, in dt
    raise TypeError("Can only use .dt accessor with datetimelike values")
TypeError: Can only use .dt accessor with datetimelike values

看起来pd.to_datetime(reindexed[col]) 不起作用。 为了完整起见,这是代码:

import pandas as pd

st = pd.read_csv('csv/stop_times.csv')

sorted_st = st.sort(['trip_id','stop_sequence'], ascending=[False,True])

reindexed = sorted_st.reset_index(drop=True)

for col in ('arrival_time', 'departure_time'):
    reindexed[col] = pd.to_datetime(reindexed[col])
    reindexed[col] = (
        reindexed[col].dt.hour * 60
        + reindexed[col].dt.minute)
    reindexed[col] = reindexed[col].interpolate()

print(reindexed.iloc[:, :3])

【问题讨论】:

    标签: python csv pandas


    【解决方案1】:

    只要有可能,尽量将计算表述为对整列而不是行或逐项的操作。您可以使用pd.to_datetime 将整列转换为datetime64s,而不是一次处理一个reindexed['arrival_time'] 中的每个值。一系列datetime64s 有一个dt 属性,它允许您以整数形式访问小时和分钟。所以你可以像这样表达整个列的计算:

    for col in ('arrival_time', 'departure_time'):
        reindexed[col] = pd.to_datetime(reindexed[col])
        reindexed[col] = (
            reindexed[col].dt.hour * 60
            + reindexed[col].dt.minute)
        reindexed[col] = reindexed[col].interpolate()
    
    print(reindexed.iloc[:5, :3])
    

    产量

        trip_id  arrival_time  departure_time
    0   1423492    647.000000      647.000000
    1   1423492    649.666667      649.666667
    2   1423492    652.333333      652.333333
    3   1423492    655.000000      655.000000
    4   1423492    655.750000      655.750000
    

    调试TypeError: Can only use .dt accessor with datetimelike values

    确实,正如您所指出的,pd.to_datetime 没有将时间转换为 datetime64s。相反,它是 只是返回与字符串相同的数据。 pd.to_datetime 在尝试将输入转换为日期时间时遇到错误时返回输入。您可以通过添加errors='raise' 参数来收集更多有关问题所在的信息:

    pd.to_datetime(reindexed['arrival_time'], errors='raise')
    

    加注

    ValueError: hour must be in 0..23
    

    所以啊哈——时间格式可能有超过 23 小时的时间。

    使用

    col = 'arrival_time'
    x = reindexed[col]
    mask = x.str.extract(r'(\d+):(\d+):(\d+)')[0].astype('int')  > 23
    

    我们可以看到小时数大于 23 的行示例:

    In [48]: x[mask].head()
    Out[48]: 
    42605    26:09:00
    42610    26:12:00
    42611    26:20:00
    42612    26:30:00
    42613    26:35:00
    Name: arrival_time, dtype: object
    

    x.str.extract 使用正则表达式模式拆分到达时间字符串 r'(\d+):(\d+):(\d+)'。它返回一个包含三列的 DataFrame。

    这段调试代码提出了一种解决方法。而不是pd.to_datetime, 我们可以使用x.str.extract 来查找小时和分钟:

    import pandas as pd
    
    st = pd.read_csv('csv/stop_times.csv')
    
    sorted_st = st.sort(['trip_id','stop_sequence'], ascending=[False,True])
    
    reindexed = sorted_st.reset_index(drop=True)
    
    for col in ('arrival_time', 'departure_time'):
        df = reindexed[col].str.extract(
            r'(?P<hour>\d+):(?P<minute>\d+):(?P<second>\d+)').astype('float')
        reindexed[col] = df['hour'] * 60 + df['minute']
        reindexed[col] = reindexed[col].interpolate()
    
    print(reindexed.iloc[:5, :3])
    

    产量

       trip_id  arrival_time  departure_time
    0  1423492    647.000000      647.000000
    1  1423492    649.666667      649.666667
    2  1423492    652.333333      652.333333
    3  1423492    655.000000      655.000000
    4  1423492    655.750000      655.750000
    

    【讨论】:

    • 所以这似乎适用于存在的值,但似乎为所有空格/空值分配了 -61 的值,并且不会在实际值之间进行插值。
    • 经过进一步检查,每当调用 pd.to_datetime() 时,它都会用 NaT 替换所有 NaN,这似乎会导致插值失败。但是,我仍然无法进行插值工作。
    • 我已经发布了我得到的结果。这不是你看到的吗?
    • 所以我做了sudo pip install --upgrade pandas,看哪,插值按照你的建议工作。另外,感谢您提供的最佳实践。我很感激!
    • 我添加了一些关于如何调试错误、错误发生原因和解决方法的 cmets。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多