Pandas Dataframe:如何将一列拆分为多个单热编码列[重复]
Posted
技术标签:
【中文标题】Pandas Dataframe:如何将一列拆分为多个单热编码列[重复]【英文标题】:Pandas Dataframe: How to split one column into multiple one-hot-encoded columns [duplicate] 【发布时间】:2019-11-06 01:37:03 【问题描述】:我有一个这样的文本文件:
444537110 3 11112111022002200022022111121222002...
输入文件中的最终字段长度为 50k 个字符,并且只有 0,1 或 2。我想要这个最终字段的一个热编码版本。所以我的预期结果是这样的数据框:
id chip g1_0 g1_1 g1_2 g2_0 g2_1 g2_2 g3_0 g3_1 g3_2 g4_0 ...
444537110 3 0 1 0 0 1 0 0 1 0 0
我通过读取输入文件创建了一个初始数据框:
df = pd.read_csv('test.txt', index_col=0, sep='\s+', header=None, names = ['chip', 'genos'])
这将创建一个包含 3 列的数据框:
id chip genos
444537110 3 1111211102200220000022022111121222000200022002...
我认为我可以使用类似下面的方法创建初始的单个列,然后使用 pandas get_dummies 函数进行一个热编码,但我无法创建单个列。我试过了
[c for c in df['genos'].str]
但这并没有分隔字符
我在这里看过一个类似的问题和答案:How can I one hot encode in Python?
但这仅处理一种热编码,不处理拆分非常大的列所增加的复杂性
【问题讨论】:
猜你可能需要df['genos'].str.get_dummies()
,但不确定提供的数据
刚刚尝试了这个建议,但没有奏效。它返回一个数据框,其中有一列以 genos 作为列标题,只有一个值
@daragh 你能假装你的最后一列只有 3 个字符而不是 50k,然后发布一些多行样本输入和完整的所需 OHE 输出吗?这将使您的意图更加清晰。因为就目前而言,听起来您想要 OHE 一个字段,该字段可能包含 3 到 50k 个不同值的幂,这似乎是个坏主意(即 waaaaay 列太多而无用)
@Dan 我将生成的数据帧提供给神经网络,所以我确实希望有 150k 列
【参考方案1】:
首先创建DataFrame
并将字符串转换为列表并调用get_dummies
:
df1 = pd.DataFrame([list(x) for x in df['genos']], index=df.index).add_prefix('g')
df2 = pd.get_dummies(df1)
如果需要将新列添加到原始列(如果可能缺少某些组合),请使用 DataFrame.reindex
拆分列与 _
以及由 MultiIndex.from_product
创建的所有组合:
df1 = pd.DataFrame([list(x) for x in df.pop('genos')], index=df.index).add_prefix('g')
df2 = pd.get_dummies(df1)
splitted = df2.columns.str.split('_')
df2.columns = [splitted.str[0].astype(int) + 1, splitted.str[1].astype(int)]
#
mux = pd.MultiIndex.from_product([df2.columns.get_level_values(0), [0,1,2]])
df2 = df2.reindex(mux, axis=1, fill_value=0)
df2.columns = [f'ga_b' for a, b in df2.columns]
print (df2)
g1_0 g1_1 g1_2 g2_0 g2_1 g2_2 g3_0 g3_1 g3_2 g4_0 ... g32_2 \
0 0 1 0 0 1 0 0 1 0 0 ... 1
g33_0 g33_1 g33_2 g34_0 g34_1 g34_2 g35_0 g35_1 g35_2
0 1 0 0 1 0 0 0 0 1
[1 rows x 105 columns]
【讨论】:
你确定这给出了正确的输出吗? genos的第一个基因应该编码为g1_X
(X取决于它的值)
@SebastienD - 抱歉,现在是晚餐时间,所以现在编辑了答案。【参考方案2】:
考虑到@Dan 对您的问题的评论,即您将以 50k*3 列结尾,您可以通过这样做获得所需的输出:
string ="444537110 3 11112111022002200022022111121222002"
df = pd.DataFrame([string.split(" ")],columns=['id','chip','genos'])
max_number_of_genes = int(df.genos.apply(lambda x : len([y for y in x])).max())
#Create columns
for gene in range(1,max_number_of_genes+1):
for y in range(4):
df['g_'.format(gene, y)] = 0
#Iterating over genos values
for row_number, row in df.iterrows():
genos = [int(x) for x in df.iloc[row_number, 2]]
for gene_number, gene in enumerate(genos):
df.loc[row_number, 'g_'.format(gene_number+1, gene)] = 1
print(df)
输出
+----+------------+-------+--------------------------------------+-------+-------+-------+-------+-------+-------+-------+------+--------+--------+--------+--------+--------+--------+--------+--------+--------+-------+
| | id | chip | genos | g1_0 | g1_1 | g1_2 | g1_3 | g2_0 | g2_1 | g2_2 | ... | g33_2 | g33_3 | g34_0 | g34_1 | g34_2 | g34_3 | g35_0 | g35_1 | g35_2 | g35_3 |
+----+------------+-------+--------------------------------------+-------+-------+-------+-------+-------+-------+-------+------+--------+--------+--------+--------+--------+--------+--------+--------+--------+-------+
| 0 | 444537110 | 3 | 11112111022002200022022111121222002 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
+----+------------+-------+--------------------------------------+-------+-------+-------+-------+-------+-------+-------+------+--------+--------+--------+--------+--------+--------+--------+--------+--------+-------+
【讨论】:
【参考方案3】:如果您只拆分 50k 个字符,您可以使用原始 Python(为了便于阅读):
>>> a,b,c = zip(*[0:(1,0,0),1:(0,1,0),2:(0,0,1)[int(c)] for c in df['genos'][0]])
>>> a,b,c
((0, 0, 0, 0, 0, 0, ...), (1, 1, 1, 1, 0, 1, ...), (0, 0, 0, 0, 1, 0, ...))
【讨论】:
以上是关于Pandas Dataframe:如何将一列拆分为多个单热编码列[重复]的主要内容,如果未能解决你的问题,请参考以下文章
python使用pandas后如何利用DataFrame拆分列
如何将一列中的单词拆分然后在Python中将单词整合在一起,即二维列表到一维列表?