集合多个值的差异在大熊猫单列(Difference of sets of multiple valu

2019-09-30 17:13发布

我有一些分组表格数据,并在此数据有针对每个数据点其实可以有一组不同的值的列。 我试图计算出一套不同于差异组在其前面的数据点的它的一员。 例如,下面给出的数据,我试图计算的值的差Tokens Timestep从的值值n Tokens用于与所述行Timestampn - 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})

然后,我创建的群组Dyad,Participant使用数据点pandas.DataFrame.groupby(..)

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

不过,我不确定如何让每一行,它的precedessor的Tokens值(这应该是一个frozenset ):我有一个试图做这样一些功能,但我不能确定的功能本身就是错误的,或者如果我提取行数据不正确。

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的:“系列”对象有没有属性“联盟”

但我知道我不使用/理解/正确所著的Grokking大熊猫API,因此非常啰嗦的问题。 我怎么能组我的数据,然后,每个组内,计算从一行它前面的行度量使用设置样的价值观和同一列的值?


在真实数据,有超过1,000个可能的值, Tokens ,所以,至少对我来说,如果我列举每个令牌布尔值,例如存在这个任务会更难Token_AppleToken_Banana等。

Answer 1:

设定

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

概括地说,这是什么代码是干什么的,通过分组DyadParticipant ,然后找出两两比。 这需要一些复杂的groupbyapply ,因为我们需要做几组uniondifference操作。 该核心逻辑是里面groupby.apply ,而剩下的只是prettification。

此代码运行在:

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']]


文章来源: Difference of sets of multiple values for single column in pandas