投射到timedelta的Pandas DataFrame失败了

时间:2015-06-24 11:02:32

标签: python python-2.7 pandas casting

我有一点奇怪的情况,我不明白为什么它在一种情况下起作用而不是另一种情况。

我正在尝试在timedelta64 [ns]到timedelta64 [s]的多索引上投射一列,而且我还有一行的多索引。 如果元组是我想要的列(level_0,level_1):

  • 适用于df [tuple] = df [tuple] .astype(timedelta64 [s])

  • 它不适用于df.loc [:,tuple] .astype(timedelta64 [s])

以下是一些示例数据(csv):

Level_0,,,Respondent,Respondent,Respondent,OtherCat,OtherCat
Level_1,,,Something,StartDate,EndDate,Yes/No,SomethingElse
Region,Site,RespondentID,,,,,
Region_1,Site_1,3987227376,A,5/25/2015 10:59,5/25/2015 11:22,Yes,
Region_1,Site_1,3980680971,A,5/21/2015 9:40,5/21/2015 9:52,Yes,Yes
Region_1,Site_2,3977723249,A,5/20/2015 8:27,5/20/2015 8:41,Yes,
Region_1,Site_2,3977723089,A,5/20/2015 8:33,5/20/2015 9:09,Yes,No

加载:

In [1]: df = pd.read_csv(header=[0,1], index_col=[0,1,2])
        df

Out[1]: 

sample

我想创建一个列“持续时间”(然后一个名为“DurationMinutes”,将持续时间除以60)。

我首先将日期转换为日期时间:

In [2]: 

df.loc[:,('Respondent','StartDate')] = pd.to_datetime(sample.loc[:,('Respondent','StartDate')])

df.loc[:,('Respondent','EndDate')] = pd.to_datetime(df.loc[:,('Respondent','EndDate')])
df.loc[:,('Respondent','Duration')] = df.loc[:,('Respondent','EndDate')] - df.loc[:,('Respondent','StartDate')]

这是我不知道发生了什么的地方。我想将它转换为timedelta64 [s],因为我需要它。 如果我只是显示astype('timedelta64[s]')的结果,它就像一个魅力:

In [3]: df.loc[:,('Respondent','Duration')].astype('timedelta64[s]')
Out[3]: 
Region    Site    RespondentID
Region_1  Site_1  3987227376      1380
                  3980680971       720
          Site_2  3977723249       840
                  3977723089      2160
Name: (Respondent, Duration), dtype: float64

但如果我分配,然后显示该列,则失败:

In [4]: df.loc[:,('Respondent','Duration')] = df.loc[:,'Respondent','Duration')].astype('timedelta64[s]')
       df.loc[:,('Respondent','Duration')]
Out[4]: 
Region    Site    RespondentID
Region_1  Site_1  3987227376     00:00:00.000001
                  3980680971     00:00:00.000000
          Site_2  3977723249     00:00:00.000000
                  3977723089     00:00:00.000002
Name: (Respondent, Duration), dtype: timedelta64[ns]

奇怪的是,如果我这样做:它会起作用:

In [5]: df[('Respondent','Duration')] = df[('Respondent','Duration')].astype('timedelta64[s]')
        df.loc[:,('Respondent','Duration')]
Out[5]:
Region    Site    RespondentID
Region_1  Site_1  3987227376      1380
                  3980680971       720
          Site_2  3977723249       840
                  3977723089      2160
Name: (Respondent, Duration), dtype: float64

另一件奇怪的事情,如果我过滤一个网站,并删除Region以便我最终得到一个单级索引,它就可以......:

In [6]:
Survey = 'Site_1'
df = df.xs(Survey, level='Site').copy()
​
# Drop the 'Region' from index
df.index = df.index.droplevel(level='Region')

df.loc[:,('Respondent','StartDate')] = pd.to_datetime(df.loc[:,('Respondent','StartDate')])
df.loc[:,('Respondent','EndDate')] = pd.to_datetime(df.loc[:,('Respondent','EndDate')])
df.loc[:,('Respondent','Duration')] = df.loc[:,('Respondent','EndDate')] - df.loc[:,('Respondent','StartDate')]

​# This works fine
df.loc[:,('Respondent','Duration')] = df.loc[:,('Respondent','Duration')].astype('timedelta64[s]')
​
# Display
df.loc[:,('Respondent','Duration')]

Out[6]:
RespondentID
3987227376    1380
3980680971     720
Name: (Respondent, Duration), dtype: float64

显然我遗漏了为什么df.loc [:,tuple]与df [tuple] 不同的原因。

有人可以解决一些问题吗?

Python 2.7.9,pandas 0.16.2

1 个答案:

答案 0 :(得分:4)

这是一个错误,我刚修好它here,将在0.17.0。

要点就是这个。当您执行df.loc[:,column] = value之类的操作时,此操作与df[[column]] = value完全相同。这意味着类型强制与列WAS无关。将其与df.loc[indexer,column]对比,例如您正在部分设置列。这里新值和列的现有dtype很重要。

错误是当帧具有多索引时,即使多索引是完整索引(例如,它包含帧中的全部值),它也没有采用正确的路径。

所以底线是这些案例应该(并且将会)相同。