Линейный регрессионный анализ со строковыми/категориальными признаками (переменными)?
Похоже, что алгоритмы регрессии работают с функциями, представленными в виде чисел. Например:
![enter image description here]()
Этот набор данных не содержит категориальных функций/переменных. Совершенно ясно, как сделать регрессию на этих данных и прогнозировать цену.
Но теперь я хочу сделать регрессионный анализ данных, которые содержат категориальные особенности:
![enter image description here]()
Есть 5 функций: District
, Condition
, Material
, Security
, Type
Как я могу сделать регресс на этих данных? Нужно ли вручную преобразовывать все эти строковые/категориальные данные в числа? Я имею в виду, если мне нужно создать некоторые правила кодирования и в соответствии с этими правилами преобразовать все данные в числовые значения. Есть ли простой способ преобразовать строковые данные в числа без необходимости вручную создавать собственные правила кодирования? Может быть, в Python есть библиотеки, которые можно использовать для этого? Есть ли риск того, что регрессионная модель будет как-то неверной из-за "плохого кодирования"?
Ответы
Ответ 1
Да, вам нужно будет преобразовать все в числа. Это требует размышления о том, что представляют эти атрибуты.
Обычно есть три возможности:
- Однострочное кодирование для категориальных данных
- Произвольные номера для порядковых данных
- Используйте что-то вроде групповых средств для категориальных данных (например, средних цен для городских районов).
Вы должны быть осторожны, чтобы не вводить информацию, которую вы не имеете в случае приложения.
Одно горячее кодирование
Если у вас есть категориальные данные, вы можете создать фиктивные переменные с значениями 0/1 для каждого возможного значения.
Е. г.
idx color
0 blue
1 green
2 green
3 red
к
idx blue green red
0 1 0 0
1 0 1 0
2 0 1 0
3 0 0 1
Это легко сделать с помощью pandas:
import pandas as pd
data = pd.DataFrame({'color': ['blue', 'green', 'green', 'red']})
print(pd.get_dummies(data))
приведет к:
color_blue color_green color_red
0 1 0 0
1 0 1 0
2 0 1 0
3 0 0 1
Числа для порядковых данных
Создайте сопоставление сортируемых категорий, например. г.
старый < обновленный < new → 0, 1, 2
Это также возможно с помощью pandas:
data = pd.DataFrame({'q': ['old', 'new', 'new', 'ren']})
data['q'] = data['q'].astype('category')
data['q'] = data['q'].cat.reorder_categories(['old', 'ren', 'new'], ordered=True)
data['q'] = data['q'].cat.codes
print(data['q'])
Результат:
0 0
1 2
2 2
3 1
Name: q, dtype: int8
Использование категориальных данных для групповых операций
Вы можете использовать среднее значение для каждой категории за прошлые (известные события).
Скажем, у вас есть DataFrame с последними известными средними ценами для городов:
prices = pd.DataFrame({
'city': ['A', 'A', 'A', 'B', 'B', 'C'],
'price': [1, 1, 1, 2, 2, 3],
})
mean_price = prices.groupby('city').mean()
data = pd.DataFrame({'city': ['A', 'B', 'C', 'A', 'B', 'A']})
print(data.merge(mean_price, on='city', how='left'))
Результат:
city price
0 A 1
1 B 2
2 C 3
3 A 1
4 B 2
5 A 1
Ответ 2
В этом случае вы можете использовать "Dummy Coding". Есть библиотеки Python для фиктивного кодирования, у вас есть несколько вариантов.
Вы можете использовать библиотеку scikit-learn. Посмотрите здесь.
Или, если вы работаете с пандами, у него есть встроенная функция для создания фиктивных переменных. Проверьте это.
Пример с пандами ниже:
import pandas as pd
sample_data = [[1,2,'a'],[3,4,'b'],[5,6,'c'],[7,8,'b']]
df = pd.DataFrame(sample_data, columns=['numeric1','numeric2','categorical'])
dummies = pd.get_dummies(df.categorical)
df.join(dummies)
Ответ 3
При линейной регрессии с категориальными переменными вы должны быть осторожны с фиктивной переменной. Ловушка фиктивной переменной - это сценарий, в котором независимые переменные являются мультиколлинеарными - сценарий, в котором две или более переменных сильно коррелированы; Проще говоря, одну переменную можно предсказать из других. Это может привести к необычности модели, то есть ваша модель просто не будет работать. Читайте об этом здесь
Идея состоит в том, чтобы использовать фиктивную переменную с кодировкой drop_first=True
, при этом будет исключен один столбец из каждой категории после преобразования категориальной переменной в фиктивные/индикаторные переменные. Делая это, вы НЕ БУДЕТЕ потерять какую-либо релевантную информацию просто потому, что весь ваш смысл в наборе данных может быть полностью объяснен остальными функциями.
Вот полный код того, как вы можете сделать это для своего набора данных жилья
Итак, у вас есть категорические особенности:
District, Condition, Material, Security, Type
И одна из числовых особенностей, которую вы пытаетесь предсказать:
Price
Сначала вам нужно разделить ваш начальный набор данных на входные переменные и прогнозирование, предполагая, что его кадр данных pandas будет выглядеть так:
Входные переменные:
X = housing[['District','Condition','Material','Security','Type']]
Прогноз:
Y = housing['Price']
Преобразуйте категориальные переменные в фиктивные/индикаторные переменные и поместите по одной в каждую категорию:
X = pd.get_dummies(data=X, drop_first=True)
Так что теперь, если вы проверите форму X с помощью drop_first=True
вы увидите, что у него на 4 столбца меньше - по одному для каждой вашей категориальной переменной.
Теперь вы можете продолжать использовать их в вашей линейной модели. Для реализации scikit-learn это может выглядеть так:
from sklearn import linear_model
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = .20, random_state = 40)
regr = linear_model.LinearRegression() # Do not use fit_intercept = False if you have removed 1 column after dummy encoding
regr.fit(X_train, Y_train)
predicted = regr.predict(X_test)
Ответ 4
Один из способов достижения регрессии с категориальными переменными в качестве независимых переменных, как указано выше - Использование кодирования. Другой способ сделать это - использовать R-подобную статистическую формулу с помощью библиотеки statmodels. Вот фрагмент кода
from statsmodels.formula.api import ols
tips = sns.load_dataset("tips")
model = ols('tip ~ total_bill + C(sex) + C(day) + C(day) + size', data=tips)
fitted_model = model.fit()
fitted_model.summary()
Dataset
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4
Резюме регрессии
![enter image description here]()