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 каким-то образом сохраняется или не назначается правильно, если это первый добавленный столбец.