Pandas Python:将数据框中的每两行合并

3 投票
1 回答
7510 浏览
提问于 2025-04-18 04:07

我该如何从

Idx            A B C
2004-04-01     1 1 0
2004-04-02     1 1 0
2004-05-01     0 0 0
2004-05-02     0 0 0

变成

Idx            A B C
2004-04        2 2 0
2004-05        0 0 0

备注: 我该如何将索引折叠(更具体地说,就是把索引变成只有月份)以及每两行的数据?

使用滚动平均值是最好的方法吗?

更新 - 我把上面的版本简化了,但unutbu的回答似乎不太管用

                       Time      A   B
1    2004-01-04 - 2004-01-10     0   0
2    2004-01-11 - 2004-01-17     0   0
3    2004-01-18 - 2004-01-24     0   0
4    2004-01-25 - 2004-01-31     0   0
5    2004-02-01 - 2004-02-07     56  0
6    2004-02-08 - 2004-02-14     67  0

1 个回答

8

你可以通过一个叫做 groupby/sum 的操作来合并行数据:

import pandas as pd
import numpy as np

df = pd.DataFrame([('2004-04-01', 1L, 1L, 0L), ('2004-04-02', 1L, 1L, 0L),
       ('2004-05-01', 0L, 0L, 0L), ('2004-05-02', 0L, 0L, 0L)],
                  columns=['Idx', 'A', 'B', 'C'])
df['Idx'] = pd.DatetimeIndex(df['Idx'])

你可以按年份和月份来分组:

print(df.groupby([d.strftime('%Y-%m') for d in df['Idx']]).sum())
#          A  B  C
# 2004-04  2  2  0
# 2004-05  0  0  0

# [2 rows x 3 columns]

或者,按每两行来分组:

result = df.groupby(np.arange(len(df))//2).sum()
result.index = df.loc[1::2, 'Idx']
print(result)
#             A  B  C
# Idx                
# 2004-04-02  2  2  0
# 2004-05-02  0  0  0

# [2 rows x 3 columns]

注意:这里用的是 df.loc[1::2, 'Idx'],而不是 df.loc[::2, 'Idx'],这样合并后的行的 Idx 会对应到每组的第二个日期,而不是第一个。

如果你只想要年份和月份,可以用这个列表推导式来设置索引:

result.index = [d.strftime('%Y-%m') for d in df.loc[1::2, 'Idx']]
print(result)
#          A  B  C
# 2004-04  2  2  0
# 2004-05  0  0  0

# [2 rows x 3 columns]

不过,处理日期时,使用 DatetimeIndex(日期时间索引)会比用字符串索引更强大。所以你可能想保留 DatetimeIndex,主要用它来处理数据,最后再转换成年份-月份的字符串来展示...


关于更新的问题:

import pandas as pd
import numpy as np

data = np.rec.array([('2004-01-04 - 2004-01-10', 0L, 0L),
       ('2004-01-11 - 2004-01-17', 0L, 0L),
       ('2004-01-18 - 2004-01-24', 0L, 0L),
       ('2004-01-25 - 2004-01-31', 0L, 0L),
       ('2004-02-01 - 2004-02-07', 56L, 0L),
       ('2004-02-08 - 2004-02-14', 67L, 0L)], 
      dtype=[('Time', 'O'), ('A', '<i8'), ('B', '<i8')])
df = pd.DataFrame(data)

如果有一列时间包含两个日期,数据处理会变得更复杂。最好是有两列 DatetimeIndex,分别叫 StartEnd

df[['Start', 'End']] = df['Time'].str.extract('(?P<Start>.+) - (?P<End>.+)')
del df['Time']
df['Start'] = pd.DatetimeIndex(df['Start'])
df['End'] = pd.DatetimeIndex(df['End'])

然后你可以按 Start 列来分组:

print(df.groupby([d.strftime('%Y-%m') for d in df['Start']]).sum())
#            A  B
# 2004-01    0  0
# 2004-02  123  0

# [2 rows x 2 columns]

或者按每两行分组,基本上和之前的做法一样:

result = df.groupby(np.arange(len(df))//2).sum()
result.index = df.loc[1::2, 'Start']
print(result)
#               A  B
# Start             
# 2004-01-11    0  0
# 2004-01-25    0  0
# 2004-02-08  123  0

# [3 rows x 2 columns]

撰写回答