2016-10-31 3 views
6

Как я могу отмечать строку в фрейме данных каждый раз, когда столбец меняет свое строковое значение?Pandas "diff()" со строкой

Ex:

Входной

ColumnA ColumnB 
1   Blue 
2   Blue 
3   Red 
4   Red 
5   Yellow 


# diff won't work here with strings.... only works in numerical values 
dataframe['changed'] = dataframe['ColumnB'].diff()   


ColumnA ColumnB  changed 
1   Blue   0 
2   Blue   0 
3   Red   1 
4   Red   0 
5   Yellow  1 
+0

Производительность Примечание: Это может быть лучше просто использовать 'np.bool' типа вместо целых чисел. 'np.bool' занимает один байт. Я полагаю, вы могли бы использовать 'np.int8', но по умолчанию' np.int64' или 'np.int64' (независимо от того, какой C длинный в вашей системе) используется, я считаю ... –

ответ

7

я получить более высокую производительность с ne вместо использования фактического != сравнения:

df['changed'] = df['ColumnB'].ne(df['ColumnB'].shift().bfill()).astype(int) 

Timings

Используя следующую настройку для создания более крупного фрейма данных:

df = pd.concat([df]*10**5, ignore_index=True) 

я получаю следующие тайминги:

%timeit df['ColumnB'].ne(df['ColumnB'].shift().bfill()).astype(int) 
10 loops, best of 3: 38.1 ms per loop 

%timeit (df.ColumnB != df.ColumnB.shift()).astype(int) 
10 loops, best of 3: 77.7 ms per loop 

%timeit df['ColumnB'] == df['ColumnB'].shift(1).fillna(df['ColumnB']) 
10 loops, best of 3: 99.6 ms per loop 

%timeit (df.ColumnB.ne(df.ColumnB.shift())).astype(int) 
10 loops, best of 3: 19.3 ms per loop 
+1

Можете ли вы добавить тайминги для '(df.ColumnB.ne (df.ColumnB.shift())). Astype (int)'? – jezrael

+0

@jezrael: Добавлено время. Использование 'ix' для создания первой строки 0 добавляет ~ 1 мс к времени, поэтому оно выглядит таким быстрым. – root

4

Использование .shift и сравнения:

dataframe['changed'] = dataframe['ColumnB'] == dataframe['ColumnB'].shift(1).fillna(dataframe['ColumnB']) 
+0

очень чистый ответ – guilhermecgs

4

работает для меня сравнить с shift, затем NaN был заменен 0, потому что до никакого значения:

df['diff'] = (df.ColumnB != df.ColumnB.shift()).astype(int) 
df.ix[0,'diff'] = 0 
print (df) 
    ColumnA ColumnB diff 
0  1 Blue  0 
1  2 Blue  0 
2  3  Red  1 
3  4  Red  0 
4  5 Yellow  1 

Редактируйте timings другого ответа - самый быстрый в использовании ne:

df['diff'] = (df.ColumnB.ne(df.ColumnB.shift())).astype(int) 
df.ix[0,'diff'] = 0 
+1

Интересно, есть ли разница в производительности между этим подходом и просто используя '! ='? –

+1

@ juanpa.arrivillaga - Конечно, спасибо. – jezrael

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