pandas эквивалент кодирования Stata

Я ищу способ воспроизвести кодирование поведение в Stata, которое преобразует столбец категориальной строки в столбец чисел.

x = pd.DataFrame({'cat':['A','A','B'], 'val':[10,20,30]})
x = x.set_index('cat')

что приводит к:

     val
cat     
A     10
A     20
B     30

Я хотел бы преобразовать столбец cat из строк в целые числа, сопоставляя каждую уникальную строку с (произвольным) целым числом 1-к-1. В результате:

     val
cat     
1     10
1     20
2     30

или, так же хорошо:

  cat  val
0   1   10
1   1   20
2   2   30

какие предложения?

большое спасибо, как всегда, Роб!--7-->

3 ответов


стата по encode команда начинается со строковой переменной и создает новую целочисленную переменную с метками, сопоставленными с исходной строковой переменной. Прямым аналогом этого в панд теперь будет категориальный переменный тип, который стал полноценной частью панд, начиная с 0.15 (который был выпущен после того, как этот вопрос был первоначально задан и ответил).

документации здесь.

чтобы продемонстрировать для этого примера, команда Stata было бы что-то вроде:

encode cat, generate(cat2)

тогда как команда панд будет:

x['cat2'] = x['cat'].astype('category')

  cat  val cat2
0   A   10    A
1   A   20    A
2   B   30    B

так же, как Stata делает с encode, данные хранятся в виде целых чисел, но отображаются в виде строк в выходных данных по умолчанию.

вы можете проверить это, используя категориальный метод доступа cat чтобы увидеть базовое целое число. (И по этой причине вы, вероятно, не хотите использовать " cat " в качестве имени столбца.)

x['cat2'].cat.codes

0    0
1    0
2    1

вы могли бы использовать pd.factorize:

import pandas as pd

x = pd.DataFrame({'cat':('A','A','B'), 'val':(10,20,30)})
labels, levels = pd.factorize(x['cat'])
x['cat'] = labels
x = x.set_index('cat')
print(x)

доходность

     val
cat     
0     10
0     20
1     30

вы можете добавить 1 к labels если вы хотите воспроизвести поведение Stata:

x['cat'] = labels+1

предполагая, что у вас есть фиксированный набор одиночных заглавных английских букв в качестве категориальной переменной, вы также можете сделать это:

x['cat'] = x.cat.map(lambda x: ord(x) - 64)

Я считаю, что это немного взломать. Но опять же, в Python лучше всего было бы определить отображение из символов в целые числа, которые вы, например,

my_map = {"A":1, ...} 
# e.g.: {x:ord(x)-64  for x in string.ascii_uppercase}
# if that's the convention you happen to desire.

а потом сделай

x['cat'] = x.cat.map(lambda x: my_map[x])

или что-то подобное.

Это превосходит опору на соглашения встроенного функции для вашего целочисленного отображения по многим причинам и (IMO) это такие вещи, которые "чувствуют себя" неприятными преобразованиями программисту-аналитику, но на самом деле представляют собой важные метаданные о программном обеспечении, которое вы пишете, которые раскрывают реальную слабость глобальных функций удобства на языках более высокого уровня, таких как MATLAB, STATA и т. д. Даже если есть встроенная функция, которая случайно присоединяется к конкретному соглашению, которое вы хотите использовать (произвольное соглашение, которое " A" сопоставляется с 1, "B" сопоставляется с 2 и т. д.) это не делает его хорошей идеей, чтобы использовать его.