pandas 如何在Python中向DF添加/插补附加行

efzxgjgh  于 2023-01-01  发布在  Python
关注(0)|答案(3)|浏览(115)

我有一个 Dataframe ,看起来像这样:
| 识别号|得分|年龄|性别问题|日期|
| - ------|- ------|- ------|- ------|- ------|
| A类|二十五|五个|男|2019年1月1日|
| A类|三十二|五个|男|2019年1月1日|
| A类|三十二|五个|男|2019年1月5日|
| B|四十五|九|F级|2019年2月1日|
| B|七十六|九|F级|2019年5月1日|
| C级|五十四|七|F级|2019年3月1日|
对于每个唯一ID,我希望确保正好有2个条目。如果ID有2个以上的条目,我希望这两个条目的日期最晚(如果出现平局,则只取任意两行和日期)。如果ID的条目少于2个,则为该ID插入/插补一行,其中分数设置为0,日期设置为该ID的最近日期,但是年龄和性别被保留(假设年龄和性别对于任何一个ID总是相同的)。
一种可能的解决方案是:
| 识别号|得分|年龄|性别问题|日期|
| - ------|- ------|- ------|- ------|- ------|
| A类|三十二|五个|男|2019年1月1日|
| A类|三十二|五个|男|2019年1月5日|
| B|四十五|九|F级|2019年2月1日|
| B|七十六|九|F级|2019年5月1日|
| C级|五十四|七|F级|2019年3月1日|
| C级|无|七|F级|2019年3月1日|
我的数据集非常大,所以使用pd.multiIndex进行多索引使我的内存很快耗尽(我使用的实际数据集大约有50万行)。
我试着实现类似的东西:How to pad on extra rows in dataframe for Neural Netowrk
但我不知道如何实现“使用最新日期”的限制。

1dkrff03

1dkrff031#

暴力

def f(d):
    d = d.nlargest(2, ['Date'])
    if len(d) < 2:
        d = d.append(d.assign(Score=0))
    return d

df.groupby('ID', as_index=False, group_keys=False).apply(f)

# ⇓ Ugly index is ugly

    ID  Score  Age Gender       Date
  2  A     32    5      M 2019-01-05
  0  A     25    5      M 2019-01-01
  4  B     76    9      F 2019-05-01
  3  B     45    9      F 2019-02-01
  5  C     54    7      F 2019-03-01
  5  C      0    7      F 2019-03-01

如果需要2以外的特定数字,请输入5

def f(d, limit):
    d = d.nlargest(limit, ['Date'])
    if len(d) < limit:
        d = pd.concat([d] + [d.assign(Score=0)] * (limit - len(d)))
    return d

df.groupby('ID', as_index=False, group_keys=False).apply(f, limit=5)

少一点野蛮,也许?

pd.concat([
    d.append(d.assign(Score=0)) if len(d) < 2 else d.tail(2)
    for _, d in df.sort_values(['ID', 'Date']).groupby('ID')
], ignore_index=True)

  ID  Score  Age Gender       Date
0  A     32    5      M 2019-01-01
1  A     32    5      M 2019-01-05
2  B     45    9      F 2019-02-01
3  B     76    9      F 2019-05-01
4  C     54    7      F 2019-03-01
5  C      0    7      F 2019-03-01
8ljdwjyq

8ljdwjyq2#

让我们试试懒惰groupby和concat:

df= df.sort_values(['ID','Date'],ascending=[True, False])

g = df.groupby('ID')
enums = g.cumcount()
sizes = g['ID'].transform('size')

pd.concat([df[enums<2],                  # row 1 and 2 in each group
           df[sizes==1].assign(Score=0)  # duplicate groups with 1 row
          ]).sort_index()

还有head的另一个变体:

pd.concat([g.head(2),                   # row 1 and 2 in each group
           df[sizes==1].assign(Score=0)  # duplicate groups with 1 row
          ]).sort_index()

输出:

ID  Score  Age Gender        Date
0  A      25    5     M   2019-01-01
2  A      32    5     M   2019-01-05
3  B      45    9     F   2019-02-01
4  B      76    9     F   2019-05-01
5  C      54    7     F   2019-03-01
5  C       0    7     F   2019-03-01
nx7onnlm

nx7onnlm3#

下面是一个方法:
首先获取每个ID的前2个

d = df.sort_values(by='Date',ascending=False).groupby('ID').head(2).set_index('ID')

然后找到没有重复的,并使其重复

a = pd.concat([d.loc[~d.index.duplicated(keep=False)]]*2)

然后将其中一个赋值为0

a.loc[a.index.duplicated(),'Score'] = 0

然后concat新的df。

final = pd.concat([d.loc[d.index.duplicated(keep=False)],a]).sort_index()

以下解决方案应能够处理2个以上条目:

n = 2

df = df.sort_values('Date',ascending=False)

(pd.concat([df.groupby('ID').head(n),
v.loc[(v:=df.groupby('ID',as_index=False).last()
.assign(Score = 0))
.index
.repeat((n - v['ID'].map(df['ID'].value_counts()))
.clip(lower = 0))]])
.sort_values('ID'))

相关问题