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]
你可以尝试 max
或 min
或 first
...
使用 agg
,您可以为每一列指定您想要的...如果您有多个列(除了 groupby
),您可以为每一列指定一些内容 column
...
除了 agg
,goupped
数据帧还有其他方法:像 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...
所以,我们有两个你想要的部分,现在...因此我们必须找到一种方法将它们加入每个 row
:axis: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
您的 0
和 3
行用于 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")
还有一些要点:
- 什么是
astype(str)
:它将每个元素都转换为字符串,工作方式类似于str(x)
,但对每个元素。为什么?在它之前添加“-”并使用 rjust
.
- 什么是
eq
?如果等于值,则每行为 is-equal?
和 return True
,否则为 False
。
- 为什么
df.number[df["number"].eq("-" + "0" * 2)] = ""
?因为我们将每个组的所有第一个元素都转换为 ""
- 为什么
"-" + "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
我想更改我的副本的值。这是我的数据框:
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]
你可以尝试 max
或 min
或 first
...
使用 agg
,您可以为每一列指定您想要的...如果您有多个列(除了 groupby
),您可以为每一列指定一些内容 column
...
除了 agg
,goupped
数据帧还有其他方法:像 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...
所以,我们有两个你想要的部分,现在...因此我们必须找到一种方法将它们加入每个 row
:axis: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
您的 0
和 3
行用于 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")
还有一些要点:
- 什么是
astype(str)
:它将每个元素都转换为字符串,工作方式类似于str(x)
,但对每个元素。为什么?在它之前添加“-”并使用rjust
. - 什么是
eq
?如果等于值,则每行为is-equal?
和 returnTrue
,否则为False
。 - 为什么
df.number[df["number"].eq("-" + "0" * 2)] = ""
?因为我们将每个组的所有第一个元素都转换为""
- 为什么
"-" + "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