替换 Pandas DataFrame 列中超过 n 个连续值
Replacing more than n consecutive values in Pandas DataFrame column
假设我有以下 DataFrame df
df = pd.DataFrame({"a" : [1,2,2,2,2,2,2,2,2,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5], "b" : [3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,7,7], "c" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,1,2,2,2,2,2,2,2,2,3,3]})
而且我希望用 10 个 4 和其余的 5 替换任何列(可能有数百列)中连续重复 10 次以上的数字 4。
因此,例如,12 个连续的 4 将被替换为十个 4 和两个 5。
我如何使用 Pandas 实现此目的?
我想应用 lambda,但我不知道如何回溯足够多的行,而且它必须从末尾开始向前移动,否则会破坏值的序列。每次查找都必须查看前面的 10 行,看它们是否都等于 4,如果是,则将当前值设置为 5。
虽然不知道该怎么做!
这应该可以解决问题:
import pandas as pd
df = pd.DataFrame({"a" : [1,2,2,2,2,2,2,2,2,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5], "b" : [3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,7,7], "c" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,1,2,2,2,2,2,2,2,2,3,3]})
def replacer(l,target_val=4,replace_val=5,repeat_max=10):
counter = 0
new_l = []
for e in l:
if e == target_val: counter += 1
else:
counter = 0
if counter > repeat_max:
new_l.append(replace_val)
else:
new_l.append(e)
return new_l
df1 = df.apply(replacer)
输出:
a b c
0 1 3 4
1 2 3 4
2 2 3 4
3 2 3 4
4 2 3 4
5 2 3 4
6 2 3 4
7 2 4 4
8 2 4 4
9 3 4 4
10 3 4 5
11 4 5 5
12 4 5 5
13 4 5 5
14 4 5 5
15 4 5 5
16 4 5 5
17 4 5 5
18 4 5 5
19 4 5 5
20 4 5 5
21 5 5 1
22 5 5 2
23 5 5 2
24 5 5 2
25 5 5 2
26 5 5 2
27 5 5 2
28 5 6 2
29 5 6 2
30 5 7 3
31 5 7 3
您可以使用:
#column a is changed for 2 groups of 4
df = pd.DataFrame({
"a" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,7,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5],
"b" : [3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,7,7],
"c" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,1,2,2,2,2,2,2,2,2,3,3]})
如果 NaN
由 where
and then apply boolean mask
to original df
for replace 4
to 5
by mask
:
创建,则解决方案计算连续 4 次并重置
a = df == 4
mask = a.cumsum()-a.cumsum().where(~a).ffill().fillna(0) > 10
df1 = df.mask(mask, 5)
print (df1)
a b c
0 4 3 4
1 4 3 4
2 4 3 4
3 4 3 4
4 4 3 4
5 4 3 4
6 4 3 4
7 4 4 4
8 4 4 4
9 4 4 4
10 5 4 5
11 5 5 5
12 5 5 5
13 5 5 5
14 7 5 5
15 4 5 5
16 4 5 5
17 4 5 5
18 4 5 5
19 4 5 5
20 4 5 5
21 4 5 1
22 4 5 2
23 4 5 2
24 4 5 2
25 5 5 2
26 5 5 2
27 5 5 2
28 5 6 2
29 5 6 2
30 5 7 3
31 5 7 3
为了更好地检查值,可以使用 concat
:
print (pd.concat([df, df1], axis=1, keys=['orig','new']))
orig new
a b c a b c
0 4 3 4 4 3 4
1 4 3 4 4 3 4
2 4 3 4 4 3 4
3 4 3 4 4 3 4
4 4 3 4 4 3 4
5 4 3 4 4 3 4
6 4 3 4 4 3 4
7 4 4 4 4 4 4
8 4 4 4 4 4 4
9 4 4 4 4 4 4
10 4 4 4 5 4 5
11 4 5 4 5 5 5
12 4 5 4 5 5 5
13 4 5 4 5 5 5
14 7 5 4 7 5 5
15 4 5 4 4 5 5
16 4 5 4 4 5 5
17 4 5 4 4 5 5
18 4 5 5 4 5 5
19 4 5 5 4 5 5
20 4 5 5 4 5 5
21 4 5 1 4 5 1
22 4 5 2 4 5 2
23 4 5 2 4 5 2
24 4 5 2 4 5 2
25 4 5 2 5 5 2
26 4 5 2 5 5 2
27 4 5 2 5 5 2
28 4 6 2 5 6 2
29 5 6 2 5 6 2
30 5 7 3 5 7 3
31 5 7 3 5 7 3
删除所有 4s,使用 limit=10
作为参数用 4s 填充 na,并用 5s 删除剩余的 NA。我发现这种方法更明确,更能反映您的意图:
df[df!=4].fillna(4, limit=10).fillna(5)
如果需要,将 df 转换回整数并在末尾添加 astype(int)
,因为 NA 的入侵会将数据帧转换为浮点数。
假设我有以下 DataFrame df
df = pd.DataFrame({"a" : [1,2,2,2,2,2,2,2,2,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5], "b" : [3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,7,7], "c" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,1,2,2,2,2,2,2,2,2,3,3]})
而且我希望用 10 个 4 和其余的 5 替换任何列(可能有数百列)中连续重复 10 次以上的数字 4。
因此,例如,12 个连续的 4 将被替换为十个 4 和两个 5。
我如何使用 Pandas 实现此目的?
我想应用 lambda,但我不知道如何回溯足够多的行,而且它必须从末尾开始向前移动,否则会破坏值的序列。每次查找都必须查看前面的 10 行,看它们是否都等于 4,如果是,则将当前值设置为 5。
虽然不知道该怎么做!
这应该可以解决问题:
import pandas as pd
df = pd.DataFrame({"a" : [1,2,2,2,2,2,2,2,2,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5], "b" : [3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,7,7], "c" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,1,2,2,2,2,2,2,2,2,3,3]})
def replacer(l,target_val=4,replace_val=5,repeat_max=10):
counter = 0
new_l = []
for e in l:
if e == target_val: counter += 1
else:
counter = 0
if counter > repeat_max:
new_l.append(replace_val)
else:
new_l.append(e)
return new_l
df1 = df.apply(replacer)
输出:
a b c
0 1 3 4
1 2 3 4
2 2 3 4
3 2 3 4
4 2 3 4
5 2 3 4
6 2 3 4
7 2 4 4
8 2 4 4
9 3 4 4
10 3 4 5
11 4 5 5
12 4 5 5
13 4 5 5
14 4 5 5
15 4 5 5
16 4 5 5
17 4 5 5
18 4 5 5
19 4 5 5
20 4 5 5
21 5 5 1
22 5 5 2
23 5 5 2
24 5 5 2
25 5 5 2
26 5 5 2
27 5 5 2
28 5 6 2
29 5 6 2
30 5 7 3
31 5 7 3
您可以使用:
#column a is changed for 2 groups of 4
df = pd.DataFrame({
"a" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,7,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5],
"b" : [3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,7,7],
"c" : [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,1,2,2,2,2,2,2,2,2,3,3]})
如果 NaN
由 where
and then apply boolean mask
to original df
for replace 4
to 5
by mask
:
a = df == 4
mask = a.cumsum()-a.cumsum().where(~a).ffill().fillna(0) > 10
df1 = df.mask(mask, 5)
print (df1)
a b c
0 4 3 4
1 4 3 4
2 4 3 4
3 4 3 4
4 4 3 4
5 4 3 4
6 4 3 4
7 4 4 4
8 4 4 4
9 4 4 4
10 5 4 5
11 5 5 5
12 5 5 5
13 5 5 5
14 7 5 5
15 4 5 5
16 4 5 5
17 4 5 5
18 4 5 5
19 4 5 5
20 4 5 5
21 4 5 1
22 4 5 2
23 4 5 2
24 4 5 2
25 5 5 2
26 5 5 2
27 5 5 2
28 5 6 2
29 5 6 2
30 5 7 3
31 5 7 3
为了更好地检查值,可以使用 concat
:
print (pd.concat([df, df1], axis=1, keys=['orig','new']))
orig new
a b c a b c
0 4 3 4 4 3 4
1 4 3 4 4 3 4
2 4 3 4 4 3 4
3 4 3 4 4 3 4
4 4 3 4 4 3 4
5 4 3 4 4 3 4
6 4 3 4 4 3 4
7 4 4 4 4 4 4
8 4 4 4 4 4 4
9 4 4 4 4 4 4
10 4 4 4 5 4 5
11 4 5 4 5 5 5
12 4 5 4 5 5 5
13 4 5 4 5 5 5
14 7 5 4 7 5 5
15 4 5 4 4 5 5
16 4 5 4 4 5 5
17 4 5 4 4 5 5
18 4 5 5 4 5 5
19 4 5 5 4 5 5
20 4 5 5 4 5 5
21 4 5 1 4 5 1
22 4 5 2 4 5 2
23 4 5 2 4 5 2
24 4 5 2 4 5 2
25 4 5 2 5 5 2
26 4 5 2 5 5 2
27 4 5 2 5 5 2
28 4 6 2 5 6 2
29 5 6 2 5 6 2
30 5 7 3 5 7 3
31 5 7 3 5 7 3
删除所有 4s,使用 limit=10
作为参数用 4s 填充 na,并用 5s 删除剩余的 NA。我发现这种方法更明确,更能反映您的意图:
df[df!=4].fillna(4, limit=10).fillna(5)
如果需要,将 df 转换回整数并在末尾添加 astype(int)
,因为 NA 的入侵会将数据帧转换为浮点数。