44_Pandas将分类变量转换为虚拟变量(get_dummies)
要将分类变量(分类数据、定性数据)转换为 pandas 中的虚拟变量,请使用 pandas.get_dummies() 函数。
按字符串分类的性别等数据可以转换为男性为0,女性为1,多类特征可以转换为one-hot表达式。通常作为机器学习的预处理执行。
这里,将描述以下内容。
- pandas.get_dummies()的基本用法
- 排除第一类:drop_first
- 缺失值NaN虚拟化:dummy_na
- 指定pandas.DataFrame的虚拟变量的列名:prefix,prefix_sep
- 在pandas.DataFrame 中指定列的虚拟数字/布尔列:columns
- 任意数字化每个类别(级别):map()方法
以下数据用作示例。
import pandas as pd
import numpy as np
df = pd.read_csv('./data/44/sample_pandas_normal.csv', index_col=0)
df['sex'] = ['female', np.nan, 'male', 'male', 'female', 'male']
df['rank'] = [2, 1, 1, 0, 2, 0]
print(df)
# age state point sex rank
# name
# Alice 24 NY 64 female 2
# Bob 42 CA 92 NaN 1
# Charlie 18 CA 70 male 1
# Dave 68 TX 70 male 0
# Ellen 24 CA 88 female 2
# Frank 30 NY 57 male 0
pandas.get_dummies()的基本用法
指定 pandas.Series、array(Python 列表、NumPy 数组 ndarray 等)和 pandas.DataFrame 作为第一个参数数据。
无论哪种情况,都会返回 pandas.DataFrame 中的一个新对象。如果要更新原始对象,可以将其分配给原始对象,例如,如下所示。
df = pd.get_dummies(df)
将 pandas.Series 和数组指定为参数时
在 pandas.Series 和数组(Python 列表、NumPy 数组 ndarray 等)的情况下,类别名称将是列名称。
print(pd.get_dummies(df['sex']))
# female male
# name
# Alice 1 0
# Bob 0 0
# Charlie 0 1
# Dave 0 1
# Ellen 1 0
# Frank 0 1
print(pd.get_dummies(['male', 1, 1, 2]))
# 1 2 male
# 0 0 0 1
# 1 1 0 0
# 2 1 0 0
# 3 0 1 0
print(pd.get_dummies(np.arange(6)))
# 0 1 2 3 4 5
# 0 1 0 0 0 0 0
# 1 0 1 0 0 0 0
# 2 0 0 1 0 0 0
# 3 0 0 0 1 0 0
# 4 0 0 0 0 1 0
# 5 0 0 0 0 0 1
数组(Python 列表、NumPy 数组、ndarray 等)必须是一维数组。二维数组会导致错误。
# print(pd.get_dummies(np.arange(6).reshape((2, 3))))
# Exception: Data must be 1-dimensional
将 pandas.DataFrame 指定为参数时
对于pandas.DataFrame,默认情况下,数据类型dtype为object(主要是字符串)或category的所有列都是虚拟变量。
数值(int, float) 和Boolean bool 列不转换并保持不变。稍后将描述要虚拟化数值和布尔列时的设置。
在 pandas.DataFrame 的情况下,列名称将是原始列名称_类别名称。稍后将描述要更改的设置。
print(pd.get_dummies(df))
# age point rank state_CA state_NY state_TX sex_female sex_male
# name
# Alice 24 64 2 0 1 0 1 0
# Bob 42 92 1 1 0 0 0 0
# Charlie 18 70 1 1 0 0 0 1
# Dave 68 70 0 0 0 1 0 1
# Ellen 24 88 2 1 0 0 1 0
# Frank 30 57 0 0 1 0 0 1
排除第一类:drop_first
如果你想虚拟k个类别,你只需要k-1个虚拟变量,但是get_dummies()函数默认将它们转换为k个虚拟变量。 如果参数 drop_first = True,则排除第一个类别并转换为 k-1 虚拟变量。
print(pd.get_dummies(df, drop_first=True))
# age point rank state_NY state_TX sex_male
# name
# Alice 24 64 2 1 0 0
# Bob 42 92 1 0 0 0
# Charlie 18 70 1 0 0 1
# Dave 68 70 0 0 1 1
# Ellen 24 88 2 0 0 0
# Frank 30 57 0 1 0 1
缺失值NaN虚拟化:dummy_na
默认情况下,缺失值 NaN 被排除和处理。
如果要将 NaN 作为一个类别作为虚拟变量,请设置参数 dummy_na = True。 此时,对于不包含 NaN 的列,也会生成 NaN 虚拟变量。所有元素都是0。
print(pd.get_dummies(df, drop_first=True, dummy_na=True))
# age point rank state_NY state_TX state_nan sex_male sex_nan
# name
# Alice 24 64 2 1 0 0 0 0
# Bob 42 92 1 0 0 0 0 1
# Charlie 18 70 1 0 0 0 1 0
# Dave 68 70 0 0 1 0 1 0
# Ellen 24 88 2 0 0 0 0 0
# Frank 30 57 0 1 0 0 1 0
指定pandas.DataFrame的虚拟变量的列名:prefix,prefix_sep
以pandas.DataFrame为例,生成的虚拟变量的列名默认为原来的列名_类别名。
这可以通过参数 prefix 和 prefix_sep 进行更改。 类别名称。
参数前缀由字符串、字符串列表或字符串字典指定。
在字符串的情况下,所有前缀都是通用的。如果只想使用类别名称作为虚拟变量的列名称,请在空字符串’'中指定prefix和prefix_sep。
print(pd.get_dummies(df, drop_first=True, prefix='', prefix_sep=''))
# age point rank NY TX male
# name
# Alice 24 64 2 1 0 0
# Bob 42 92 1 0 0 0
# Charlie 18 70 1 0 0 1
# Dave 68 70 0 0 1 1
# Ellen 24 88 2 0 0 0
# Frank 30 57 0 1 0 1
在列表和字典的情况下,需要为要保留原始列名的列指定值。如果列表或字典中的元素数与要虚拟的列数不匹配,则会发生错误。
print(pd.get_dummies(df, drop_first=True, prefix=['ST', 'sex'], prefix_sep='-'))
# age point rank ST-NY ST-TX sex-male
# name
# Alice 24 64 2 1 0 0
# Bob 42 92 1 0 0 0
# Charlie 18 70 1 0 0 1
# Dave 68 70 0 0 1 1
# Ellen 24 88 2 0 0 0
# Frank 30 57 0 1 0 1
print(pd.get_dummies(df, drop_first=True, prefix={'state': 'ST', 'sex': 'sex'}, prefix_sep='-'))
# age point rank ST-NY ST-TX sex-male
# name
# Alice 24 64 2 1 0 0
# Bob 42 92 1 0 0 0
# Charlie 18 70 1 0 0 1
# Dave 68 70 0 0 1 1
# Ellen 24 88 2 0 0 0
# Frank 30 57 0 1 0 1
在pandas.DataFrame 中指定列的虚拟数字/布尔列:columns
如上所述,在pandas.DataFrame的情况下,默认情况下只有数据类型为dtype object(主要是字符串)或category的列被虚拟化。
如果在参数列中指定要虚拟的列的列名,则还可以虚拟数字或布尔列。未指定的列不会被虚拟化。
print(pd.get_dummies(df, drop_first=True, columns=['sex', 'rank']))
# age state point sex_male rank_1 rank_2
# name
# Alice 24 NY 64 0 0 1
# Bob 42 CA 92 0 1 0
# Charlie 18 CA 70 1 1 0
# Dave 68 TX 70 1 0 0
# Ellen 24 CA 88 0 0 1
# Frank 30 NY 57 1 0 0
如果您不想在列表中指定大量列,使用 astype() 将您想要虚拟的数字或布尔列的数据类型转换为对象可能更容易。
请注意,如果将列的数据类型转换为对象并更新原始对象,则在使用该列进行数值运算或布尔运算时需要返回原始类型。
df['rank'] = df['rank'].astype(object)
print(pd.get_dummies(df, drop_first=True))
# age point state_NY state_TX sex_male rank_1 rank_2
# name
# Alice 24 64 1 0 0 0 1
# Bob 42 92 0 0 0 1 0
# Charlie 18 70 0 0 1 1 0
# Dave 68 70 0 1 1 0 0
# Ellen 24 88 0 0 0 0 1
# Frank 30 57 1 0 1 0 0
任意数字化每个类别(级别):map()方法
如果要将字符串分类的每个类别替换为任意数值,而不是像虚拟变量那样为每个类别(级别)生成 0 或 1 列,请使用 map() 方法。
指定字典 {original value:converted value} 作为参数。
print(df['state'].map({'CA': 0, 'NY': 1, 'TX': 2}))
# name
# Alice 1
# Bob 0
# Charlie 0
# Dave 2
# Ellen 0
# Frank 1
# Name: state, dtype: int64
map() 是pandas.Series 的一个方法。如果要处理pandas.DataFrame的列并更新值,可以如下赋值给原列。
df['state'] = df['state'].map({'CA': 0, 'NY': 1, 'TX': 2})
print(df)
# age state point sex rank
# name
# Alice 24 1 64 female 2
# Bob 42 0 92 NaN 1
# Charlie 18 0 70 male 1
# Dave 68 2 70 male 0
# Ellen 24 0 88 female 2
# Frank 30 1 57 male 0