pandas: итерация по индексу фрейма данных с loc
Я не могу, кажется, найти обоснование поведения .линия контроля. Я знаю, что он основан на метках, поэтому, если я перебираю объект Index, должен работать следующий минимальный пример. Но это не так. Я, конечно, погуглил, но мне нужно дополнительное объяснение от кого-то, кто уже захватил индексацию.
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']
2 ответов
проблема не в df.loc
;
df.loc[idx, 'Weekday']
просто возвращает серию.
Удивительное поведение связано с тем, чтоpd.Series
пытается привести значения типа datetime к меткам времени.
df.loc[0, 'Weekday']
"формы" серии
pd.Series(np.array([pd.Timestamp('2014-01-01 00:00:00'), 'WED'], dtype=object))
, когда pd.Series(...)
- это пытается бросить данные к соответствующему dtype.
если вы проследите через код, вы обнаружите, что он в конечном итоге прибывает в эти строки в панды.ядро.общий._possibly_infer_to_datetimelike:
sample = v[:min(3,len(v))]
inferred_type = lib.infer_dtype(sample)
который проверяет первые несколько элементов данных, и пытается вывести dtype.
Когда одним из значений является pd.Временная метка, панды проверяет, могут ли все данные быть приведены в качестве временных меток. Действительно,'Wed'
можно бросить в pd.Метки:
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 показывает, что добавление в образец значения, отличного от datelike (integer), может предотвратить pd.Серия от приведения всех значений к отметкам времени.
кроме того, вы можете получить доступ df['Weekdays']
до используя .loc
:
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']
выбирает таблицы данных 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. Фреймы данных могут иметь разные dtype для каждого столбца. Так Метка времени в Date
столбец не влияет на dtype значения в .
таким образом, проблема была устранена с помощью селектора индекса, который возвращает фрейм данных.
альтернатива: используйте целые числа для буднего дня
еще одна альтернатива-сохранить целое число isoweekday в Weekday
, и преобразовать в строки только в конце при печати:
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
еще одна альтернатива, которая работает здесь.
Это кажется мне ошибкой, для справки я использую python 3.3.5 64-бит, 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 каким-то образом сохраняется или не назначается правильно, если это первый добавленный столбец.