根据值拆分数据框输出

时间:2016-12-29 21:57:41

标签: python pandas

这篇文章涵盖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

3 个答案:

答案 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]

解决手头的问题

df2np.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