替换数据框中的重复值
Replacing duplicate values in a dataframe
我有以下数据框:
import numpy as np
import pandas as pd
df = pd.DataFrame({'ID': [1, 1, 2, 5, 5, 6, 1, 1, 2, 2, 5, 9, 1, 2, 3, 3, 3, 5]})
print(df)
给出:
ID
0 1
1 1
2 2
3 5
4 5
5 6
6 1
7 1
8 2
9 2
10 5
11 9
12 1
13 2
14 3
15 3
16 3
17 5
我想用尚未使用的最低值替换 'ID' 列中的重复值。然而,相应的相同值应该被视为一个组,并且它们的值应该以相同的方式改变。例如:前两个值都是 1。它们是连续的,因此它们是一个组,因此第二个“1”不应替换为“2”。第 14-16 行是三个连续的三分球。值 3 已经被用来替换上面的值,因此需要替换这三个值。但它们是相应的,因此是一个组,并且应该获得相同的替换值。预期结果如下,会更清楚:
ID
0 1
1 1
2 2
3 5
4 5
5 6
6 3
7 3
8 4
9 4
10 7
11 9
12 8
13 10
14 11
15 11
16 11
17 12
我想出了一种使用 for 循环和字典来获得结果的方法。公平地说,我希望更难,代码起初看起来有点复杂,但事实并非如此。可能有一种方法可以使用多个逻辑向量,但我不知道。
import numpy as np
import pandas as pd
df = pd.DataFrame({'ID': [1, 1, 2, 5, 5, 6, 1, 1, 2, 2, 5, 9, 1, 2, 3, 3, 3, 5]})
print(df)
####################
diffs = np.diff(df.ID) # differences ID(k) - ID(k-1)
uniq = sorted(pd.unique(df.ID)) # unique values in ID colums
# dict with range of numbers from min to max in ID col
d = {} # Empty dict
a = range(uniq[0],uniq[-1]*int(df.shape[0]/len(uniq))) # range values
d = {a[k]:False for k in range(len(a))} # Fill dict
d[df.ID[0]] = True # Set first value in col as True
for m in range(1,df.shape[0]):
# Find a value different from previous one
# therefore, beginning of new subgroup
if diffs[m-1] != 0:
# Check if value was before in the ID column
if d[df.ID[m]] == True:
# Get the lowest value which wasn't used
lowest = [k for k, v in d.items() if v == False][0]
# loop over the subgroup (which differences are 0)
for n in range(m+1,df.shape[0]):
if diffs[n-1] > 0: # If find a new subgroup
break # then stop looping
# Replace the subgroup with the lowest value
df.ID[m:n] = lowest # n is the final index of the subgroup
# *Exception in case last number is a subgroup itself
# then previous for loop doesnt work
if m == df.shape[0]-1:
df.ID[m] = lowest
# Update dictionaries for values retrieved from ID column
d[df.ID[m]] = True
print(df)
因此,您需要的是将您的列 ID 视为子组或不同的数组,然后检查不同的条件并进行不同的操作。您可以将列视为一组多个数组:
[1, 1 | 2 | 5, 5 | 6 | 1, 1 | 2, 2 | 5 | 9 | 1 | 2 | 3, 3, 3 | 5]
你需要做的是找到那个子群的极限并检查它们是否满足某些条件(1. 不是以前的数字,2. 我们没有使用的最小数字)。如果我们计算一个值与前一个值之间的差异,我们就可以知道子组
diffs = np.diff(df.ID) # differences ID(k) - ID(k-1)
我们可以使用字典知道条件,哪些键是我们可能需要的数组中的整数或更长的值,而值是我们是否使用过它们(真或假)。
为此,我们需要取 ID 列的最大值。但是,我们需要构建包含列中更多数字的字典(在您的示例中,max(input) = 9 和 max(output) = 12)。你可以随机做,我选择计算我们可能需要关注列中的行数和唯一值数的可能比例(a = 范围中的最后一个输入...)。
uniq = sorted(pd.unique(df.ID)) # unique values in ID colums
# dict with range of numbers from min to max in ID col
d = {}
a = range(uniq[0],uniq[-1]*int(df.shape[0]/len(uniq)))
d = {a[k]:False for k in range(len(a))}
d[df.ID[0]] = True # Set first value in col as True
代码的最后一部分是一个主要的 for 循环,里面有一些 If 和另一个 for,它的工作原理是:
# 1. Loop over ID column
# 2. Check if ID[m] value is different number from previous one (diff != 0)
# 3. Check if the ID[m] value is already in the ID column.
# 4. Calculate lowest value (first key == False in dict) and change the subset of
# in the ID
# 5. How is made step 4, if last value is a subset itself, it doesn't work, so
# there's a little condition to check it will work.
# 6. Update the dict every time a new value shows up.
我相信有很多方法可以缩短这段代码。但是这项工作应该适用于更大的数据帧和相同的条件。
df = pd.DataFrame({'ID': [1, 1, 2, 5, 5, 6, 1, 1, 2, 2, 5, 9, 1, 2, 3, 3, 3, 5]})
def fun():
v, dub = 1, set()
d = yield
while True:
num = d.iloc[0]['ID']
if num in dub:
while v in dub:
v += 1
d.ID = num = v
dub.add(num)
d = yield d
f = fun()
next(f)
df = df.groupby([df['ID'].diff().ne(0).cumsum(), 'ID'], as_index=False).apply(lambda x: f.send(x))
print(df)
输出:
ID
0 1
1 1
2 2
3 5
4 5
5 6
6 3
7 3
8 4
9 4
10 7
11 9
12 8
13 10
14 11
15 11
16 11
17 12
我有以下数据框:
import numpy as np
import pandas as pd
df = pd.DataFrame({'ID': [1, 1, 2, 5, 5, 6, 1, 1, 2, 2, 5, 9, 1, 2, 3, 3, 3, 5]})
print(df)
给出:
ID
0 1
1 1
2 2
3 5
4 5
5 6
6 1
7 1
8 2
9 2
10 5
11 9
12 1
13 2
14 3
15 3
16 3
17 5
我想用尚未使用的最低值替换 'ID' 列中的重复值。然而,相应的相同值应该被视为一个组,并且它们的值应该以相同的方式改变。例如:前两个值都是 1。它们是连续的,因此它们是一个组,因此第二个“1”不应替换为“2”。第 14-16 行是三个连续的三分球。值 3 已经被用来替换上面的值,因此需要替换这三个值。但它们是相应的,因此是一个组,并且应该获得相同的替换值。预期结果如下,会更清楚:
ID
0 1
1 1
2 2
3 5
4 5
5 6
6 3
7 3
8 4
9 4
10 7
11 9
12 8
13 10
14 11
15 11
16 11
17 12
我想出了一种使用 for 循环和字典来获得结果的方法。公平地说,我希望更难,代码起初看起来有点复杂,但事实并非如此。可能有一种方法可以使用多个逻辑向量,但我不知道。
import numpy as np
import pandas as pd
df = pd.DataFrame({'ID': [1, 1, 2, 5, 5, 6, 1, 1, 2, 2, 5, 9, 1, 2, 3, 3, 3, 5]})
print(df)
####################
diffs = np.diff(df.ID) # differences ID(k) - ID(k-1)
uniq = sorted(pd.unique(df.ID)) # unique values in ID colums
# dict with range of numbers from min to max in ID col
d = {} # Empty dict
a = range(uniq[0],uniq[-1]*int(df.shape[0]/len(uniq))) # range values
d = {a[k]:False for k in range(len(a))} # Fill dict
d[df.ID[0]] = True # Set first value in col as True
for m in range(1,df.shape[0]):
# Find a value different from previous one
# therefore, beginning of new subgroup
if diffs[m-1] != 0:
# Check if value was before in the ID column
if d[df.ID[m]] == True:
# Get the lowest value which wasn't used
lowest = [k for k, v in d.items() if v == False][0]
# loop over the subgroup (which differences are 0)
for n in range(m+1,df.shape[0]):
if diffs[n-1] > 0: # If find a new subgroup
break # then stop looping
# Replace the subgroup with the lowest value
df.ID[m:n] = lowest # n is the final index of the subgroup
# *Exception in case last number is a subgroup itself
# then previous for loop doesnt work
if m == df.shape[0]-1:
df.ID[m] = lowest
# Update dictionaries for values retrieved from ID column
d[df.ID[m]] = True
print(df)
因此,您需要的是将您的列 ID 视为子组或不同的数组,然后检查不同的条件并进行不同的操作。您可以将列视为一组多个数组:
[1, 1 | 2 | 5, 5 | 6 | 1, 1 | 2, 2 | 5 | 9 | 1 | 2 | 3, 3, 3 | 5]
你需要做的是找到那个子群的极限并检查它们是否满足某些条件(1. 不是以前的数字,2. 我们没有使用的最小数字)。如果我们计算一个值与前一个值之间的差异,我们就可以知道子组
diffs = np.diff(df.ID) # differences ID(k) - ID(k-1)
我们可以使用字典知道条件,哪些键是我们可能需要的数组中的整数或更长的值,而值是我们是否使用过它们(真或假)。
为此,我们需要取 ID 列的最大值。但是,我们需要构建包含列中更多数字的字典(在您的示例中,max(input) = 9 和 max(output) = 12)。你可以随机做,我选择计算我们可能需要关注列中的行数和唯一值数的可能比例(a = 范围中的最后一个输入...)。
uniq = sorted(pd.unique(df.ID)) # unique values in ID colums
# dict with range of numbers from min to max in ID col
d = {}
a = range(uniq[0],uniq[-1]*int(df.shape[0]/len(uniq)))
d = {a[k]:False for k in range(len(a))}
d[df.ID[0]] = True # Set first value in col as True
代码的最后一部分是一个主要的 for 循环,里面有一些 If 和另一个 for,它的工作原理是:
# 1. Loop over ID column
# 2. Check if ID[m] value is different number from previous one (diff != 0)
# 3. Check if the ID[m] value is already in the ID column.
# 4. Calculate lowest value (first key == False in dict) and change the subset of
# in the ID
# 5. How is made step 4, if last value is a subset itself, it doesn't work, so
# there's a little condition to check it will work.
# 6. Update the dict every time a new value shows up.
我相信有很多方法可以缩短这段代码。但是这项工作应该适用于更大的数据帧和相同的条件。
df = pd.DataFrame({'ID': [1, 1, 2, 5, 5, 6, 1, 1, 2, 2, 5, 9, 1, 2, 3, 3, 3, 5]})
def fun():
v, dub = 1, set()
d = yield
while True:
num = d.iloc[0]['ID']
if num in dub:
while v in dub:
v += 1
d.ID = num = v
dub.add(num)
d = yield d
f = fun()
next(f)
df = df.groupby([df['ID'].diff().ne(0).cumsum(), 'ID'], as_index=False).apply(lambda x: f.send(x))
print(df)
输出:
ID
0 1
1 1
2 2
3 5
4 5
5 6
6 3
7 3
8 4
9 4
10 7
11 9
12 8
13 10
14 11
15 11
16 11
17 12