如何将一列字符串转换为数字?

How to convert a column of string to numerical?

我有这个 pandas 来自查询的数据框:

|    name    |    event    |
----------------------------
| name_1     | event_1     |
| name_1     | event_2     |
| name_2     | event_1     |

我需要将列事件转换为数字,或者类似这样的内容:

| name    | event_1 | event_2 |
-------------------------------
| name_1  | 1       | 0       |
| name_1  | 0       | 1       |
| name_2  | 1       | 0       |

在软件 rapidminer 中,我可以用运算符 "nominal to numerical" 来做到这一点,所以我假设在 python 中转换列的类型应该是有效的,但我可能会弄错。

最后,想法是对具有相同名称的列值求和,结果是 table,应该如下所示:

| name    | event_1 | event_2 |
-------------------------------
| name_1  | 1       | 1       |
| name_2  | 1       | 0       |

有一个函数 returns 什么是预期的?

重要提示:我无法对事件进行简单的计数,因为我不了解它们,并且事件对于用户来说是不同的

编辑:好吧,谢谢大家,我可以看到有多种方法可以做到这一点,你们能说出其中哪一种是最 pythonic 的方法吗?

一些实现方法

1)

In [366]: pd.crosstab(df.name, df.event)
Out[366]:
event   event_1  event_2
name
name_1        1        1
name_2        1        0

2)

In [367]: df.groupby(['name', 'event']).size().unstack(fill_value=0)
Out[367]:
event   event_1  event_2
name
name_1        1        1
name_2        1        0

3)

In [368]: df.pivot_table(index='name', columns='event', aggfunc=len, fill_value=0)
Out[368]:
event   event_1  event_2
name
name_1        1        1
name_2        1        0

4)

In [369]: df.assign(v=1).pivot(index='name', columns='event', values='v').fillna(0)
Out[369]:
event   event_1  event_2
name
name_1      1.0      1.0
name_2      1.0      0.0

选项 1
pir1pir1_5

df.set_index('name').event.str.get_dummies()

        event_1  event_2
name                    
name_1        1        0
name_1        0        1
name_2        1        0

然后你可以对索引求和

df.set_index('name').event.str.get_dummies().sum(level=0)

        event_1  event_2
name                    
name_1        1        1
name_2        1        0

选项 2
pir2
或者你可以点积

pd.get_dummies(df.name).T.dot(pd.get_dummies(df.event))

        event_1  event_2
name_1        1        1
name_2        1        0

选项 3
pir3
高级模式

i, r = pd.factorize(df.name.values)
j, c = pd.factorize(df.event.values)
n, m = r.size, c.size

b = np.bincount(i * m + j, minlength=n * m).reshape(n, m)

pd.DataFrame(b, r, c)

        event_1  event_2
name_1        1        1
name_2        1        0

时机

res.plot(loglog=True)

res.div(res.min(1), 0)

            pir1      pir2  pir3      john1     john2      john3
10      9.948396  3.399913   1.0  20.478368  4.460466  10.642113
30      9.350524  2.681178   1.0  16.589248  3.847666   9.168907
100    11.414536  3.079463   1.0  18.076040  4.277752   9.949305
300    15.769594  2.940529   1.0  16.745889  3.945470   9.069265
1000   26.869451  2.617564   1.0  12.789570  3.236390   7.279205
3000   42.229542  2.099541   1.0   8.716600  2.429847   4.785814
10000  52.571678  1.716088   1.0   4.597598  1.691989   2.800455
30000  58.644764  1.469827   1.0   2.818744  1.535012   1.929452

函数

pir1 = lambda df: df.set_index('name').event.str.get_dummies().sum(level=0)
pir1_5 = lambda df: pd.get_dummies(df.set_index('name').event).sum(level=0)
pir2 = lambda df: pd.get_dummies(df.name).T.dot(pd.get_dummies(df.event))

def pir3(df):
    i, r = pd.factorize(df.name.values)
    j, c = pd.factorize(df.event.values)
    n, m = r.size, c.size

    b = np.bincount(i * m + j, minlength=n * m).reshape(n, m)

    return pd.DataFrame(b, r, c)

john1 = lambda df: pd.crosstab(df.name, df.event)
john2 = lambda df: df.groupby(['name', 'event']).size().unstack(fill_value=0)
john3 = lambda df: df.pivot_table(index='name', columns='event', aggfunc='size', fill_value=0)

测试

res = pd.DataFrame(
    index=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    columns='pir1 pir2 pir3 john1 john2 john3'.split(),
    dtype=float
)

for i in res.index:
    d = pd.concat([df] * i, ignore_index=True)
    for j in res.columns:
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        res.at[i, j] = timeit(stmt, setp, number=100)

您要求的是 pythonic 方式,我认为 python 这种方式是使用一种称为 one-hot encoding 的技术在像 sklearn 这样的库中得到很好的实现,在一次热编码之后,您需要按第一列对数据帧进行分组并应用求和函数。

这是一个代码:

import pandas as pd #the useful libraries
import numpy as np
from sklearn.preprocessing import LabelBinarizer #form sklmearn
dataset = pd.DataFrame([['name_1', 'event_1' ], ['name_1', 'event_2'], ['name_2', 'event_1']], columns=['name', 'event'], index=[1, 2, 3])
data = dataset['event'] #just reproduce your dataframe
enc = LabelBinarizer(neg_label=0)
dataset['event_2'] = enc.fit_transform(data)
event_two = dataset['event_2']
dataset['event_1'] = (~event_two.astype(np.bool)).astype(np.int64) #this is a tip to reproduce the event_1 columns
dataset = dataset.groupby('name').sum()
dataset.reset_index(inplace=True)

输出为: