我有一个巨大的数据集,我需要处理很多数字并寻找 1. 以获得实际解决方案和 2. 用于快速解决方案。
我试图尽可能简化并将我的问题转移到现实世界的例子中,我希望它很清楚。我很确定(至少我希望(这在某种程度上是熊猫的常见问题,而不是一个非常特殊的问题。
假设我在一家名为foo
和bar
的公司有两名工人。有时他们在同一天工作,一遍又一遍地做同样的任务。我测量他们完成任务所需的时间(有时一天只有一次,有时多次(。
我现在正在寻找的是,如果他们都在同一天工作,最短时间之间的差异。
我尝试采用全麦方法,因此尽可能多地处理表(而不是迭代(。
我目前的策略是:按day
和name
对数据进行分组,每day
和name
只保留最短的time
,如果组大小为 2(这意味着我在同一天有两个工人的数据(减去两次。
最终目标: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'])
这是分组并仅保留最短时间后表格的外观:
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
现在我只对第 1 天和第 5 天感兴趣,因为这是我唯一拥有bar
和foo
数据的日子。因此,如果我能以某种方式过滤数据并在每组中减去两次,那么结果将是[-5, -7]
的(从第 1 天:4-9,第 5 天 1-8 开始(,我会完成。
由于我无法过滤和减去,我正在尝试为两个名称创建一个系列并减去每个名称,但是索引不匹配:
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
如何通过仅匹配day
作为索引来减去这两个系列?
这甚至是快速完成它的正确方法吗?
我认为您可以将pivot_table
与aggfunc=min
一起使用,然后减去列bar
和foo
:
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
我认为你想做的是"内部"连接。这种类型的联接执行您要查找的索引匹配:
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