我有一些分组的表格数据,在此数据中有一列,每个数据点实际上可以具有一组不同的值。我正在尝试计算该组与其所属的组中先前数据点的差异。例如,给定下面的数据,我试图计算出Tokens
†值n的Timestep
†值与行中Tokens
值n-1的行的Timestamp
值的差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"])
但是,我不确定如何获取每一行,并且它是先行者的
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:“系列”对象没有属性“联合”
但我知道我没有正确使用/理解/理解熊猫API,因此这是一个冗长的问题。如何对数据进行分组,然后在每个组内部,使用一行中的集合值和该行前一行的同一列值来计算指标?
†在实际数据中,
Tokens
可能有1,000多个值,因此,至少对于我来说,如果我将每个令牌的存在枚举为布尔值(例如, Token_Apple
,Token_Banana
等 最佳答案
设定
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
,因为我们需要执行一些set 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']]
关于python - Pandas 中单列的多个值集的差异,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46400906/