代码之家  ›  专栏  ›  技术社区  ›  errantlinguist

pandas中单个列的多个值集的差异

  •  1
  • errantlinguist  · 技术社区  · 8 年前

    我有一些分组的表格数据,在这些数据中有一列,每个数据点实际上可以有一组不同的值。我试图计算这个集合与它所属的组中先前数据点的差值。例如,给定下面的数据,我试图计算 Tokens 对于 Timestep 价值 代币 Timestamp 价值 -每个1个 Dyad,Participant 组合:

    | Dyad | Participant | Timestep | Tokens            |
    |------|-------------|----------|-------------------|
    | 1    | A           | 1        | apple,banana      |
    | 1    | B           | 1        | apple,orange      |
    | 1    | A           | 2        | banana            |
    | 1    | B           | 2        | orange,kumquat    |
    | 1    | A           | 3        | orange            |
    | 1    | B           | 3        | orange,pear       |
    | 2    | A           | 1        | orange,pear       |
    | 2    | B           | 1        | apple,banana,pear |
    | 2    | A           | 2        | banana,persimmon  |
    | 2    | B           | 2        | apple             |
    | 2    | A           | 3        | banana            |
    | 2    | B           | 3        | apple             |
    

    预期结果

    我最终想要创建一个具有函数输出的新列 token_overlap(data) Token 与前面数据点的值重叠的值:

    | Dyad | Participant | Timestep | Tokens            | TokenOverlap |
    |------|-------------|----------|-------------------| -------------|
    | 1    | A           | 1        | apple,banana      | (no value)   |
    | 1    | B           | 1        | apple,orange      | (no value)   |
    | 1    | A           | 2        | banana            | 0.5          |
    | 1    | B           | 2        | orange,kumquat    | 0.333        |
    | 1    | A           | 3        | orange            | 0            |
    | 1    | B           | 3        | orange,pear       | 0.333        |            
    | 2    | A           | 1        | orange,pear       | (no value)   |
    | 2    | B           | 1        | apple,banana,pear | (no value)   |
    | 2    | A           | 2        | banana,persimmon  | 0            |
    | 2    | B           | 2        | apple             | 0.333        |
    | 2    | A           | 3        | banana            | 0.5          |
    | 2    | B           | 3        | apple             | 1            |
    

    我将多个值转换为 frozenset 通过使用 converters 的关键字 pandas.read_csv(...) :

    def parse_set(cell_value: str) -> FrozenSet[str]:
        return frozenset(cell_value.split(','))
    
    round_tokens = pandas.read_csv(inpath, converters={"Tokens": parse_set})
    

    二元,参与者 pandas.DataFrame.groupby(..) :

    round_tokens.sort_values(["Dyad", "Timestep"])
    dyad_participants = round_tokens.groupby(["Dyad", "Participant"])
    

    然而,我不确定如何获得每一行,它是Precessor的 值(应为 ):我有一些函数试图这样做,但我不确定函数本身是否错误,或者我是否错误地提取了行数据。

    def token_overlap(data):
        own_relevant_tokens = data["Tokens"]
        prev_tokens = data.shift(-1)["Tokens"]
        overlap = own_relevant_tokens.intersection(prev_tokens)
        union = own_relevant_tokens.union(prev_tokens)
        return len(overlap) / len(union)
    
    round_tokens["TokenOverlap"] = dyad_participants.apply(token_overlap)
    

    然而,这实际上并不起作用:实际的错误是

    AttributeError:“Series”对象没有属性“union”

    如何将数据分组,然后在每个组中使用一行中的类似集合的值以及该行前面的同一列的值来计算度量?


    在实际数据中,有1000多个可能的值 代币 Token_Apple , Token_Banana

    1 回复  |  直到 8 年前
        1
  •  1
  •   cs95 abhishek58g    8 年前

    安装程序

    df
        Dyad Participant  Timestep             Tokens
    0      1           A         1       apple,banana
    1      1           B         1       apple,orange
    2      1           A         2             banana
    3      1           B         2     orange,kumquat
    4      1           A         3             orange
    5      1           B         3        orange,pear
    6      2           A         1        orange,pear
    7      2           B         1  apple,banana,pear
    8      2           A         2   banana,persimmon
    9      2           B         2              apple
    10     2           A         3             banana
    11     2           B         3              apple
    
    tokens = df.Tokens.str.split(',', expand=False).apply(frozenset) 
    
    tokens
    0           (apple, banana)
    1           (orange, apple)
    2                  (banana)
    3         (orange, kumquat)
    4                  (orange)
    5            (orange, pear)
    6            (orange, pear)
    7     (apple, banana, pear)
    8       (persimmon, banana)
    9                   (apple)
    10                 (banana)
    11                  (apple)
    Name: Tokens, dtype: object
    

    # union logic - https://stackoverflow.com/a/46402781/4909087
    df =  df.assign(Tokens=tokens)\
            .groupby(['Dyad', 'Participant']).apply(\
                   lambda x: (x.Tokens.str.len() - 
                          x.Tokens.diff().str.len()) \
                        / pd.Series([len(k[0].union(k[1])) 
       for k in zip(x.Tokens, x.Tokens.shift(1).fillna(''))], index=x.index))\
            .reset_index(level=[0, 1], name='TokenOverlap')\
            .assign(Timestep=df.Timestep, Tokens=df.Tokens)\
            .sort_values(['Dyad', 'Timestep', 'Participant'])\
            .fillna('(no value)')\
             [['Dyad', 'Participant', 'Timestep', 'Tokens', 'TokenOverlap']]
    
    df
    
        Dyad Participant  Timestep             Tokens TokenOverlap
    0      1           A         1       apple,banana   (no value)
    1      1           B         1       apple,orange   (no value)
    2      1           A         2             banana          0.5
    3      1           B         2     orange,kumquat     0.333333
    4      1           A         3             orange            0
    5      1           B         3        orange,pear     0.333333
    6      2           A         1        orange,pear   (no value)
    7      2           B         1  apple,banana,pear   (no value)
    8      2           A         2   banana,persimmon            0
    9      2           B         2              apple     0.333333
    10     2           A         3             banana          0.5
    11     2           B         3              apple            1
    

    简而言之,这段代码的作用是按 Dyad Participant ,然后求成对比。这需要一些复杂的 groupby apply ,因为我们需要做几组 union difference 操作。核心逻辑在 groupby.apply 剩下的只是修饰。

    10 loops, best of 3: 19.2 ms per loop
    

    df2 = df.assign(Tokens=tokens)
    df2 = df2.groupby(['Dyad', 'Participant']).apply(\
                       lambda x: (x.Tokens.str.len() - 
                              x.Tokens.diff().str.len()) \
                            / pd.Series([len(k[0].union(k[1])) 
           for k in zip(x.Tokens, x.Tokens.shift(1).fillna(''))], index=x.index)) # the for loop is part of this huge line
    
    df2 = df2.reset_index(level=[0, 1], name='TokenOverlap')    
    df2 = df2.assign(Timestep=df.Timestep, Tokens=df.Tokens)
    df2 = df2.sort_values(['Dyad', 'Timestep', 'Participant']).fillna('(no value)')    
    df2 = df2[['Dyad', 'Participant', 'Timestep', 'Tokens', 'TokenOverlap']]