Python Pandas按连续值分组DataFrame

0 投票
2 回答
49 浏览
提问于 2025-04-13 15:47

我有一个很大的 pandas 数据框,里面有一个时间戳列,一个数值列,一个“键”列,还有一个标志列,用来表示一个数据块的结束(其实还有其他列)。

timestamp, value, key, last_in_block
12345, 1.0, 2, False <-- start of block 1
12346, 0.5, 4, False
12347, 1.2, 1, False
12348, 2.2, 6, False
12349, 1.5, 3, False
12350, 1.2, 3, False
12351, 2.3, 3, False
12352, 0.4, 5, True
12371, 1.3, 2, False <-- start of block 2
12372, 0.9, 4, False
12373, 1.7, 1, False
12374, 2.0, 6, False
12375, 1.2, 3, False
12376, 1.4, 3, False
12377, 2.7, 3, False
12378, 0.8, 5, True
...

在“键”列中,有一串特定的数值序列(在这个例子中是 2 4 5 6 3 3 3 5),这个序列用来标识一个数据块。我想用“groupBy”语句把这个数据框按块分组。请问这怎么做?

df = pd.DataFrame(data =
              {"timestamp": list(range(12345,12353)) + list(range(12371,12379)),
                "value": [1.0,0.5,1.2,2.2,1.5,1.2,2.3,0.4,1.3,0.9,1.7,2.0,1.2,1.4,2.7,0.8],
                "key": [2,4,1,6,3,3,3,5]*2,
               "last_in_block" : [False]*7+[True]+[False]*7+[True]})

更新,关于问题的回答:

  • 我事先知道这个序列
  • 除了非常少见的例外,这些序列都是完整的

2 个回答

1

如果你有一个标记,表示每个区块的最后一个项目,你可以使用反向的 cumsum 来形成分组:

group = df.loc[::-1, 'last_in_block'].cumsum()
for k, g in df.groupby(group, sort=False):
    print(g)

另外,如果你不知道周期性或者没有标记,你可以通过自相关来估算周期性,使用 autocorr 方法在关键数据上进行计算,周期性对应于最大相关性的滞后值:

lag = pd.Series({i: df['key'].autocorr(i)
                 for i in range(1, len(s)//2+1)}
               ).idxmax()
# periodicity: 8

group = np.arange(len(df))//lag

for k, g in df.groupby(group, sort=False):
    print(g)

输出结果:

   timestamp  value  key  last_in_block
0      12345    1.0    2          False
1      12346    0.5    4          False
2      12347    1.2    1          False
3      12348    2.2    6          False
4      12349    1.5    3          False
5      12350    1.2    3          False
6      12351    2.3    3          False
7      12352    0.4    5           True
    timestamp  value  key  last_in_block
8       12371    1.3    2          False
9       12372    0.9    4          False
10      12373    1.7    1          False
11      12374    2.0    6          False
12      12375    1.2    3          False
13      12376    1.4    3          False
14      12377    2.7    3          False
15      12378    0.8    5           True

自相关图:

enter image description here

1

你可以用 last_in_block 来识别不同的组,然后再用 groupby 来分组:

df["last_in_block"] = np.where(df["last_in_block"].shift(), 1, 0)
df["last_in_block"] = df["last_in_block"].cumsum()
grouped = df.groupby("last_in_block")

grouped.groups:

{1: [0, 1, 2, 3, 4, 5, 6, 7], 2: [8, 9, 10, 11, 12, 13, 14, 15]}

grouped.mean():

               timestamp   value    key
last_in_block                          
1                12348.5  1.2875  3.375
2                12374.5  1.5000  3.375

撰写回答