
[英]Using get_loc to get index of multiple values by iterating over a dataframe in Pandas
[英]pandas: iterating over DataFrame index with loc
我似乎无法找到.loc行为背后的原因。 我知道它是基于标签的,所以如果我遍历Index对象,下面的最小例子应该可行。 但事实并非如此。 我当然用Google搜索,但我需要一些已经掌握索引的人的其他解释。
import datetime
import pandas as pd
dict_weekday = {1: 'MON', 2: 'TUE', 3: 'WED', 4: 'THU', 5: 'FRI', 6: 'SAT', 7: 'SUN'}
df = pd.DataFrame(pd.date_range(datetime.date(2014, 1, 1), datetime.date(2014, 1, 15), freq='D'), columns=['Date'])
df['Weekday'] = df['Date'].apply(lambda x: dict_weekday[x.isoweekday()])
for idx in df.index:
print df.loc[idx, 'Weekday']
问题不在于df.loc
; df.loc[idx, 'Weekday']
刚刚返回一个系列。 令人惊讶的行为是由于pd.Series
尝试将类似日期时间的值转换为Timestamps的方式。
df.loc[0, 'Weekday']
形成系列
pd.Series(np.array([pd.Timestamp('2014-01-01 00:00:00'), 'WED'], dtype=object))
当pd.Series(...)
,它会尝试将数据转换为适当的dtype。
如果你追踪代码,你会发现它最终到达pandas.core.common._possibly_infer_to_datetimelike中的这些行 :
sample = v[:min(3,len(v))]
inferred_type = lib.infer_dtype(sample)
这是检查数据的前几个元素并尝试推断dtype。 当其中一个值是pd.Timestamp时,Pandas会检查是否所有数据都可以转换为时间戳。 实际上, 'Wed'
可以转换为pd.Timestamp:
In [138]: pd.Timestamp('Wed')
Out[138]: Timestamp('2014-12-17 00:00:00')
这是问题的根源,导致pd.Series
返回两个时间戳而不是时间戳和字符串:
In [139]: pd.Series(np.array([pd.Timestamp('2014-01-01 00:00:00'), 'WED'], dtype=object))
Out[139]:
0 2014-01-01
1 2014-12-17
dtype: datetime64[ns]
因此返回
In [140]: df.loc[0, 'Weekday']
Out[140]: Timestamp('2014-12-17 00:00:00')
而不是'Wed'
。
替代方案:首先选择系列df['Weekday']
:
有很多解决方法; EdChum表明,向样本添加非日期(整数)值可以防止pd.Series将所有值转换为Timestamps。
或者,您可以在使用.loc
之前访问df['Weekdays']
:
for idx in df.index:
print df['Weekday'].loc[idx]
替代方案: df.loc[[idx], 'Weekday']
:
另一种选择是
for idx in df.index:
print df.loc[[idx], 'Weekday'].item()
df.loc[[idx], 'Weekday']
首先选择DataFrame df.loc[[idx]]
。 例如,当idx
等于0
,
In [10]: df.loc[[0]]
Out[10]:
Date Weekday
0 2014-01-01 WED
而df.loc[0]
返回系列:
In [11]: df.loc[0]
Out[11]:
Date 2014-01-01
Weekday 2014-12-17
Name: 0, dtype: datetime64[ns]
Series尝试将值转换为单个有用的dtype。 DataFrame可以为每列提供不同的dtype。 因此, Date
列中的Timestamp不会影响Weekday
列中值的Weekday
。
因此,使用返回DataFrame的索引选择器可以避免问题。
替代方案:使用整数作为工作日
另一种方法是在Weekday
存储isoweekday整数,并在打印时仅在结尾处转换为字符串:
import datetime
import pandas as pd
dict_weekday = {1: 'MON', 2: 'TUE', 3: 'WED', 4: 'THU', 5: 'FRI', 6: 'SAT', 7: 'SUN'}
df = pd.DataFrame(pd.date_range(datetime.date(2014, 1, 1), datetime.date(2014, 1, 15), freq='D'), columns=['Date'])
df['Weekday'] = df['Date'].dt.weekday+1 # add 1 for isoweekday
for idx in df.index:
print dict_weekday[df.loc[idx, 'Weekday']]
替代方案:使用df.ix
:
df.loc
是_LocIndexer
,而df.ix
是_IXIndexer
。 他们有不同的__getitem__
方法。 如果您单步执行代码(例如,使用pdb),您会发现df.ix
调用df.getvalue
:
def __getitem__(self, key):
if type(key) is tuple:
try:
values = self.obj.get_value(*key)
并且DataFrame方法df.get_value
成功返回'WED'
:
In [14]: df.get_value(0, 'Weekday')
Out[14]: 'WED'
这就是为什么df.ix
是另一种在这里工作的选择。
这对我来说似乎是一个错误,作为参考,我使用的是64位的python 3.3.5,pandas 0.15.1和numpy 1.9.1:
您的代码显示虽然它是以字符串形式打印,但dtype是一个时间戳:
In [56]:
df.iloc[0]['Weekday']
Out[56]:
Timestamp('2014-12-17 00:00:00')
如果我执行以下操作,那么它将保持为字符串:
In [58]:
df['Weekday'] = df['Date'].apply(lambda x: dict_weekday[x.isoweekday()])
df['WeekdayInt'] = df['Date'].map(lambda x: x.isoweekday())
df.iloc[0]['Weekday']
Out[58]:
'WED'
以上是奇怪的,因为我所做的只是添加第二列。
同样,如果我创建一个列来存储int day值然后执行apply,那么它也可以:
In [60]:
df['WeekdayInt'] = df['Date'].map(lambda x: x.isoweekday())
df['Weekday'] = df['WeekdayInt'].apply(lambda x: dict_weekday[x])
df.iloc[0]['Weekday']
Out[60]:
'WED'
如果dtype是附加的第一列,看起来dtype以某种方式持久存在或未正确分配。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.