编码分类变量,使得字符的存在和位置在文字字符串中都很重要
Encoding categorical variables such that both the presence as well as the position of characters matter in literal strings
假设我们有一个数据框,其最后一列由如下文字字符串组成:
df = pd.DataFrame(
{
"col1": ["C", "A", "B"],
"col2": [4, 1.7, 1],
"col3": ["SHRTYPPS", "PGYTCCCKAR", "VPCCYCCARE"],
}
)
请注意,1) 字符在字符串中的存在和 2) 它在字符串中的位置都很重要。
单热编码最后一列如下:
col3_lst = [list(i) for i in df.col3]
ids, U = pd.factorize(np.concatenate(col3_lst))
df_new = pd.DataFrame([np.isin(U, i) for i in col3_lst], columns=U).astype(int)
pd.concat([df, df_new], axis=1).drop(["col3"], axis=1)
这将导致:
col1 col2 S H R T Y P G C K A V E
0 C 4.0 1 1 1 1 1 1 0 0 0 0 0 0
1 A 1.7 0 0 1 1 1 1 1 1 1 1 0 0
2 B 1.0 0 0 1 0 1 1 0 1 0 1 1 1
但是,如您所见,订单并未得到相应处理。无论如何将有关字符在相应字符串中的位置的信息注入到输出数据帧中?例如,如果最后一个字符串中有四个 C,我们需要捕获该字母明显出现在第 3、4、6 和 7 位的事实信息。我正在寻找类似以下内容的内容:
col1 col2 position_1 posistion_2 position_3 position_4 position_5 ....
0 C 4.0 19 8 18 20 25 ....
1 A 1.7 16 7 25 20 3 ....
2 B 1.0 22 16 3 3 25 ....
,其中编码列的每个数字标签,$position_{i}$
,属于英文字母表中后续字符的位置;即 A 为 1,B 为 2,等等...
或者更好的是,类似于以下内容:
col1 col2 position_1_A position_1_B ... posistion_2_A posistion_2_B ... position_3_A position_3_B ... position_4_A position_4_B ...
0 C 4.0 0 0 ... 0 0 ... 0 0 ... 0 0 ...
1 A 1.7 0 0 ... 0 0 ... 0 0 ... 0 0 ...
2 B 1.0 0 0 ... 0 0 ... 0 0 ... 0 0 ...
谢谢,
好的,像这样应该可以解决问题:
result = df["col3"].str.upper()\
.str.extractall("(.)")\
.unstack().droplevel(0, axis=1)\
.add_prefix('position_')
result.applymap(lambda x: ord(x) - 64 if pd.notna(x) else x)
在第一步中我们提取所有字符(我使用 extractall("(.)")
而不是 split("")
来不处理额外的字符 (\n)。
在第二个中,我们将字母映射到数字。
结果看起来像这样:
match position_0 position_1 position_2 position_3 position_4 position_5 position_6 position_7 position_8 position_9
0 19 8 18 20 25 16 16 19 NaN NaN
1 16 7 25 20 3 3 3 11 1 18.0
2 22 16 3 3 25 3 3 1 18 5.0
编辑:如果你想做一个 hot_encoding 使用 pd.get_dummies()
result = df["col3"].str.upper()\
.str.extractall("(.)")\
.unstack().droplevel(0, axis=1)\
.add_prefix('position_')
pd.get_dummies(result)
哪个可以给你:
position_0_P position_0_S position_0_V ... position_9_R
0 0 1 0 ... 0
1 1 0 0 ... 1
2 0 0 1 ... 0
编辑 2:
如果您已经将缺失编码为 .
,并且您希望使用序数编码将它们编码为缺失,则必须将 .
替换为 np.nan
:
result = df["col3"].str.upper()\
.str.extractall("(.)")\
.unstack().droplevel(0, axis=1)\
.add_prefix('position_')\
.replace('.',np.nan)
其他一切保持不变。
例如:
df = pd.DataFrame(
{
"col1": ["C", "A", "B", "D"],
"col2": [4, 1.7, 1, 12],
"col3": ["SHRTYPPS", "PGYTCCCKAR", "VPCCYCCARE", "HY.RT..CCTCC"],
}
)
result = df["col3"].str.upper().str.extractall("(.)").unstack().droplevel(0, axis=1).add_prefix('position_').replace('.',np.nan)
result.applymap(lambda x: ord(x) - 64 if pd.notna(x) else x)
#match position_0 position_1 position_2 ... position_11
#0 19 8 18.0 ... NaN
#1 16 7 25.0 ... NaN
#2 22 16 3.0 ... NaN
#3 8 25 NaN ... 3.0
pd.get_dummies(result)
# position_0_H position_0_P position_0_S position_0_V ... position_10_C position_11_C
#0 0 0 1 0 ... 0 0
#1 0 1 0 0 ... 0 0
#2 0 0 0 1 ... 0 0
#3 1 0 0 0 ... 1 1
编辑 3:
如果您想将某些组(例如括号中的组)视为一个字符,您应该修改正则表达式以将其捕获为一个组。在这种情况下,如上所示的序号编码将不起作用(因为它占据了字母表中单个字母的位置)。但是 one-hot 编码应该可以正常工作。例如:
df = pd.DataFrame(
{
"col1": ["C", "D"],
"col2": [4, 12],
"col3": ["SHRTYPPS(hr3)", "HY.RT..CCTCC(hr4)"],
}
)
result = df["col3"].str.extractall("(\(.*\)|.)")\
.unstack().droplevel(0, axis=1)\
.add_prefix('position_')\
.replace('.',np.nan)\
.apply(lambda x: x.str.replace(r'[\(\)]+', '', regex = True))
pd.get_dummies(result)
# position_0_H position_0_S ... position_11_C position_12_hr4
#0 0 1 ... 0 0
#1 1 0 ... 1 1
最后一个应用只是为了去掉列名中的括号,它可以被删除,如果名称 position_12_(hr4)
比 position_12_hr4
更好。
假设我们有一个数据框,其最后一列由如下文字字符串组成:
df = pd.DataFrame(
{
"col1": ["C", "A", "B"],
"col2": [4, 1.7, 1],
"col3": ["SHRTYPPS", "PGYTCCCKAR", "VPCCYCCARE"],
}
)
请注意,1) 字符在字符串中的存在和 2) 它在字符串中的位置都很重要。
单热编码最后一列如下:
col3_lst = [list(i) for i in df.col3]
ids, U = pd.factorize(np.concatenate(col3_lst))
df_new = pd.DataFrame([np.isin(U, i) for i in col3_lst], columns=U).astype(int)
pd.concat([df, df_new], axis=1).drop(["col3"], axis=1)
这将导致:
col1 col2 S H R T Y P G C K A V E
0 C 4.0 1 1 1 1 1 1 0 0 0 0 0 0
1 A 1.7 0 0 1 1 1 1 1 1 1 1 0 0
2 B 1.0 0 0 1 0 1 1 0 1 0 1 1 1
但是,如您所见,订单并未得到相应处理。无论如何将有关字符在相应字符串中的位置的信息注入到输出数据帧中?例如,如果最后一个字符串中有四个 C,我们需要捕获该字母明显出现在第 3、4、6 和 7 位的事实信息。我正在寻找类似以下内容的内容:
col1 col2 position_1 posistion_2 position_3 position_4 position_5 ....
0 C 4.0 19 8 18 20 25 ....
1 A 1.7 16 7 25 20 3 ....
2 B 1.0 22 16 3 3 25 ....
,其中编码列的每个数字标签,$position_{i}$
,属于英文字母表中后续字符的位置;即 A 为 1,B 为 2,等等...
或者更好的是,类似于以下内容:
col1 col2 position_1_A position_1_B ... posistion_2_A posistion_2_B ... position_3_A position_3_B ... position_4_A position_4_B ...
0 C 4.0 0 0 ... 0 0 ... 0 0 ... 0 0 ...
1 A 1.7 0 0 ... 0 0 ... 0 0 ... 0 0 ...
2 B 1.0 0 0 ... 0 0 ... 0 0 ... 0 0 ...
谢谢,
好的,像这样应该可以解决问题:
result = df["col3"].str.upper()\
.str.extractall("(.)")\
.unstack().droplevel(0, axis=1)\
.add_prefix('position_')
result.applymap(lambda x: ord(x) - 64 if pd.notna(x) else x)
在第一步中我们提取所有字符(我使用 extractall("(.)")
而不是 split("")
来不处理额外的字符 (\n)。
在第二个中,我们将字母映射到数字。
结果看起来像这样:
match position_0 position_1 position_2 position_3 position_4 position_5 position_6 position_7 position_8 position_9
0 19 8 18 20 25 16 16 19 NaN NaN
1 16 7 25 20 3 3 3 11 1 18.0
2 22 16 3 3 25 3 3 1 18 5.0
编辑:如果你想做一个 hot_encoding 使用 pd.get_dummies()
result = df["col3"].str.upper()\
.str.extractall("(.)")\
.unstack().droplevel(0, axis=1)\
.add_prefix('position_')
pd.get_dummies(result)
哪个可以给你:
position_0_P position_0_S position_0_V ... position_9_R
0 0 1 0 ... 0
1 1 0 0 ... 1
2 0 0 1 ... 0
编辑 2:
如果您已经将缺失编码为 .
,并且您希望使用序数编码将它们编码为缺失,则必须将 .
替换为 np.nan
:
result = df["col3"].str.upper()\
.str.extractall("(.)")\
.unstack().droplevel(0, axis=1)\
.add_prefix('position_')\
.replace('.',np.nan)
其他一切保持不变。
例如:
df = pd.DataFrame(
{
"col1": ["C", "A", "B", "D"],
"col2": [4, 1.7, 1, 12],
"col3": ["SHRTYPPS", "PGYTCCCKAR", "VPCCYCCARE", "HY.RT..CCTCC"],
}
)
result = df["col3"].str.upper().str.extractall("(.)").unstack().droplevel(0, axis=1).add_prefix('position_').replace('.',np.nan)
result.applymap(lambda x: ord(x) - 64 if pd.notna(x) else x)
#match position_0 position_1 position_2 ... position_11
#0 19 8 18.0 ... NaN
#1 16 7 25.0 ... NaN
#2 22 16 3.0 ... NaN
#3 8 25 NaN ... 3.0
pd.get_dummies(result)
# position_0_H position_0_P position_0_S position_0_V ... position_10_C position_11_C
#0 0 0 1 0 ... 0 0
#1 0 1 0 0 ... 0 0
#2 0 0 0 1 ... 0 0
#3 1 0 0 0 ... 1 1
编辑 3:
如果您想将某些组(例如括号中的组)视为一个字符,您应该修改正则表达式以将其捕获为一个组。在这种情况下,如上所示的序号编码将不起作用(因为它占据了字母表中单个字母的位置)。但是 one-hot 编码应该可以正常工作。例如:
df = pd.DataFrame(
{
"col1": ["C", "D"],
"col2": [4, 12],
"col3": ["SHRTYPPS(hr3)", "HY.RT..CCTCC(hr4)"],
}
)
result = df["col3"].str.extractall("(\(.*\)|.)")\
.unstack().droplevel(0, axis=1)\
.add_prefix('position_')\
.replace('.',np.nan)\
.apply(lambda x: x.str.replace(r'[\(\)]+', '', regex = True))
pd.get_dummies(result)
# position_0_H position_0_S ... position_11_C position_12_hr4
#0 0 1 ... 0 0
#1 1 0 ... 1 1
最后一个应用只是为了去掉列名中的括号,它可以被删除,如果名称 position_12_(hr4)
比 position_12_hr4
更好。