【问题标题】:Get first and last value for a sequence of pairs between two columns of a pandas dataframe获取熊猫数据框两列之间的对序列的第一个和最后一个值
【发布时间】:2020-11-25 17:12:23
【问题描述】:

我有一个包含 3 列 Replaced_IDNew_IDInstallation DateNew_ID 的数据框。

每个 New_ID 都会替换 Replaced_ID。

Replaced_ID      New_ID             Installation Date (of New_ID)
     3             5                    16/02/2018
     5             7                    17/05/2019
     7             9                    21/06/2019
     9             11                   23/08/2020
    25             39                   16/02/2017
    39             41                   16/08/2018

我的目标是获得一个包含序列的firstlast记录的数据框。我只关心第一个 Replaced_ID 值和最后一个 New_ID 值。

即从上面的数据框我想要这个

    Replaced_ID      New_ID             Installation Date (of New_ID)
        3              11                    23/08/2020
        25             41                    16/08/2018

据我所知,按日期排序并执行轮班并不是这里的解决方案。

另外,我尝试将列 New_IDReplaced_ID 连接起来,但事实并非如此,因为它只返回前一个序列。

我需要找到一种方法来获取序列 [3,5,7,9,11][25,41] 组合所有行的 Replaced_IDNew_ID 列。

我最关心的是获取第一个 Replaced_ID 值和最后一个 New_ID 值,而不是 Installation Date,因为我可以在最后执行连接。

这里有什么想法吗?谢谢。

【问题讨论】:

  • 合并Replaced_IDNew_ID的区间,然后将New_ID的结果映射到安装日期。
  • 合并区间是什么意思?

标签: python pandas


【解决方案1】:

首先,让我们创建 DataFrame:

import pandas as pd
import numpy as np
from io import StringIO

data = """Replaced_ID,New_ID,Installation Date (of New_ID)
3,5,16/02/2018
5,7,17/05/2019
7,9,21/06/2019
9,11,23/08/2020
25,39,16/02/2017
39,41,16/08/2018
11,14,23/09/2020
41,42,23/10/2020
"""
### note that I've added two rows to check whether it works with non-consecutive rows

### defining some short hands
r = "Replaced_ID"
n = "New_ID"
i = "Installation Date (of New_ID)"

df = pd.read_csv(StringIO(data),header=0,parse_dates=True,sep=",")
df[i] =  pd.to_datetime(df[i], )

现在是我的实际解决方案:

a = df[[r,n]].values.flatten()
### returns a flat list of r and n values which clearly show duplicate entries, i.e.:
#  [ 3  5  5  7  7  9  9 11 25 39 39 41 11 14 41 42]

### now only get values that occur once, 
#   and reshape them nicely, such that the first column gives the lowest (replaced) id,
#   and the second column gives the highest (new) id, i.e.:
#    [[ 3 14]
#     [25 42]]
u, c = np.unique( a, return_counts=True)
res = u[c == 1].reshape(2,-1)

### now filter the dataframe where "New_ID" is equal to the second column of res, i.e. [14,42]:
#   and replace the entries in "r" with the "lowest possible values" of r
dfn = df[  df[n].isin(res[:,1].tolist()) ]
# print(dfn)
dfn.loc[:][r] = res[:,0]
print(dfn)

产量:

   Replaced_ID  New_ID Installation Date (of New_ID)
6            3      14                    2020-09-23
7           25      42                    2020-10-23

【讨论】:

  • 此解决方案在这里有效,因为每个序列的最大 id 小于下一个序列的最小值。在这里,u, c = np.unique( a, return_counts=True) 进行排序工作。如果将 id 值 11 替换为 100,则输出应为 false。尽管我需要我在这里描述的解决方案(从 100 替换为 11,但我会将 @Asmus 答案标记为 Correct 因为它解决了我描述的问题。我现在正在考虑如何克服这个问题具体情况。生成的New ID大于其他序列的Replaced_ID。
【解决方案2】:

假设日期已排序,您可以创建一个辅助系列,然后进行 groupby 和聚合:

df['Installation Date (of New_ID)']=pd.to_datetime(df['Installation Date (of New_ID)'])

s = df['Replaced_ID'].ne(df['New_ID'].shift()).cumsum()
out = df.groupby(s).agg(
      {"Replaced_ID":"first","New_ID":"last","Installation Date (of New_ID)":"last"}
     )

print(out)

   Replaced_ID  New_ID Installation Date (of New_ID)
1            3      11                    2020-08-23
2           25      41                    2018-08-16

帮助器系列s 通过将Replaced_IDNew_ID 的下一个值进行比较来帮助区分组,当它们不匹配时,它返回True。然后在series.cumsum 的帮助下,我们返回整个系列的总和以创建单独的组:

print(s)

0    1
1    1
2    1
3    1
4    2
5    2

【讨论】:

  • 感谢您的回答。在尝试了这个之后,我注意到了两件事(在对日期进行排序之后):1)数据框只包含原样的行。它不返回起始 Replaced_ID 和最终 New_ID 值。 2)数据框包含所有中间行。关于我的示例,数据框输出包含 Replaced_ID 5 和 Replaced_ID 7 的行。请注意,按日期排序并不意味着行将引用相同的对序列。因此,s 将针对几乎所有行返回 True。
猜你喜欢
  • 2018-08-12
  • 2019-04-07
  • 2018-04-14
  • 1970-01-01
  • 2020-04-10
  • 2016-07-22
  • 2021-09-05
  • 2021-05-19
相关资源
最近更新 更多