Pandas - 基于条件复制行

9

如果某行符合条件,我想要创建一个重复的行。在下面的表格中,我基于分组创建了一个累积计数,然后进行了另一个分组最大值的计算。

df['PathID'] = df.groupby(DateCompleted).cumcount() + 1
df['MaxPathID'] = df.groupby(DateCompleted)['PathID'].transform(max)

Date Completed    PathID    MaxPathID
1/31/17           1         3
1/31/17           2         3
1/31/17           3         3
2/1/17            1         1
2/2/17            1         2
2/2/17            2         2

在这种情况下,我只想复制2/1/17的记录,因为该日期只有一个实例(即MaxPathID == 1的实例)。
期望输出:
Date Completed    PathID    MaxPathID
1/31/17           1         3
1/31/17           2         3
1/31/17           3         3
2/1/17            1         1
2/1/17            1         1
2/2/17            1         2
2/2/17            2         2

提前感谢您!


您所需的输出中 不会2/1/17 的重复项。输出中的行与原始行在 PathID 和 MaxPathID 上有所不同。请准确说明您想要获得什么(不是通过示例,而是通过算法)。 - DYZ
你是如何获取重复项的 MaxPathID 的呢? - gold_cy
你可以使用 df.append(df[df['MaxPathID']==1]) 创建完全相同的副本,但显然这不是你想要的。 - DYZ
1
DYZ--你说得对。我修改了输出,以更改重复行的MaxPathID。最终输出不一定要这样。我只想复制MaxPathID == 1的行。 - Walt Reed
4个回答

3

我认为您需要按照完成日期获取唯一的行,然后使用concat将这些行与原始行合并:

df1 = df.loc[~df['Date Completed'].duplicated(keep=False), ['Date Completed']]
print (df1)
  Date Completed
3         2/1/17

df = pd.concat([df,df1], ignore_index=True).sort_values('Date Completed')
df['PathID'] = df.groupby('Date Completed').cumcount() + 1
df['MaxPathID'] = df.groupby('Date Completed')['PathID'].transform(max)
print (df)
  Date Completed  PathID  MaxPathID
0        1/31/17       1          3
1        1/31/17       2          3
2        1/31/17       3          3
3         2/1/17       1          2
6         2/1/17       2          2
4         2/2/17       1          2
5         2/2/17       2          2

编辑:

print (df)
  Date Completed  a  b
0        1/31/17  4  5
1        1/31/17  3  5
2        1/31/17  6  3
3         2/1/17  7  9
4         2/2/17  2  0
5         2/2/17  6  7

df1 = df[~df['Date Completed'].duplicated(keep=False)]
#alternative - boolean indexing by numpy array
#df1 = df[~df['Date Completed'].duplicated(keep=False).values]
print (df1)
  Date Completed  a  b
3         2/1/17  7  9

df = pd.concat([df,df1], ignore_index=True).sort_values('Date Completed')
print (df)
  Date Completed  a  b
0        1/31/17  4  5
1        1/31/17  3  5
2        1/31/17  6  3
3         2/1/17  7  9
6         2/1/17  7  9
4         2/2/17  2  0
5         2/2/17  6  7

那个完美运作!还有一个问题——我在我的数据框中有其他列(我没有在数据框模拟中展示),但是当我复制行时,其他列中的值为空。如何确保所有列的所有值都被复制和重复? - Walt Reed
如果有多列,则只需要将“df1 = df.loc [〜df ['Date Completed'] .duplicated(keep = False),['Date Completed']]”更改为“df1 = df [〜df ['Date Completed'] .duplicated(keep = False)]”。 - jezrael
1
也许加上 values - df1 = df[~df['Date Completed'].duplicated(keep=False).values] - jezrael
你真是个天才!谢谢你! - Walt Reed

1
我知道这可能是一个有些不同的问题,但它符合问题描述,所以人们会从谷歌来。我还没有研究过如何优化以下内容或其他任何内容,我相信有更好的方法,但有时只需接受不完美的事情 ;) 所以在这里发布,以防有人面临类似的问题并想尝试快速完成。看起来运行得相当快。
假设我们有一个像下面这样的数据框(df):

enter image description here

我们希望将其转换为以下形式,假设field3有多个条目,并且我们想要展开其中的所有条目,如下所示:

enter image description here

Here is one approach for that:

import pandas as pd
import numpy as np
from datetime import date,datetime

index = []
double_values = []


### get index and get list of values on which to expand per indexed row
for i,r in df.iterrows():
    index.append(i)
    ### below transform your column with multiple entries to a list based on delimetter
    double_values.append(str(r[2]).split(' '))

serieses = []

print('tot row to process', len(index))
count = 0
for i,dvs in zip(index,double_values):
    count+= 1
    if count % 1000 == 0:
        print('elem left', len(index)- count, datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
    if len(dvs)>1:
        for dv in dvs:
            series = df.iloc[i]
            series.loc['field3'] = dv
            serieses.append(list(series))

#create dataframe out of expanded rows now appended to serieses list, creating a list of lists
df2 = pd.DataFrame.from_records(serieses,columns=df.columns)

### drop original rows with double entries, which have been expanded and appended already
indexes_to_drop = []
for i,dvs in zip(index,double_values):
    if len(dvs)>1:
        indexes_to_drop.append(i)

df.drop(df.index[indexes_to_drop],inplace=True)
len(df)


df = df.append(df2)

1

使用duplicated + repeat的创意numpy方法

dc = df['Date Completed']
rg = np.arange(len(dc)).repeat((~dc.duplicated(keep=False).values) + 1)
df.iloc[rg]

  Date Completed  PathID  MaxPathID
0        1/31/17       1          3
1        1/31/17       2          3
2        1/31/17       3          3
3         2/1/17       1          1
3         2/1/17       1          1
4         2/2/17       1          2
5         2/2/17       2          2

1
这里有一个简单的方法,适用于任何情况。
condition = df["MaxPathID"] == 1
df = pd.concat([df, df[condition].copy()], ignore_index=True)

print(df)
  Date Completed  PathID  MaxPathID
0        1/31/17       1          3
1        1/31/17       2          3
2        1/31/17       3          3
3         2/1/17       1          1
4         2/2/17       1          2
5         2/2/17       2          2
6         2/1/17       1          1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接