使用pandas和numpy将字符串类别映射为数字

6

我有一个数据数组,每一行代表着一组数据样本(5个样本),每一列代表数据中的一个特征(每个样本有6个特征)。

我尝试量化每一列包含的状态数量,然后将它们映射到一组数字。仅当该列当前不是数值型时才应执行此操作。

通过示例更容易理解:

示例输入(输入类型为numpy.ndarray):

In = array([['x', 's', 3, 'k', 's', 'u'],
            ['x', 's', 2, 'n', 'n', 'g'],
            ['b', 's', 0, 'n', 'n', 'm'],
            ['k', 'y', 1, 'w', 'v', 'l'],
            ['x', 's', 2, 'o', 'c', 'l']], dtype=object)

第一列

curr_column = 0
colset = set()
for row in In:
    curr_element = row[curr_column]
    if curr_element not in colset:
        colset.add(curr_element)

#now colset = {'x', 'b', 'k'} so 3 possible states
collist = list(colset) #make it indexible
coldict = {}
for i in range(len(collist)):
    coldict[collist[i]] = i

这将生成一个字典,因此我现在可以按照以下方式重新创建原始数据: (假设coldict = {'x':0, 'b':1, 'k':2})
for i in range(len(In)): #loop over each row
    curr_element = In[i][curr_column] #get current element
    In[i][curr_column] = coldict[curr_element] #use it to find the numerical value
'''
now
In = array([[0, 's', 3, 'k', 's', 'u'],
            [0, 's', 2, 'n', 'n', 'g'],
            [1, 's', 0, 'n', 'n', 'm'],
            [2, 'y', 1, 'w', 'v', 'l'],
            [0, 's', 2, 'o', 'c', 'l']], dtype=object)
'''

现在对每一列重复这个过程。
我知道可以通过一次遍历数据集来填充所有列字典,然后再用一个循环替换所有值,以加快速度。但为了清楚起见,我省略了这一步。
这种方法在空间和时间上非常低效,在处理大量数据时需要大量时间。有哪些方法可以改进这个算法?是否有numpy或pandas中的映射函数可以完成或帮助我?
我考虑过类似于
np.unique(Input, axis=1)

但我需要这个是可移植的,并不是每个人都有numpy的1.13.0开发者版本。
另外,我该如何区分哪些列是数字列,哪些不是,以决定应用到哪些列?
2个回答

22

Pandas也有一个映射函数可以使用。假设你有这个将字符串映射到代码的字典:

codes = {'x':0, 'b':1, 'k':2}

你可以使用 map 函数来映射 pandas 数据帧中的列:

df[col] = df[col].map(codes)

6
您可以使用分类编码。请参见文档中的分类部分。 (链接)
In [11]: df
Out[11]:
   0  1  2  3  4  5
0  x  s  3  k  s  u
1  x  s  2  n  n  g
2  b  s  0  n  n  m

In [12]: for col in df.columns:
     ...:     df[col] = pd.Categorical(df[col], categories=df[col].unique()).codes

In [13]: df
Out[13]:
   0  1  2  3  4  5
0  0  0  0  0  0  0
1  0  0  1  1  1  1
2  1  0  2  1  1  2
3  2  1  3  2  2  3
4  0  0  1  3  3  3

我怀疑有一个小变化可以使得在不显式传递类别的情况下实现这个功能(注意:pandas保证.unique()是按顺序出现的)。


注意:要“区分数字列和非数字列”,你可以在迭代之前使用 select_dtypes

for col in df.select_dtypes(exclude=['int']).columns:
    ...

@Jeff 对我来说,它是按相反的顺序(或者可能是排序后的顺序?),即在我的(糟糕的复制)示例的第一列中是 2 2 1 0 2 - Andy Hayden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接