Pandas DataFrame:合并具有相同 ID 的行

Posted

技术标签:

【中文标题】Pandas DataFrame:合并具有相同 ID 的行【英文标题】:Pandas DataFrame: Merge rows with same id 【发布时间】:2021-11-02 09:16:37 【问题描述】:

我有一个熊猫DataFrame,具有以下属性,

timestamp code code_2 q1 q2 q3
1525815633939 1 5 0.528285138670663 0.0 -10.2012590087440983
1525815633979 1 5 0.728820351190643 0.0 -10.1985732939503924
1525815633990 6 5 9.7439931640624877 10.25547685467354
1525815633990 6 5 0.92935559526222
1525815634000 6 5 9.7079931640624864 10.25475688648455
1525815634000 6 5 0.029623209410135

如您所见,有时一个条目会一分为二,尽管它不是双值的。最后两对行对应于相同的timestamps、相同的code 和相同的code_2,但q1,q2,q3 被拆分。 (timestampscodecode_2 构成我的唯一标识符)。

我想要什么,

timestamp code code_2 q1 q2 q3
1525815633939 1 5 0.528285138670663 0.0 -10.2012590087440983
1525815633979 1 5 0.728820351190643 0.0 -10.1985732939503924
1525815633990 6 5 0.92935559526222 9.7439931640624877 10.25547685467354
1525815634000 6 5 0.029623209410135 9.7079931640624864 10.25475688648455

而且我还需要考虑以下情况,我想继续丢弃“完整行”

timestamp code code_2 q1 q2 q3
1525815633939 1 5 0.528285138670663 0.0 -10.2012590087440983
1525815633979 1 5 0.728820351190643 0.0 -10.1985732939503924
1525815633990 6 5 9.7439931640624877 10.25547685467354
1525815633990 6 5 0.92935559526222
1525815634000 6 5 0.984554565478545 9.7079931640624864 10.25475688648455
1525815634000 6 5 0.029623209410135

【问题讨论】:

好吧,我会创建一个函数,它只是选择第一个时间戳并遍历所有时间步以找到等效的时间戳,然后在两个时间戳行中添加 q1、q2、q3,如果其中一个有 NaN,否则对最后一种情况不做任何事情? 这确实是一个选择,但我期待更有效的东西。我有加载的数据,这会很慢,你不觉得吗? 还有,我期待这可以通过内置的 pandas 方法来完成。 嗯,我也很喜欢 :),肯定有一个内置函数,如果两个单元格具有相同的元素,它们可以明确地相加,或者如果其中一个是 NaN,则替换它与其他值。但是对于您的最后一种情况,内置函数如何知道要获得哪个值?喜欢:df.groupby('TimeStamp')['q1'].sum() 以及 q2、q3 等 尝试我的解决方案以获得更好的运行时间(另外由于不使用 apply 功能相对较慢)。 ***.com/a/69055997/7836972 【参考方案1】:

我一直在寻找一种不使用“apply”功能的方法,通过使用 pandas 内置函数来获得更好的运行时间

比较具有和不具有应用功能的运行时: 数据集:

data_temp1 = 'timestamp':np.concatenate([np.arange(0,30000,1)]*2), 'code':[6,6, 5]*20000, 'code_2':[6,6, 5]*20000, 'q1':[0.134555,0.984554565478545, 54]*20000, 'q2':[9.7079931640624864,None, 43]*20000, 'q3':[10.25475688648455,None, 54]*20000 
df = pd.DataFrame(data_temp1)

使用类似于@Andrej Kesely 示例的apply 解决方案:

7.21 秒 ± 8.56 毫秒/循环(平均值 ± 标准偏差,7 次运行,每次 1 次循环)

我的解决方案不适用的解决方案:

98.4 毫秒 ± 79.2 µs 每个循环(平均值 ± 标准偏差,7 次运行,每次 10 次循环)

我的解决方案: (仅当存在时才会填充空单元格。因此,根据您的两种情况都是正确的)。

按空单元格的数量对行进行排序 按下面的行填充每个组中的每一行(没关系,因为先排序) 删除包含空单元格的行
columns_to_groupby = ["timestamp", "code"]
# Sort rows of a dataframe in descending order of None counts
df = df.iloc[df.isnull().sum(1).sort_values(ascending=True).index].set_index(columns_to_groupby)
# group by timestamp column, fill the None cells if exists, delete the incomplete rows (from which we filled in the others)
df.groupby(df.index).bfill().dropna()

示例:

示例 1:

输入:

结果:

示例 2(包含没有空单元格的行):

输入:

结果:

如您所见,两者的结果相同。

【讨论】:

只需将 code_2 添加到 columns_to_groupby (我在迷你示例中使用它)【参考方案2】:

对于问题1:你可以.groupby"timestamp""code""code_2",然后是 ffill()/bfill() 值,然后删除重复项:

x = (
    df.groupby(["timestamp", "code", "code_2"])
    .apply(lambda x: x.ffill().bfill())
    .drop_duplicates(["timestamp", "code", "code_2"])
)
print(x)

打印:

       timestamp  code  code_2                 q1                  q2                    q3
0  1525815633939     1       5  0.528285138670663                 0.0  -10.2012590087440983
1  1525815633979     1       5  0.728820351190643                 0.0  -10.1985732939503924
2  1525815633990     6       5   0.92935559526222  9.7439931640624877     10.25547685467354
4  1525815634000     6       5  0.029623209410135  9.7079931640624864     10.25475688648455

对于问题2:你可以.sort_values一行中有多少NaNs(所以整行将在第一位)然后从问题1开始操作:

df["tmp"] = df[["q1", "q2", "q3"]].isna().sum(1)
df = df.sort_values(by="tmp").drop(columns="tmp")

x = (
    df.groupby(["timestamp", "code", "code_2"])
    .apply(lambda x: x.ffill().bfill())
    .drop_duplicates(["timestamp", "code", "code_2"])
)
print(x)

打印:

       timestamp  code  code_2                 q1                  q2                    q3
0  1525815633939     1       5  0.528285138670663                 0.0  -10.2012590087440983
1  1525815633979     1       5  0.728820351190643                 0.0  -10.1985732939503924
4  1525815634000     6       5  0.984554565478545  9.7079931640624864     10.25475688648455
2  1525815633990     6       5   0.92935559526222  9.7439931640624877     10.25547685467354

【讨论】:

太好了,这就是我想要的。 Pandas 的方法!

以上是关于Pandas DataFrame:合并具有相同 ID 的行的主要内容,如果未能解决你的问题,请参考以下文章

合并和填充 Pandas DataFrame

合并具有来自两个不同列的匹配值的 DataFrame - Pandas [重复]

合并两个具有相同列名但在熊猫中列数不同的数据框

如何在一个除一列之外的所有列都相同的 Pandas DataFrame 中合并观察结果?

基于多列值的具有重复键的两个大型 Pandas DataFrame 的条件合并/连接 - Python

根据 pandas 中的多个键合并两个 DataFrame