Python 将数据帧中的值从字符串映射到int(例如,带有性别)

Python 将数据帧中的值从字符串映射到int(例如,带有性别),python,pandas,mapping,Python,Pandas,Mapping,我有一个名为df_base的数据帧,看起来像这样。正如你所看到的,有一个名为Sex的专栏,它是男性或女性。我想将这些值分别映射到0和1 +---+-------------+----------+--------+---------------------------------------------------+--------+-----+-------+-------+------------------+---------+-------+----------+ | | Passe

我有一个名为
df_base
的数据帧,看起来像这样。正如你所看到的,有一个名为
Sex
的专栏,它是
男性
女性
。我想将这些值分别映射到0和1

+---+-------------+----------+--------+---------------------------------------------------+--------+-----+-------+-------+------------------+---------+-------+----------+
|   | PassengerId | Survived | Pclass |                       Name                        |  Sex   | Age | SibSp | Parch |      Ticket      |  Fare   | Cabin | Embarked |
+---+-------------+----------+--------+---------------------------------------------------+--------+-----+-------+-------+------------------+---------+-------+----------+
| 0 |           1 |        0 |      3 | Braund, Mr. Owen Harris                           | male   |  22 |     1 |     0 | A/5 21171        |    7.25 | NaN   | S        |
| 1 |           2 |        1 |      1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female |  38 |     1 |     0 | PC 17599         | 71.2833 | C85   | C        |
| 2 |           3 |        1 |      3 | Heikkinen, Miss. Laina                            | female |  26 |     0 |     0 | STON/O2. 3101282 |   7.925 | NaN   | S        |
| 3 |           4 |        1 |      1 | Futrelle, Mrs. Jacques Heath (Lily May Peel)      | female |  35 |     1 |     0 | 113803           |    53.1 | C123  | S        |
| 4 |           5 |        0 |      3 | Allen, Mr. William Henry                          | male   |  35 |     0 |     0 | 373450           |    8.05 | NaN   | S        |
+---+-------------+----------+--------+---------------------------------------------------+--------+-----+-------+-------+------------------+---------+-------+----------+
我在StackOverflow上看到了一些方法,但我想知道最有效的方法是执行以下映射:

+---------+---------+
| Old Sex | New Sex |
+---------+---------+
| male    |       0 |
| female  |       1 |
| female  |       1 |
| female  |       1 |
| male    |       0 |
+---------+---------+
我用这个:

df_base['Sex']。替换(['male','female'],[0,1],inplace=True)


。。。但我忍不住觉得这有点粗制滥造。有更好的方法吗?也有使用
.loc
的方法,但是它在数据帧的行中循环,所以效率较低,对吧?

我认为,如果
Sex
中有
男性
女性
的话,字典的使用会更好/更快:

df_base['Sex'] = df_base['Sex'].map(dict(zip(['male','female'],[0,1]))
什么是一样的:

df_base['Sex'] = df_base['Sex'].map({'male': 0,'female': 1})
如果仅存在
女性
男性
值,则解决方案将布尔掩码转换为整数
真/假
转换为
1,0

df_base['Sex'] = (df_base['Sex'] == 'female').astype(int)
性能

np.random.seed(2019)

import perfplot    

def ma(df):
    df = df.copy()
    df['Sex_new'] = df['Sex'].map({'male': 0,'female': 1})
    return df

def rep1(df):
    df = df.copy()
    df['Sex'] = df['Sex'].replace(['male','female'],[0,1])
    return df

def nwhere(df):
    df = df.copy()
    df['Sex_new'] = np.where(df['Sex'] == 'male', 0, 1)
    return df

def mask1(df):
    df = df.copy()
    df['Sex_new'] = (df['Sex'] == 'female').astype(int)
    return df

def mask2(df):
    df = df.copy()
    df['Sex_new'] = (df['Sex'].values == 'female').astype(int)
    return df


def make_df(n):
    df = pd.DataFrame({'Sex': np.random.choice(['male','female'], size=n)})

    return df

结论:

如果仅替换2个值是最慢的
replace
numpy.where、map和mask
。要提高性能,请将numpy数组与
值进行比较


也取决于数据,所以最好用真实数据进行测试。

我认为,如果
列中
性别
中只有
男性
女性
存在,那么字典使用起来更好/更快:

df_base['Sex'] = df_base['Sex'].map(dict(zip(['male','female'],[0,1]))
什么是一样的:

df_base['Sex'] = df_base['Sex'].map({'male': 0,'female': 1})
如果仅存在
女性
男性
值,则解决方案将布尔掩码转换为整数
真/假
转换为
1,0

df_base['Sex'] = (df_base['Sex'] == 'female').astype(int)
性能

np.random.seed(2019)

import perfplot    

def ma(df):
    df = df.copy()
    df['Sex_new'] = df['Sex'].map({'male': 0,'female': 1})
    return df

def rep1(df):
    df = df.copy()
    df['Sex'] = df['Sex'].replace(['male','female'],[0,1])
    return df

def nwhere(df):
    df = df.copy()
    df['Sex_new'] = np.where(df['Sex'] == 'male', 0, 1)
    return df

def mask1(df):
    df = df.copy()
    df['Sex_new'] = (df['Sex'] == 'female').astype(int)
    return df

def mask2(df):
    df = df.copy()
    df['Sex_new'] = (df['Sex'].values == 'female').astype(int)
    return df


def make_df(n):
    df = pd.DataFrame({'Sex': np.random.choice(['male','female'], size=n)})

    return df

结论:

如果仅替换2个值是最慢的
replace
numpy.where、map和mask
。要提高性能,请将numpy数组与
值进行比较


也取决于数据,因此最好使用真实数据进行测试。

另一种解决方案可以与
np一起使用。其中

只是一个示例数据帧:

>>> df
      Sex
0    male
1  female
2  female
3  female
4    male
>>> df['new_Sex'] = np.where(df['Sex'] != 'male', 1, 0)
>>> df
      Sex  new_Sex
0    male        0
1  female        1
2  female        1
3  female        1
4    male        0
根据条件创建新列
new\u Sex

>>> df['new_Sex'] = np.where(df['Sex'] == 'male', 0, 1)
>>> df
      Sex  new_Sex
0    male        0
1  female        1
2  female        1
3  female        1
4    male        0
或:

>>> df
      Sex
0    male
1  female
2  female
3  female
4    male
>>> df['new_Sex'] = np.where(df['Sex'] != 'male', 1, 0)
>>> df
      Sex  new_Sex
0    male        0
1  female        1
2  female        1
3  female        1
4    male        0

可与
np一起使用的另一种解决方案。其中

只是一个示例数据帧:

>>> df
      Sex
0    male
1  female
2  female
3  female
4    male
>>> df['new_Sex'] = np.where(df['Sex'] != 'male', 1, 0)
>>> df
      Sex  new_Sex
0    male        0
1  female        1
2  female        1
3  female        1
4    male        0
根据条件创建新列
new\u Sex

>>> df['new_Sex'] = np.where(df['Sex'] == 'male', 0, 1)
>>> df
      Sex  new_Sex
0    male        0
1  female        1
2  female        1
3  female        1
4    male        0
或:

>>> df
      Sex
0    male
1  female
2  female
3  female
4    male
>>> df['new_Sex'] = np.where(df['Sex'] != 'male', 1, 0)
>>> df
      Sex  new_Sex
0    male        0
1  female        1
2  female        1
3  female        1
4    male        0

我的直觉可能会建议使用
.map()
,但我基于一个包含1500个随机男性/女性值的数据框,将您的解决方案与map进行了比较

%timeit df_base['Sex_new'] = df_base['Sex'].map({'male': 0,'female': 1})
1000 loops, best of 3: 653 µs per loop
根据coldspeeds注释进行编辑,因为重新指定它与其他注释相比更好:

%timeit df_base['Sex_new'] = df_base['Sex'].replace(['male','female'],[0,1])
1000 loops, best of 3: 968 µs per loop
所以实际上要慢一点
.map()

因此,基于此示例,您的“劣质”解决方案似乎比
.map()

编辑

pygo的解决方案:

%timeit df_base['Sex_new'] = np.where(df_base['Sex'] == 'male', 0, 1)
1000 loops, best of 3: 331 µs per loop
太快了

Jezrael的解决方案具有
.astype(int)


因此也比
.map()
.replace()
更快

我的直觉会建议使用
.map()
,但我基于一个包含1500个随机男性/女性值的数据框,对您的解决方案和map进行了比较

%timeit df_base['Sex_new'] = df_base['Sex'].map({'male': 0,'female': 1})
1000 loops, best of 3: 653 µs per loop
根据coldspeeds注释进行编辑,因为重新指定它与其他注释相比更好:

%timeit df_base['Sex_new'] = df_base['Sex'].replace(['male','female'],[0,1])
1000 loops, best of 3: 968 µs per loop
所以实际上要慢一点
.map()

因此,基于此示例,您的“劣质”解决方案似乎比
.map()

编辑

pygo的解决方案:

%timeit df_base['Sex_new'] = np.where(df_base['Sex'] == 'male', 0, 1)
1000 loops, best of 3: 331 µs per loop
太快了

Jezrael的解决方案具有
.astype(int)



因此也比
.map()
.replace()
更快

为什么我看不到有人建议重复,而问题实际上是重复的?@coldspeed,我从未了解过这条线索,所以不能将其作为重复播放。@pygo我不反对有人建议重复,但我不喜欢双重标准。我在任何地方都能看到它,而且对某些用户来说比其他用户要多。@coldspeed-是的,标准解决方案是replace/map,但如果OP需要性能,还有其他解决方案,所以不会被我愚弄。@jezrael每个问题都可以用这种推理来解决。我相信你以前也用过同样的推理来回答类似的问题,所以找一个,并标记为dupe。或者向复制目标添加答案。这样你会比一遍又一遍地回答这样的问题得到更多的支持。为什么我看不到有人建议重复,而这个问题实际上是重复的?@coldspeed,我从来都不知道这个帖子,所以不能将它作为重复播放。@pygo我不反对有人建议重复,但我不喜欢双重标准。我在任何地方都能看到它,而且对某些用户来说比其他用户要多。@coldspeed-是的,标准解决方案是replace/map,但如果OP需要性能,还有其他解决方案,所以不会被我愚弄。@jezrael每个问题都可以用这种推理来解决。我相信你以前也用过同样的推理来回答类似的问题,所以找一个,并标记为dupe。或者向复制目标添加答案。通过这种方式,你将获得更多的代表性,而不是一遍又一遍地回答这样的问题。关于
df['Old_Sex']=np.where(df['Sex']='male',0,1)
comparations?并检查
map/replace
comparisonYes,使用numpy的解决方案将更快。注意
df_base['Sex'].replace(['male','female',',',',0,1],inplace=True)
将不起作用,因为带有replace的系列上的
inplace=True
有问题的历史记录。重新分配。感谢您的计时,但我还有其他问题,
replace
对我来说比较慢,请检查我的答案。您测试性能的代码是什么?关于
df['Old_Sex']=np。其中(df['Sex']='male',0,1)
比较?并检查<