将所选的整数值替换为带有Pandas的值列表

时间:2017-12-21 08:52:04

标签: python pandas

我有一个pandas数据框,其中包含#34; Survived" 该列有两个可能的值:1和0 我想用[1,0]和0替换为[0,1]。

这些是我尝试过的方法:

首先将列数据类型从int转换为object:

data["Survived"] = data["Survived"].astype(object)

然后尝试更改值(它们都可以使用整数,但不能使用列表):

data["Survived"][data["Survived"] == 1] = 5 # works
data["Survived"][data["Survived"] == 1] = [1, 0] # ValueError: cannot assign mismatch length to masked array
data["Survived"][::].replace(1, 5) # works
data["Survived"][::].replace(1, [1, 0]) # {TypeError}Invalid "to_replace" type: 'int'

以及导致这些错误的其他一些类似方法。

奇怪的是,我可以将值设置为逐个列出 因此,如果我遍历所有条目,我可以将它们全部更改为列表(这给出了我想要的结果):

for i, val in enumerate(data["Survived"]):
    data["Survived"][i] = [1, 0] if val == 1 else [0, 1]

这怎么样,既缓慢又丑陋。大熊猫做这件事的方式是什么?

3 个答案:

答案 0 :(得分:5)

您可以将numpy.where用于广播:

data["Survived"] = np.where((data["Survived"] == 1)[:, None], [1,0],[0,1]).tolist()

答案 1 :(得分:3)

如果您的数据框只包含0和1,则可以使用:

data.loc[:, 'Survived'] = data.Survived.apply(lambda x: [0,1] if x == 0 else [1,0])

检查比较中的类型

修改

IMO基于get_dummies的答案不是最佳的,因为您需要在您的级别导入numpy,因此使用np.where的答案都不是最佳的。

以下是使用apply + lambdanp.whereget_dummies提出的解决方案所用时间的基准。

x轴是行数的log10(即7表示1e7行= 1000万行)。

Benchmark of the solutions

总结:

  • 对于较少数量的商品,几乎没有差异。

  • 最佳(略有)效果解决方案为np.where,但您需要导入numpy

  • 第二个最佳选择apply非常接近第一个。

编辑2

按要求设置此处。

import pandas as pd
import numpy as np
import time

perfdf = pd.DataFrame(index=[3, 4, 5, 6, 7], columns=['apply', 'where', 'get_dummies'])
for s in perfdf.index:
    data = pd.DataFrame({'Survived':np.random.randint(low=0,high=2, size=10**s)})

    tstart = time.time()   
    pd.get_dummies(data.Survived).values[:, ::-1].tolist()
    tstop = time.time()
    perfdf.loc[s, 'get_dummies'] = tstop - tstart

    tstart = time.time()
    np.where((data["Survived"] == 1)[:, None], [1,0],[0,1]).tolist()
    tstop = time.time()
    perfdf.loc[s, 'where'] = tstop - tstart

    tstart = time.time()
    data.Survived.apply(lambda x: [0,1] if x == 0 else [1,0])
    tstop = time.time()
    perfdf.loc[s, 'apply'] = tstop - tstart

perfdf

答案 2 :(得分:3)

选项1
使用get_dummies

df

   Survived
0         1
1         0
2         1
3         0
4         0
5         1
6         1
7         0

df['Survived'] = pd.get_dummies(df.Survived).values[:, ::-1].tolist()
df

  Survived
0   [1, 0]
1   [0, 1]
2   [1, 0]
3   [0, 1]
4   [0, 1]
5   [1, 0]
6   [1, 0]
7   [0, 1]

选项2
或者,使用numpy索引,假设您的列只有0和1。

i = np.array([[0, 1], [1, 0]])
df['Survived'] = i[df['Survived'].values].tolist()

df

  Survived
0   [1, 0]
1   [0, 1]
2   [1, 0]
3   [0, 1]
4   [0, 1]
5   [1, 0]
6   [1, 0]
7   [0, 1]

<强>计时

df = pd.concat([df] * 100000, ignore_index=True)
%timeit pd.get_dummies(df.Survived).values[:, ::-1].tolist()
1 loop, best of 3: 295 ms per loop
%timeit i[df['Survived'].values].tolist()
1 loop, best of 3: 273 ms per loop
%timeit np.where((df["Survived"] == 1)[:, None], [1,0],[0,1]).tolist()
1 loop, best of 3: 285 ms per loop
%timeit df.Survived.apply(lambda x: [0,1] if x == 0 else [1,0])
1 loop, best of 3: 368 ms per loop

所有这些解决方案都具有同等竞争力。这是一个选择问题,你决定使用哪一个。