Dan*_*niB 11 python group-by pandas
我的目标是以下输出。
| 一种 | 乙 | C | D | 乙 | F |
|---|---|---|---|---|---|
| 0000 | ZZZ | 987 | QW1 | 8 | 前三四列和偏移量 |
| 0000 | ZZZ | 987 | QW1 | -8 | 前三四列和偏移量 |
| 0000 | ZZZ | 987 | QW1 | -8 | 第一次或不匹配 |
| 1111 | AAA | 123 | AB1 | 1 | 前三四列和偏移量 |
| 1111 | AAA | 123 | CD1 | -1 | 前三四列和偏移量 |
| 2222 | BBB | 456 | EF1 | -4 | 前三四列和偏移量 |
| 2222 | BBB | 456 | GH1 | -1 | 前三四列和偏移量 |
| 2222 | BBB | 456 | IL1 | 5 | 前三四列和偏移量 |
| 3333 | CCC | 789 | MN1 | 2 | 前两个 col 和 offset |
| 3333 | CCC | 101 | MN1 | -2 | 前两个 col 和 offset |
| 4444 | 直拨电话 | 121 | UYT | 6 | 前两个 col 和 offset |
| 4444 | 直拨电话 | 131 | FB1 | -5 | 前两个 col 和 offset |
| 4444 | 直拨电话 | 141 | UYT | -1 | 前两个 col 和 offset |
| 5555 | 电子电气设备 | 151 | CB1 | 3 | 前两个 col 和 offset |
| 5555 | 电子电气设备 | 161 | CR1 | -3 | 前两个 col 和 offset |
| 5555 | 电子电气设备 | 161 | CR1 | -5 | 第一次或不匹配 |
| 6666 | FFF | 111 | CB1 | 4 | 第一次或不匹配 |
| 7777 | GGG | 222 | ZB1 | 10.5 | 前三四列和小偏移 |
| 7777 | GGG | 222 | ZB1 | -10 | 前三四列和小偏移 |
第一条规则)前三列必须彼此相等 - 无论第四列如何,可以相等也可以不相等。每个组合都必须将关联的数字 (col E) 偏移为零(可以是 2 到 X 条记录的组合)。即使条目不均匀,它也应该适用。
第二条规则)前两列必须彼此相等 - 无论第四列如何,可以相等也可以不相等。每个组合都必须将关联的数字 (col E) 偏移为零(可以是 2 到 X 条记录的组合)。即使条目不均匀,它也应该适用。
第三条规则)不匹配。
第四条规则)前三列必须彼此相等 - 无论第四列如何,可以相等也可以不相等。每个组合可以有0.5AT MOST (col E) 和 NO 偏移为零的差异(可以是 2 到 X 条记录的组合)。即使条目不均匀,它也应该适用。
请在下面查看我的代码。
通过下面的代码,我能够得到类似的结果,但是,这种方式不适用于不均匀的条目,例如前三行将导致如下结果:
| 一种 | 乙 | C | D | 乙 | F |
|---|---|---|---|---|---|
| 0000 | ZZZ | 987 | QW1 | 8 | 第一次或不匹配 |
| 0000 | ZZZ | 987 | QW1 | -8 | 第一次或不匹配 |
| 0000 | ZZZ | 987 | QW1 | -8 | 第一次或不匹配 |
而不是以下内容:
| 一种 | 乙 | C | D | 乙 | F |
|---|---|---|---|---|---|
| 0000 | ZZZ | 987 | QW1 | 8 | 前三四列和偏移量 |
| 0000 | ZZZ | 987 | QW1 | -8 | 前三四列和偏移量 |
| 0000 | ZZZ | 987 | QW1 | -8 | 第一次或不匹配 |
到目前为止的代码:
m1 = df.groupby(['A', 'B', 'C'])['E'].transform('sum').eq(0) # Rule 1
m2 = df.groupby(['A', 'B'])['E'].transform('sum').eq(0) # Rule 2
m3 = df.groupby(['A', 'B', 'C'])['E'].transform('sum').abs().le(0.5) # Rule 4
df['new'] = np.select([m1, m2, m3], ['first three-four col and offset',
'first two col and offset', 'first three-four col and small offset'], 'first or no match')
Run Code Online (Sandbox Code Playgroud)
这是解决方案的一个潜在开始......我怀疑这个逻辑需要更加强大才能处理您的真实世界数据集。
#Read in your dataframe from this question
df = pd.read_clipboard(dtype={'A':'str'})
def f2(x):
cum = x.cumsum()
m = (cum == 0)[::-1].cumsum()[::-1].astype(bool)
x[m]='first two col and offset'
x[~m]=np.nan
return x
def f1(x):
cum = x.cumsum()
m = (cum == 0)[::-1].cumsum()[::-1].astype(bool)
x[m]='first three col and offset'
cl = ((cum.abs() <= .5) & (cum != 0))[::-1].cumsum()[::-1].astype(bool)
x[cl] = 'first three col and small offset'
x[~m & ~cl] = np.nan
return x
df['F2'] = df.groupby(['A','B'])['E'].apply(f2)
df['F1'] = df.groupby(['A', 'B', 'C'])['E'].apply(f1)
df['F'] = df['F1'].fillna(df['F2']).fillna('first or no match')
df = df.drop(['F1', 'F2'], axis=1)
Run Code Online (Sandbox Code Playgroud)
输出:
A B C D E F
0 0000 ZZZ 987 QW1 8.0 first three col and offset
1 0000 ZZZ 987 QW1 -8.0 first three col and offset
2 0000 ZZZ 987 QW1 -8.0 first or no match
3 1111 AAA 123 AB1 1.0 first three col and offset
4 1111 AAA 123 CD1 -1.0 first three col and offset
5 2222 BBB 456 EF1 -4.0 first three col and offset
6 2222 BBB 456 GH1 -1.0 first three col and offset
7 2222 BBB 456 IL1 5.0 first three col and offset
8 3333 CCC 789 MN1 2.0 first two col and offset
9 3333 CCC 101 MN1 -2.0 first two col and offset
10 4444 DDD 121 UYT 6.0 first two col and offset
11 4444 DDD 131 FB1 -5.0 first two col and offset
12 4444 DDD 141 UYT -1.0 first two col and offset
13 5555 EEE 151 CB1 3.0 first two col and offset
14 5555 EEE 161 CR1 -3.0 first two col and offset
15 5555 EEE 161 CR1 -5.0 first or no match
16 6666 FFF 111 CB1 4.0 first or no match
17 7777 GGG 222 ZB1 10.5 first three col and small offset
18 7777 GGG 222 ZB1 -10.0 first three col and small offset
Run Code Online (Sandbox Code Playgroud)
细节:
f2,基于相同的“A”和“B”取一组“E”,然后计算累积和。
然后我们检查 cumsum 等于 0 的位置以创建一个布尔系列。
反转,使用 [::-1] 以负一步切片,该系列并再次使用 cumsum 来标记 cumsum == 0 之前的所有记录。
使用 [::-1] 恢复到原始顺序并转换为布尔值。
接下来,使用该 bolean 系列的“真值”来设置“前两个列和偏移量”,然后使用假记录来设置 np.nan。
f1,除了捕获偏移量关闭记录的额外逻辑外,其他功能相同。
_thresh_sum我们可以定义一个递归函数,它将输入参数作为一维 numpy 数组,并返回与输入数组具有相同形状的一维布尔数组
from numba import jit
@jit(nopython=True)
def _thresh_sum(arr, indices, flags, offset, thresh):
if flags[indices].any(): return
s = np.abs(arr[indices].sum())
if s <= thresh and len(indices) > 1:
flags[indices] = True
return
for i, _ in enumerate(arr[offset:]):
new_offset = offset + i + 1
new_indices = np.array(list(indices) + [offset + i])
_thresh_sum(arr, new_indices, flags, new_offset, thresh)
def thresh_sum(arr, thresh=0):
flags = np.full(len(arr), False)
_thresh_sum(np.array(arr),
np.array([], dtype='int'), flags, 0, thresh + 1e-6)
return flags
Run Code Online (Sandbox Code Playgroud)
背后的直觉 _thresh_sum
我们可以通过将函数直接编译为机器码,借助称为即时编译的技术来进一步提高代码的性能,使用_thresh_sumnumba
注意:这是NP-Hard类型问题。随着每个唯一组的元素数量增加,问题的计算复杂度将增加大约O(2^n)。
Group并transform与thresh_sum现在我们组数据帧按照给定的规则1,2,4和transform列E使用函数thresh_sum对应于每个规则
m1 = df.groupby(['A', 'B', 'C'])['E'].transform(thresh_sum) # Rule 1
m2 = df[~m1].groupby(['A', 'B'])['E'].transform(thresh_sum) # Rule 2
m3 = df[~(m1 | m2)].groupby(['A', 'B', 'C'])['E'].transform(thresh_sum, thresh=0.5) # Rule 4
Run Code Online (Sandbox Code Playgroud)
np.select根据计算出的布尔掩码m1,m2并m3对应规则1,2和4,填充列中的值F
df['F'] = np.select([m1, m2.reindex(m1.index, fill_value=False), m3.reindex(m1.index, fill_value=False)],
['first three-four col and offset', 'first two col and offset', 'first three-four col and small offset'], 'first or no match')
Run Code Online (Sandbox Code Playgroud)
A B C D E F
0 0000 ZZZ 987 QW1 8.0 first three-four col and offset
1 0000 ZZZ 987 QW1 -8.0 first three-four col and offset
2 0000 ZZZ 987 QW1 -8.0 first or no match
3 1111 AAA 123 AB1 1.0 first three-four col and offset
4 1111 AAA 123 CD1 -1.0 first three-four col and offset
5 2222 BBB 456 EF1 -4.0 first three-four col and offset
6 2222 BBB 456 GH1 -1.0 first three-four col and offset
7 2222 BBB 456 IL1 5.0 first three-four col and offset
8 3333 CCC 789 MN1 2.0 first two col and offset
9 3333 CCC 101 MN1 -2.0 first two col and offset
10 4444 DDD 121 UYT 6.0 first two col and offset
11 4444 DDD 131 FB1 -5.0 first two col and offset
12 4444 DDD 141 UYT -1.0 first two col and offset
13 5555 EEE 151 CB1 3.0 first two col and offset
14 5555 EEE 161 CR1 -3.0 first two col and offset
15 5555 EEE 161 CR1 -5.0 first or no match
16 6666 FFF 111 CB1 4.0 first or no match
17 7777 GGG 222 ZB1 10.5 first three-four col and small offset
18 7777 GGG 222 ZB1 -10.0 first three-four col and small offset
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
391 次 |
| 最近记录: |