熊猫:创建一列,在另一列中包含“下一个”更改后的值

时间:2019-07-30 07:13:52

标签: python pandas dataframe search

我想从B列创建C列,而没有for循环...

数据框:

title = 'Daily Log  ';
value = $(txt).val().replace(/\n/g, '</tspan><tspan x="0" dy="1.2em">');

numberOfLines = $(txt).val().split("\n").length;
txt = '<text transform="translate(' + 560 + ', ' + 30 + ')"><tspan x="0" dy="1.2em">' + title + '</br>' + ' at ' + '</tspan></text>';
if (i == 0) {

  top += 100
  svgArr.push(txt);

}
i += 1;

基本上,我想获取B中下一个更改的值并将其设置为新的列C。

到目前为止,答案来自:Determining when a column value changes in pandas dataframe 我有:

# |  A  |  B |  C  
--+-----+----+-----
1 |  2  |  3 |  4
2 |  3  |  3 |  4
3 |  4  |  4 |  6
4 |  5  |  4 |  6
5 |  5  |  4 |  6
6 |  3  |  6 |  2
7 |  2  |  6 |  2
8 |  4  |  2 |  3  #< --- loop back around if possible (B value at index 1)

但是在那之后,我不确定如何在不使用循环的情况下创建C ...

编辑: @(Ayoub ZAROU)的答案回答了我的原始问题,但是,如果我们假设数据中存在循环,我注意到我的示例数据框未涵盖所有情况:

df_filtered = df[df['B'].diff() != 0]

在这种情况下,如果3的最后一个片段被认为是3的第一个片段的一部分,那么使用此解决方案,C中的最后两个值将是错误的。

一个简单的解决方法是将最后几个元素移到列表的开头,反之亦然

4 个答案:

答案 0 :(得分:3)

您可以尝试,请注意np.roll与大熊猫的转变相同,唯一的不同是,它允许您将值翻转, 在下面的内容中,c为您提供了没有变化的索引

c = (df.B.diff(-1) == 0)

c
Out[104]: 
0     True
1    False
2     True
3     True
4    False
5     True
6    False
7    False
Name: B, dtype: bool

我们然后将其中的值设置为使用np.roll产生的B列上的下一个值,并使用pandas.Series.where进行设置,请注意,在何处更改值,在何处更改列{{1 }}不是c

True

然后我们在熊猫上使用df['C'] = np.nan df['C'] = df.C.where(c, np.roll(df.B, -1)) df.C Out[107]: 0 NaN 1 4.0 2 NaN 3 NaN 4 6.0 5 NaN 6 2.0 7 3.0 Name: C, dtype: float64 填充其余行,并将其强制转换为bfill'列B, 因此,在全球范围内

dtype
c = (df.B.diff(-1) == 0)
df['C'] = np.nan
df['C'] = df.C.where(c, np.roll(df.B, -1)).bfill().astype(df.B.dtype)

答案 1 :(得分:3)

另一种方法是获取值更改:

In [11]: changes = (df.B != df.B.shift()).cumsum()

In [12]: changes
Out[12]:
0    1
1    1
2    2
3    2
4    2
5    3
6    3
7    4
Name: B, dtype: int64

和一个查找图:

In [13]: lookup = df.B[(df.B != df.B.shift())]

In [14]: lookup.at[len(lookup)] = df.B.iloc[0]

In [15]: lookup
Out[15]:
0    3
2    4
5    6
7    2
4    3
Name: B, dtype: int64

然后使用它们查找“下一个”:

In [16]: lookup.iloc[changes]
Out[16]:
2    4
2    4
5    6
5    6
5    6
7    2
7    2
4    3
Name: B, dtype: int64

要创建列,您需要忽略索引中的重复项:

In [17]: df["C"] = lookup.iloc[changes].values

答案 2 :(得分:1)

移动B,按原始df.B分组。最后,transformfillna

df.B.shift(-1).groupby([df.B]).transform('last').fillna(df.at[1,'B'])

Out[22]:
1    4.0
2    4.0
3    6.0
4    6.0
5    6.0
6    2.0
7    2.0
8    3.0
Name: B, dtype: float64

您还可以将np.rollassign一起使用,以创建列C并在B上分组transformC。这样,您就不需要shiftfillna

df.assign(C=np.roll(df.B,-1)).groupby('B').C.transform('last')

Out[36]:
1    4
2    4
3    6
4    6
5    6
6    2
7    2
8    3
Name: C, dtype: int64

答案 3 :(得分:0)

您可以使用pandas.DataFrame.shift。 让我们用一个例子来做。考虑一个数据框:

a = pd.DataFrame(columns=['a','b'], data=[[1,2], [5,6], [5,3]])
print(a)

Out[0]: 
   a  b
0  1  2
1  5  6
2  5  3

然后使用shift创建列'c'

a['c'] = a.b.shift(1)
Out[1]: 
   a  b    c
0  1  2  NaN
1  5  6  2.0
2  5  3  6.0

然后用列'c'减去列'b'。

a.c = a.b - a.c
Out[2]: 
   a  b    c
0  1  2  NaN
1  5  6  4.0
2  5  3 -3.0

这将为您提供下一个更改的值,即列“ b”和“ c”之间的差。 希望对您有所帮助。

相关问题