2014-12-09 2 views
1

Я использую панды ежедневно в своей работе. Недавно я обновился до 0.15.1 с 0.13.1, и теперь куча кода слишком медленная, чтобы закончить при итерации через относительно небольшие DataFrames.Очень медленная индексация в Pandas 0,15 по сравнению с 0,13.1

(я понимаю, что часто лучше/быстрее способы выполнения итерации на DataFrame, но иногда это очень ясно и сжато, чтобы иметь для структуры цикла)

я сузил проблему вниз к проблеме при смешивании типов :

def iterGet(df,col): 
    for i in df.index: 
     tmp = df[col].loc[i] 

def iterLocSet(df,col,val): 
    for i in df.index: 
     #df[col].loc[i] = val 
     df.loc[i,col] = val 
     df.at[i,col] = val 
return df 

N = 100 
df = pd.DataFrame(rand(N,3),columns = ['a','b','c']) 

df['listCol'] = [[] for i in range(df.shape[0])] 
df['strCol'] = [str(i) for i in range(df.shape[0])] 
df['intCol'] = [i for i in range(df.shape[0])] 
df['float64Col'] = [float64(i) for i in range(df.shape[0])] 

print df.a[:5] 

%time iterGet(df[['a','intCol']].copy(),'a') 
%time tmpDf = iterLocSet(df[['a','intCol']].copy(),'a',0.) 
print tmpDf.a[:5] 

%time iterGet(df[['a','float64Col']].copy(),'a') 
%time tmpDf = iterLocSet(df[['a','float64Col']].copy(),'a',0.) 
print tmpDf.a[:5] 

на панд 0.15.1 результат:

0 0.114738 
1 0.586447 
2 0.296024 
3 0.446697 
4 0.720984 
Name: a, dtype: float64 
Wall time: 6 ms 
Wall time: 3.41 s 
0 0 
1 0 
2 0 
3 0 
4 0 
Name: a, dtype: float64 
Wall time: 6 ms 
Wall time: 18 ms 
0 0 
1 0 
2 0 
3 0 
4 0 
Name: a, dtype: float64 

Но панд 0.13.1 результат заключается в следующем:

0 0.651796 
1 0.738661 
2 0.885366 
3 0.513006 
4 0.846323 
Name: a, dtype: float64 
Wall time: 6 ms 
Wall time: 14 ms 
0 0 
1 0 
2 0 
3 0 
4 0 
Name: a, dtype: float64 
Wall time: 5 ms 
Wall time: 15 ms 
0 0 
1 0 
2 0 
3 0 
4 0 
Name: a, dtype: float6 

Похоже, что выполнение задания с использованием индексации строк в многотипном массиве в 200 раз медленнее в Pandas 0.15.1?

Я знаю, что здесь может быть потенциальная ошибка, назначая то, что может быть копией массива, но я признаю, что я не совсем понимаю эту проблему. Здесь, по крайней мере, я вижу, что задание работает. EDIT Хотя теперь я вижу, что использование любого из них в цикл исправляет проблему:

df.loc[i,col] = val 
df.at[i,col] = val 

Я не знаю достаточно о реализации, чтобы диагностировать это. Может ли кто-нибудь воспроизвести это? Это то, чего вы ожидаете? Что я делаю не так? Спасибо!

+0

Что такое 'iterGet' и' iterLocSet'? – BrenBarn

+0

Возможно, вы захотите посмотреть [этот вопрос] (http://stackoverflow.com/questions/22869893/assign-value-to-subset-of-rows-in-pandas-dataframe). – BrenBarn

ответ

2

Использование .loc даже на однодисковой раме, может вызывать копию данных при частичном назначении. (Это почти всегда верно, если у вас есть объект dtypes, в меньшей степени с числовыми типами).

Когда парциальное назначение, я имею в виду:

df.loc[1,'B'] = value 

IOW. в этом случае устанавливается одно значение (установка нескольких значений аналогична). Однако установка колонки очень отличается.

df['B'] = values 
df[:,'B'] = values 

довольно эффективен и не копирует.

Таким образом, вы должны полностью избегать итераций и просто делать это.

df['B'] = [ ..... ] # if you want to set with a list-like 
df['B'] = value # for a scalar 

Так что в приведенном выше примере это, скорее всего, копирование на каждой итерации. 0.13.1 был немного ошибся в обработке частичных заданий и неправильно обрабатывал определенные случаи, поэтому копирование было необходимо немного больше.

+0

Итак, рекомендуемое решение состоит в том, чтобы сделать одну копию столбца, который нужно отредактировать, а затем скопировать обратно в df после завершения редактирования? Я хотел бы знать, что не так с df[col].loc[i] = val. Кроме того, обратите внимание, что 0.13.1, возможно, было «ошибкой», но в этом случае оно было правильным и эффективным. – agartland

+0

Хорошо, я думаю, что вижу.'df [col] .loc [i] = val', вероятно, делает копию всего столбца для каждого присваивания, а' df.loc [i, col] = val 'не (и это поведение должно было измениться в 0.15). Благодаря! – agartland

+0

поэтому '' df [col] .loc [i] '' является * прикомандированным присваиванием *. Он * может * работать, но в смешанном формате dtype обычно не будет (и это трение, оно должно либо всегда, либо никогда не работать, но зависит от того, происходит ли представление). Вот почему копирование происходит чаще. Тем не менее вы почти никогда не должны устанавливать вещи в цикле. Гораздо эффективнее не делать этого. – Jeff

Смежные вопросы