python pandas 如何编辑重复值?

python pandas how to edit value of duplicate?

我想更改我的副本的值。这是我的数据框:

  sku
FAT-001
FAT-001
FAT-001
FAT-002
FAT-002

我预期的数据框将如下所示

  sku
FAT-001 #don't want to change first value of duplicate 
FAT-001-01
FAT-001-02
FAT-002
FAT-002-01
df["number"] = df.groupby("sku").cumcount()
df.apply(lambda x: x.sku + ("" if x.number == 0 else "-" + str(x.number).rjust(2,"0")), axis = 1)

或:

df["number"] = "-" + df.groupby("sku").cumcount().astype(str).str.rjust(2, '0')
df.number[df["number"].eq("-" + "0" * 2)] = ""
df.sku + df.number 

我的输出:

0       FAT-001
1    FAT-001-01
2    FAT-001-02
3       FAT-002
4    FAT-002-01
dtype: object

解释:

什么是 groupby?它是一个 sql-inspired 命令,可以根据每个唯一元素为您提供一些元素...例如:长度、最大值、列表或其他...

df = pd.DataFrame([
    [1,2],
    [1,3],
    [1,4],
    [2,5],
    [2,6],
], columns=["id","number"])
df.groupby("id").agg({"number": len})

给你:

    number
id  
1   3
2   2

每个唯一元素的数量,或

df.groupby("id").agg({"number": list})

给你

    number
id  
1   [2, 3, 4]
2   [5, 6]

你可以尝试 maxminfirst...

使用 agg,您可以为每一列指定您想要的...如果您有多个列(除了 groupby),您可以为每一列指定一些内容 column...

除了 agggoupped 数据帧还有其他方法:像 cumcount,为每个 group 设置索引每个 row,我的意思是它为每个 group:

重置 index
df.groupby("sku").cumcount()

输出:

0    0
1    1
2    2
3    0
4    1

您的第一个 FAT-001 获得 index: 0,下一个:1,...对于 FAT-002,首先再次获得索引 0...

所以,我们有两个你想要的部分,现在...因此我们必须找到一种方法将它们加入每个 rowaxis:1 in apply 表示每一行

所以,您有一个例外:您不希望每个组的每一行都使用 index...因此将其更改为“”,为空:

df.apply(lambda x: "" if x.number == 0 else str(x.number), axis = 1)

:

0     
1    1
2    2
3     
4    1
dtype: object

您的 03 行用于 new-group...

接下来,您想要的格式是:01,02,...每个索引的 0。 pandas 有一种方法可以将每个字符串转换为具有任意 char: rjust(desird_length, arbitrary_char)

所需长度的字符串

工作原理:如果您将其称为 rjust(2,"0"),它不会更改 "22" 或其他 2-char、3-char、... 字符串,但是,如果您的字符串长度为1 like 1 将被转换为 01 和...(注意还有一个方法叫做 ljust :))

df["number"] = df.groupby("sku").cumcount()
df.apply(lambda x: "" if x.number == 0 else str(x.number).rjust(2,"0"), axis = 1)
0      
1    01
2    02
3      
4    01
dtype: object

if语句可以写成:

if x.number == 0:
   return ""
else:
    return "-" + str(x.number).rjust(2,"0")

还有一些要点:

  1. 什么是astype(str):它将每个元素都转换为字符串,工作方式类似于str(x),但对每个元素。为什么?在它之前添加“-”并使用 rjust.
  2. 什么是eq?如果等于值,则每行为 is-equal? 和 return True,否则为 False
  3. 为什么df.number[df["number"].eq("-" + "0" * 2)] = ""?因为我们将每个组的所有第一个元素都转换为 ""
  4. 为什么"-" + "0" * 2?因为我们在上一行添加了 "-" 和 ljust,所以我们必须使用正确的值:"-00"。为什么 "0" * 2?因为你可以使用 ljust length 的每个数字,比如 10,并将它也设置在那里

类似于@MoRe的回答,使用groupby.cumcount创建组;然后你可以使用 str.zfill 填充 0s 和 mask 每组的第一个元素:

groups = df.groupby('sku').cumcount()
df['new'] = df['sku'] + ('-' + groups.astype('string').str.zfill(2)).mask(groups.eq(0), '')

输出:

       sku         new
0  FAT-001     FAT-001
1  FAT-001  FAT-001-01
2  FAT-001  FAT-001-02
3  FAT-002     FAT-002
4  FAT-002  FAT-002-01

替代方案one-liner:

 df.sku = df.sku + df.groupby('sku').cumcount().apply(lambda x: f"-{x:02d}" if x > 0 else '')

输出:

          sku
0     FAT-001
1  FAT-001-01
2  FAT-001-02
3     FAT-002
4  FAT-002-01