什么是分类数据,为什么需要编码?
在进入数据集和编码方法之前,我们先来了解一下什么是分类数据,以及为什么在机器学习领域需要对其进行特殊处理。
什么是分类数据?
分类数据就像我们日常生活中使用的描述性标签。它代表的是可以归类的特征或品质。
为什么分类数据需要编码?
这里有一个问题:大多数机器学习算法就像挑食的人--它们只消化数字。它们无法直接理解 “晴天 ”与 “雨天 ”的不同。这就是编码的作用所在。这就好比把这些分类翻译成机器可以理解和使用的语言。
分类数据类型
并非所有类别都是相同的。我们通常有两种类型:
1. 名义: 这些类别没有固有顺序。
例如:“展望”(晴天、阴天、雨天)就是名义类别。这些天气条件之间没有自然的排序。
2. 顺序: 这些类别具有有意义的顺序。
例如:“温度”(很低、很低、很高、很高)是顺序性的。从最冷到最热有一个明显的递进过程。
为什么要关注正确编码?
试想一下,如果我们将 “晴天 ”编码为 1,将 “雨天 ”编码为 2,模型可能会认为雨天 “大于 ”晴天,而这并不是我们想要的!
既然我们已经了解了什么是分类数据以及为什么需要编码,那么让我们来看看我们的数据集,看看如何使用六种不同的编码方法来处理其中的分类变量。
数据集
让我们用一个简单的高尔夫球数据集来说明我们的编码方法(该数据集大部分是分类列)。该数据集记录了各种天气状况以及高尔夫球场的拥挤程度。
import pandas as pd
import numpy as np
data = {
'Date': ['03-25', '03-26', '03-27', '03-28', '03-29', '03-30', '03-31', '04-01', '04-02', '04-03', '04-04', '04-05'],
'Weekday': ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
'Month': ['Mar', 'Mar', 'Mar', 'Mar', 'Mar', 'Mar', 'Mar', 'Apr', 'Apr', 'Apr', 'Apr', 'Apr'],
'Temperature': ['High', 'Low', 'High', 'Extreme', 'Low', 'High', 'High', 'Low', 'High', 'Extreme', 'High', 'Low'],
'Humidity': ['Dry', 'Humid', 'Dry', 'Dry', 'Humid', 'Humid', 'Dry', 'Humid', 'Dry', 'Dry', 'Humid', 'Dry'],
'Wind': ['No', 'Yes', 'Yes', 'Yes', 'No', 'No', 'Yes', 'No', 'Yes', 'Yes', 'No', 'Yes'],
'Outlook': ['sunny', 'rainy', 'overcast', 'sunny', 'rainy', 'overcast', 'sunny', 'rainy', 'sunny', 'overcast', 'sunny', 'rainy'],
'Crowdedness': [85, 30, 65, 45, 25, 90, 95, 35, 70, 50, 80, 45]
}
# Create a DataFrame from the dictionary
df = pd.DataFrame(data)
我们可以看到,我们有很多分类变量。我们的任务是对这些变量进行编码,以便机器学习模型可以利用它们来预测高尔夫球场的拥挤程度。
让我们开始吧。
方法 1:标签编码
标签编码法为分类变量中的每个类别分配一个唯一的整数。
常用用途: 它通常用于有明确分类顺序的序数变量,如教育水平(如小学、中学、大学)或产品评级(如 1 星、2 星、3 星)。
在我们的案例中: 我们可以对高尔夫数据集中的 “Weekday ”列使用标签编码。一周中的每一天都将被分配一个唯一的数字(例如,周一 = 0,周二 = 1 等)。但是,我们需要小心,因为这可能意味着周日(6)“大于 ”周六(5),这对我们的分析可能没有意义。
# 1. Label Encoding for Weekday
df['Weekday_label'] = pd.factorize(df['Weekday'])[0]
方法 2:单热编码
一热编码法为分类变量中的每个类别创建一个新的二进制列。
常用用途: 通常用于类别没有固有顺序的名义变量。在处理类别数量相对较少的变量时尤其有用。
在我们的案例中: 对于我们的 “Outlook ”列来说,单热编码是理想的选择。我们将创建三个新列: Outlook_sunny“、”Outlook_overcast “和 ”Outlook_rainy"。每一行都将在其中一列中输入 1,在其他列中输入 0,代表当天的天气状况。
# 2. One-Hot Encoding for Outlook
df = pd.get_dummies(df, columns=['Outlook'], prefix='Outlook', dtype=int)
方法 3:二进制编码
二进制编码法将每个类别表示为二进制数(0 和 1)。
常用用途: 通常在只有两个类别时使用,多用于 “是 ”或 “否 ”的情况。
在我们的案例中: 虽然我们的 “Windy ”列只有两个类别(是和否),但我们可以使用二进制编码来演示该技术。这将产生一个单独的二进制列,其中一个类别(如 “否”)表示为 0,另一个类别(“是”)表示为 1。
# 3. Binary Encoding for Wind
df['Wind_binary'] = (df['Wind'] == 'Yes').astype(int)
方法 4:目标编码
目标编码法将每个类别替换为该类别目标变量的平均值。
常用用途: 当分类变量和目标变量之间可能存在关系时,就会使用这种方法。对于具有合理行数的数据集中的高心数特征,这种方法尤其有用。
我们的案例中:我们可以使用 “拥挤度 ”作为目标,对 “湿度 ”列进行目标编码。多风 “列中的每个 ”干燥 “或 ”潮湿 "都将分别替换为潮湿天和干燥天的平均拥挤度。
# 4. Target Encoding for Humidity
df['Humidity_target'] = df.groupby('Humidity')['Crowdedness'].transform('mean')
方法 5:序数编码
序数编码法根据有序整数的固有顺序将其分配到序数类别中。
常用用途: 用于序数变量,在这种情况下,类别的顺序是有意义的,而且你想保留这种顺序信息。
在我们的案例中: 序数编码非常适合我们的 “温度 ”列。我们可以指定整数来表示顺序: 低 = 1,高 = 2,极端 = 3。这样就保留了温度类别的自然排序。
# 5. Ordinal Encoding for Temperature
temp_order = {'Low': 1, 'High': 2, 'Extreme': 3}
df['Temperature_ordinal'] = df['Temperature'].map(temp_order)
方法 6:循环编码
循环编码法将周期性的分类变量转换成两个数字特征,以保持变量的周期性。它通常使用正弦和余弦变换来表示周期模式。例如,对于 “月份 ”这一列,我们先将其数值化(1-12),然后创建两个新特征:
其中,m 是 1 到 12 之间的数字,代表 1 月到 12 月。
常用用途:它用于具有自然周期顺序的分类变量,如一周中的天数、一年中的月份或一天中的小时数。当类别之间的 “距离 ”很重要且环环相扣时,循环编码就特别有用(例如,12 月和 1 月之间的距离应该很小,就像其他连续月份之间的距离一样)。
在我们的案例中:在我们的高尔夫数据集中,最适合循环编码的列是 “月份 ”列。月份有明显的周期模式,每年都会重复。这对我们的高尔夫数据集特别有用,因为它可以捕捉到高尔夫活动中可能每年重复出现的季节性模式。下面是我们如何应用它:
# 6. Cyclic Encoding for Month
month_order = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
df['Month_num'] = df['Month'].map(month_order)
df['Month_sin'] = np.sin(2 * np.pi * (df['Month_num']-1) / 12)
df['Month_cos'] = np.cos(2 * np.pi * (df['Month_num']-1) / 12)
结论: 转变(和理解)的力量
就是这样!六种不同的分类数据编码方法,全部应用于我们的高尔夫球场数据集。现在,所有类别都转换成了数字!
分类编码代码总结
import pandas as pd
import numpy as np
# Create a DataFrame from the dictionary
data = {
'Date': ['03-25', '03-26', '03-27', '03-28', '03-29', '03-30', '03-31', '04-01', '04-02', '04-03', '04-04', '04-05'],
'Weekday': ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
'Month': ['Mar', 'Mar', 'Mar', 'Mar', 'Mar', 'Mar', 'Mar', 'Apr', 'Apr', 'Apr', 'Apr', 'Apr'],
'Temperature': ['High', 'Low', 'High', 'Extreme', 'Low', 'High', 'High', 'Low', 'High', 'Extreme', 'High', 'Low'],
'Humidity': ['Dry', 'Humid', 'Dry', 'Dry', 'Humid', 'Humid', 'Dry', 'Humid', 'Dry', 'Dry', 'Humid', 'Dry'],
'Wind': ['No', 'Yes', 'Yes', 'Yes', 'No', 'No', 'Yes', 'No', 'Yes', 'Yes', 'No', 'Yes'],
'Outlook': ['sunny', 'rainy', 'overcast', 'sunny', 'rainy', 'overcast', 'sunny', 'rainy', 'sunny', 'overcast', 'sunny', 'rainy'],
'Crowdedness': [85, 30, 65, 45, 25, 90, 95, 35, 70, 50, 80, 45]
}
df = pd.DataFrame(data)
# 1. Label Encoding for Weekday
df['Weekday_label'] = pd.factorize(df['Weekday'])[0]
# 2. One-Hot Encoding for Outlook
df = pd.get_dummies(df, columns=['Outlook'], prefix='Outlook')
# 3. Binary Encoding for Wind
df['Wind_binary'] = (df['Wind'] == 'Yes').astype(int)
# 4. Target Encoding for Humidity
df['Humidity_target'] = df.groupby('Humidity')['Crowdedness'].transform('mean')
# 5. Ordinal Encoding for Temperature
temp_order = {'Low': 1, 'High': 2, 'Extreme': 3}
df['Temperature_ordinal'] = df['Temperature'].map(temp_order)
# 6. Cyclic Encoding for Month
month_order = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
df['Month_num'] = df['Month'].map(month_order)
df['Month_sin'] = np.sin(2 * np.pi * df['Month_num'] / 12)
df['Month_cos'] = np.cos(2 * np.pi * df['Month_num'] / 12)
# Select and rearrange numerical columns
numerical_columns = [
'Date','Weekday_label',
'Month_sin', 'Month_cos',
'Temperature_ordinal',
'Humidity_target',
'Wind_binary',
'Outlook_sunny', 'Outlook_overcast', 'Outlook_rainy',
'Crowdedness'
]
# Display the rearranged numerical columns
print(df[numerical_columns].round(3))