更改熊猫数据框中预选元素中的列

时间:2018-09-09 17:45:01

标签: python pandas dataframe

我们有一个包含三个不同列的数据框,如上面的示例( df )所示。 此任务的目标是每次 1 列中的字母更改时,用np.nan替换 2 列的第一个元素。由于所研究的数据库非常大,因此不能用于for循环。而且,涉及到轮班的每个解决方案都被排除在外,因为它太慢了。

我相信最简单的方法是使用 groupby head 方法,但是我不知道如何在原始数据框中替换。

示例:

df = pd.DataFrame([['A','Z',1.11],['B','Z',2.1],['C','Z',3.1],['D', 'X', 2.1], ['E','X',4.3],['E', 'X', 2.1], ['F','X',4.3]])

enter image description here

要选择我们要更改的元素,我们可以执行以下操作:

df.groupby(by=1).head(1)[2] = np.nan

但是在原始数据框中没有任何变化。
目的是获得以下内容:

enter image description here

编辑:

根据评论,我们不会df[1]返回到已经看到的群组,例如['Z', 'Z', 'X', 'Z']是不可能的。

5 个答案:

答案 0 :(得分:5)

使用maskshift

df[2] = df[2].mask(df[1].ne(df[1].shift(1)))

使用masked_array

df[2] = np.ma.masked_array(df[2], df[1].ne(df[1].shift(1))).filled(np.nan)
# array([nan, 2.1, 3.1, nan, 4.3, 2.1, 4.3])

使用np.rollloc

a = df[1].values
df.loc[np.roll(a, 1)!=a, 2] = np.nan

   0  1    2
0  A  Z  NaN
1  B  Z  2.1
2  C  Z  3.1
3  D  X  NaN
4  E  X  4.3
5  E  X  2.1
6  F  X  4.3

答案 1 :(得分:5)

您可以使用numpy.where进行矢量化条件分配。假设df[1]已经排序。

df[2] = np.where(df[1].duplicated(), df[2], np.nan)

如果无法进行排序:

df[2] = np.where(df[1] != df[1].shift(), np.nan, df[2])

结果:

   0  1    2
0  A  Z  NaN
1  B  Z  2.1
2  C  Z  3.1
3  D  X  NaN
4  E  X  4.3
5  E  X  2.1
6  F  X  4.3

可以使用pd.DataFrame.mask来应用等效逻辑。

答案 2 :(得分:5)

使用

df[2].mask(df.groupby(1).cumcount().eq(0))
Out[41]: 
0    NaN
1    2.1
2    3.1
3    NaN
4    4.3
5    2.1
6    4.3
Name: 2, dtype: float64

#df[2] = df[2].mask(df.groupby(1).cumcount().eq(0))

答案 3 :(得分:4)

为速度而建

a = df[1].values
b = np.flatnonzero(np.append(True, a[1:] != a[:-1]))
df[2].values[b] = np.nan

df

   0  1    2
0  A  Z  NaN
1  B  Z  2.1
2  C  Z  3.1
3  D  X  NaN
4  E  X  4.3
5  E  X  2.1
6  F  X  4.3

答案 4 :(得分:2)

您可以从groupby中获取索引,并将其用作.loc的掩码。

import pandas as pd
import numpy as np

df = pd.DataFrame([
    ['A','Z',1.11],
    ['B','Z',2.1],
    ['C','Z',3.1],
    ['D', 'X', 2.1], 
    ['E','X',4.3],
    ['E', 'X', 2.1], 
    ['F','X',4.3]
])

m = df.groupby(by=1).head(1).index
df.loc[m,2] = np.nan

print(df)

OR ,您可以改用重复的()。这应该更快。

m = ~df[1].duplicated()
df.loc[m, 2] = np.nan

返回:

   0  1    2
0  A  Z  NaN
1  B  Z  2.1
2  C  Z  3.1
3  D  X  NaN
4  E  X  4.3
5  E  X  2.1
6  F  X  4.3