这篇文章涵盖Modification of a function to return a dataframe with specified values,我想进一步修改输出。当前函数和矢量化版本将相互减去列的所有组合,并相应地返回相关数据。
示例和测试数据:
import pandas as pd
import numpy as np
from itertools import combinations
df2 = pd.DataFrame(
{'AAA' : [80,5,6],
'BBB' : [85,20,30],
'CCC' : [100,50,25],
'DDD' : [98,50,25],
'EEE' : [103,50,25],
'FFF' : [105,50,25],
'GGG' : [109,50,25]});
df2
AAA BBB CCC DDD EEE FFF GGG
0 80 85 100 98 103 105 109
1 5 20 50 50 50 50 50
2 6 30 25 25 25 25 25
v = df2.values
df3 = df2.mask((np.abs(v[:, :, None] - v[:, None]) <= 5).sum(-1) <= 1)
df3
AAA BBB CCC DDD EEE FFF GGG
0 80.0 85.0 100 98 103 105 109
1 NaN NaN 50 50 50 50 50
2 NaN 30.0 25 25 25 25 25
阈值(此处为5)内的所有值均以np.abs <=5
为单位返回。
需要改变什么?
在df3
的第一行,在thresh(80,85)和(100,98,103,105,109)内有两组值。它们都是有效的,但不是thresh
内的两个独立的组。我希望能够根据另一个thresh
值分隔这些值。
我试图用以下(有缺陷的)代码展示我要做的事情,并且只包括这个以表明我试图自己进步...
df3.mask(df3.apply(lambda x : x >= df3.T.max() \
- (thresh * 3))).dropna(thresh=2).dropna(axis=1)
AAA BBB
0 80.0 85.0
df3.mask(~df3.apply(lambda x : x >= df3.T.max() - (thresh * 3))).dropna(axis=1)
CCC DDD EEE FFF GGG
0 100 98 103 105 109
1 50 50 50 50 50
2 25 25 25 25 25
所以我的输出很好(显示接近所需的输出),但我得到这个的方式并不是那么好......
--- 期望的输出: ---
我已经使用多行来演示但是当我使用这段代码时,它只会是一行需要输出和分割。因此,所需的输出是按行0
的此示例返回单独的列。
CCC DDD EEE FFF GGG
0 100 98 103 105 109
和
AAA BBB
0 80.0 85.0
答案 0 :(得分:2)
我认为您可以尝试以不同方式解决您的问题。这个想法是为了获得“差距和岛屿”。在每一行中并标记每个组:
因此,首先 - 将列放入行并在每个初始行索引中对值进行排序:
>>> df = df2.stack().sort_values().sortlevel(0, sort_remaining=False)
>>> df
0 AAA 80
BBB 85
DDD 98
CCC 100
EEE 103
FFF 105
GGG 109
1 AAA 5
BBB 20
GGG 50
FFF 50
DDD 50
CCC 50
EEE 50
2 AAA 6
GGG 25
EEE 25
DDD 25
CCC 25
FFF 25
BBB 30
接下来,使用&#39; prev值&#39;创建新的DataFrame。连同当前值:
>>> df = df2.stack().sort_values().sortlevel(0, sort_remaining=False)
>>> df = pd.concat([df, df.groupby(level=0).shift(1)], axis=1)
>>> df.columns = ['cur', 'prev']
>>> df
cur prev
0 AAA 80 NaN
BBB 85 80.0
DDD 98 85.0
CCC 100 98.0
EEE 103 100.0
FFF 105 103.0
GGG 109 105.0
1 AAA 5 NaN
BBB 20 5.0
GGG 50 20.0
FFF 50 50.0
DDD 50 50.0
CCC 50 50.0
EEE 50 50.0
2 AAA 6 NaN
GGG 25 6.0
EEE 25 25.0
DDD 25 25.0
CCC 25 25.0
FFF 25 25.0
BBB 30 25.0
现在,创建岛屿标签:
>>> df = (df['cur'] - df['prev'] > thresh).astype('int')
>>> df
0 AAA 0
BBB 0
DDD 1
CCC 0
EEE 0
FFF 0
GGG 0
1 AAA 0
BBB 1
GGG 1
FFF 0
DDD 0
CCC 0
EEE 0
2 AAA 0
GGG 1
EEE 0
DDD 0
CCC 0
FFF 0
BBB 0
>>> df.groupby(level=0).cumsum().unstack()
AAA BBB CCC DDD EEE FFF GGG
0 0 0 1 1 1 1 1
1 0 1 2 2 2 2 2
2 0 1 1 1 1 1 1
现在,您可以过滤掉只有一名成员并且您已完成的群组:)
>>> dfm = df.groupby(level=0).cumsum().unstack()
>>> dfm
AAA BBB CCC DDD EEE FFF GGG
0 0 0 1 1 1 1 1
1 0 1 2 2 2 2 2
2 0 1 1 1 1 1 1
>>> df2[dfm == 0].loc[0:0].dropna(axis=1)
AAA BBB
0 80 85.0
>>> df2[dfm == 1].loc[0:0].dropna(axis=1)
CCC DDD EEE FFF GGG
0 100.0 98.0 103.0 105.0 109.0
答案 1 :(得分:2)
方法1
我复制并粘贴了上一个问题,包括小改动。
我向你的closeCols
进行了矢量化和嵌入,以获得一些麻烦的乐趣
请注意,没有apply
numpy
广播,以便将所有列的组合相互减去。np.abs
<= 5
sum(-1)
我安排了广播,以便说明行0
,列AAA
与所有行0
的区别横跨最后一个维度。 -1
中的sum(-1)
表示总结最后一维。<= 1
所有值距离自身都不到5。所以我希望这些的总和大于1.因此,我们掩盖所有小于或等于一。df2 = pd.DataFrame(
{'AAA' : [80,5,6],
'BBB' : [85,20,30],
'CCC' : [100,50,25],
'DDD' : [98,50,25],
'EEE' : [103,50,25],
'FFF' : [105,50,25],
'GGG' : [109,50,25]});
v = df2.values
# let delta be the distance threshold
# let k be the cluster size threshold
x, k = 5, 2 # cluster size must be greater than k
df2.mask((np.abs(v[:, :, None] - v[:, None]) <= x).sum(-1) <= k)
# note that this is the same as before but k = 1 was hard coded
print(df3)
AAA BBB CCC DDD EEE FFF GGG
0 NaN NaN 100 98 103 105 NaN
1 NaN NaN 50 50 50 50 50.0
2 NaN 30.0 25 25 25 25 25.0
答案 2 :(得分:2)
我觉得这应该是一个单独的答案。
我编写了一个在一维数组上运行的聚类函数。我知道如何将它进一步矢量化为2维,但我还没有完成它。实际上,我使用np.apply_along_axis
此answer对此question中描述了此功能。我鼓励你按照这些链接进行操作,看看这项看似简单的功能。
它的作用是找到每个点左侧和右侧边距定义的数组中的簇。它排序,然后集群,然后排序。
delta群集功能
def delta_cluster(a, dleft, dright):
s = a.argsort()
y = s.argsort()
a = a[s]
rng = np.arange(len(a))
edge_left = a.searchsorted(a - dleft)
starts = edge_left == rng
edge_right = np.append(0, a.searchsorted(a + dright, side='right')[:-1])
ends = edge_right == rng
return (starts & ends).cumsum()[y]
解决手头的问题
对df2
中np.apply_along_axis
的每一行使用群集功能,并构建一个名为DataFrame
的{{1}}镜像与clusters
相同的索引和列。然后df2
获得stack
,以便以后更容易操作。
Series
这描述了下一段代码。
clusters = pd.DataFrame(
np.apply_along_axis(delta_cluster, 1, df2.values, 10, 10),
df2.index, df2.columns).stack()
时,我需要保留df2
的行信息。 groupby
获取每行的群集大小。 transform
stack
的值,并将群集值附加为索引的一部分。这样可以实现您正在寻找的分离。df2
mask
其中val
等于1.这些是单身群集。size
除了我将第一行分成两行外,这与你的结果相符。
lvl0 = clusters.index.get_level_values(0)
size = clusters.groupby([lvl0, clusters]).transform('size')
val = df2.stack().to_frame('value').set_index(clusters, append=True).value
val.mask(size.values == 1).dropna().unstack(1)
AAA BBB CCC DDD EEE FFF GGG
0 1 80.0 85.0 NaN NaN NaN NaN NaN
2 NaN NaN 100.0 98.0 103.0 105.0 109.0
1 3 NaN NaN 50.0 50.0 50.0 50.0 50.0
2 2 NaN 30.0 25.0 25.0 25.0 25.0 25.0