熊猫:用特定的索引匹配减去两个系列

时间:2016-02-10 07:51:26

标签: python pandas indexing

我有一个巨大的数据集,我需要处理很多数字,然后看1.实际的解决方案和2.快速的解决方案。

我试图尽可能地简化并将我的问题转移到现实世界的例子中,我希望它很清楚。我很确定(至少我希望)它在某种程度上是熊猫的常见问题,而不是一个非常特殊的问题。

因此,假设我在一家名为foobar的公司中有两名工作人员。有时他们在同一天工作并一遍又一遍地完成同样的任务。我衡量他们完成任务所需的时间(有时每天只有一次,有时多次)。

我现在正在寻找的是,如果他们两个都在同一天工作,那么最短时间之间的差异。

我尝试做全麦方法,所以尽可能地处理表(而不是迭代)。

我目前的策略是:dayname对数据进行分组,每time和{{1}只保留最短的day如果组大小为2(这意味着我在同一天有两个工作人员的数据)减去两次。

最终目标:最短时间差异name

但是,我没有进行分组和过滤,所以现在我尝试为两个工人创建两个系列,然后计算时差。

以下是一个示例数据集:

Series

这是分组后保持最短时间的表格:

from StringIO import StringIO
import pandas as pd

raw_data="""day name time
1 foo 10
1 foo 9
1 bar 4
2 foo 12
2 foo 13
3 bar 3
3 bar 5
5 foo 8
5 bar 5
5 foo 9
5 bar 1
"""

df = pd.read_csv(StringIO(raw_data), sep=' ')

grouped_by_day_and_name = df.groupby(['day', 'name'])

现在我只对第1天和第5天感兴趣,因为这是我有print grouped_by_day_and_name.agg({'time': min}) time day name 1 bar 4 foo 9 2 foo 12 3 bar 3 5 bar 1 foo 8 bar数据的唯一日子。所以,如果我以某种方式过滤数据并在每组中减去两次,我就会完成,因此结果将是foo(从第1天开始,第4-9天,第5天到第1-8天)。

由于我无法过滤和减去,我正在尝试为两个名称创建一个系列并减去每个名称,但索引不匹配:

[-5, -7]

尝试减去每一个后:

foo_best_times = df[df.name == 'foo'].groupby(['day', 'name']).agg({'time': min})
bar_best_times = df[df.name == 'bar'].groupby(['day', 'name']).agg({'time': min})

我的目标是这样的:

print foo_best_times - bar_best_times

          time
day name      
1   bar    NaN
    foo    NaN
2   foo    NaN
3   bar    NaN
5   bar    NaN
    foo    NaN

如何仅通过匹配day time 1 -5 2 NaN 3 NaN 5 -7 作为索引来减去两个系列?

这是否是快速做到的正确方法?

2 个答案:

答案 0 :(得分:2)

我认为您可以将pivot_tableaggfunc=min一起使用,然后将列barfoo减去:

from StringIO import StringIO 
import pandas as pd

raw_data="""day name time
1 foo 10
1 foo 9
1 bar 4
2 foo 12
2 foo 13
3 bar 3
3 bar 5
5 foo 8
5 bar 5
5 foo 9
5 bar 1
"""

df = pd.read_csv(StringIO(raw_data), sep=' ')
print df
    day name  time
0     1  foo    10
1     1  foo     9
2     1  bar     4
3     2  foo    12
4     2  foo    13
5     3  bar     3
6     3  bar     5
7     5  foo     8
8     5  bar     5
9     5  foo     9
10    5  bar     1
df = df.pivot_table(index='day', columns='name', values='time', aggfunc=min)

print df
name  bar  foo
day           
1       4    9
2     NaN   12
3       3  NaN
5       1    8


print df['bar'] - df['foo']
1    -5
2   NaN
3   NaN
5    -7
dtype: float64

答案 1 :(得分:1)

我认为你想做的是'内在'联接。这种类型的连接执行您正在寻找的索引匹配:

from StringIO import StringIO
import pandas as pd

raw_data="""day name time
1 foo 10
1 foo 9
1 bar 4
2 foo 12
2 foo 13
3 bar 3
3 bar 5
5 foo 8
5 bar 5
5 foo 9
5 bar 1
"""

df = pd.read_csv(StringIO(raw_data), sep=' ')

# Split the dataset into the two workers
foo = df.query('name == "foo"')
bar = df.query('name == "bar"')

# Find for each day the shortest working time
foo = foo.groupby('day').agg('min')
bar = bar.groupby('day').agg('min')

# Perform an inner join of the two workers, this only keeps days
# where both workers have been working
joined = foo.join(bar, how='inner', lsuffix='_foo', rsuffix='_bar')

# Compute the difference in minimum working times
diff = joined['time_bar'] - joined['time_foo']

print diff

结果:

day
1    -5
5    -7
dtype: int64

如果您想在只有一名工作人员工作的日子里NaN,那么您可以执行“外部”联接:

# Perform an outer join of the two workers, this only keeps days
# where both workers have been working
joined = foo.join(bar, how='outer', lsuffix='_foo', rsuffix='_bar')

# Compute the difference in minimum working times
diff = joined['time_bar'] - joined['time_foo']

print diff

结果:

day
1    -5
2   NaN
3   NaN
5    -7
dtype: float64