Pandas эквивалент Stata encode
Я ищу способ репликации поведения encode в 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
Любые предложения?
Большое спасибо, как всегда,
Rob
Ответы
Ответ 1
Команда Stata encode
начинается с строковой переменной и создает новую целочисленную переменную с метками, сопоставленными с исходной строковой переменной. Прямым аналогом этого в pandas стал бы категориальный тип переменной, который стал полноценной частью pandas начиная с 0,15 (которая была выпущена после того, как этот вопрос был изначально задан и ответил).
Смотрите документацию здесь.
Чтобы продемонстрировать этот пример, команда Stata будет выглядеть примерно так:
encode cat, generate(cat2)
тогда как команда pandas будет:
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
Ответ 2
Вы можете использовать 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
Ответ 3
Предполагая, что у вас есть фиксированный набор заглавных английских букв в качестве вашей категориальной переменной, вы также можете сделать это:
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 the convention you happen to desire.
а затем do
x['cat'] = x.cat.map(lambda x: my_map[x])
или что-то подобное.
Это выше, чем полагаться на соглашения встроенных функций для вашего целочисленного сопоставления, по многим причинам и (IMO), это такие вещи, которые "чувствуют" "неприятные преобразования" программисту-аналитику, но на самом деле представляют собой важные метаданные о написанном вами программном обеспечении, которые раскрывают реальную слабость глобальных функций удобства на языках более высокого уровня, таких как MATLAB, STATA и т.д. Даже если есть встроенная функция, которая случайно соприкасается с конкретным соглашением, которое вы хотите (произвольное соглашение о том, что "A" отображается в 1, "B" отображается на 2 и т.д.), это не делает его хорошей идеей для его использования.