Python Mathematica';使用Pandas groupby按函数进行聚集

Python Mathematica';使用Pandas groupby按函数进行聚集,python,pandas,dataframe,group-by,pandas-groupby,Python,Pandas,Dataframe,Group By,Pandas Groupby,我正在设计一个类似于Mathematica中的函数。我想通过在Pandas中修饰groupby函数可以很容易地实现。此函数将根据特定的给定特征函数对列表进行分组 设置 time1 = pd.date_range(start=datetime.datetime(2015, 1, 30), end=datetime.datetime(2015, 2, 5)) datedat = np.array([time1, 0.1 * numpy.arange(7), 0.2 * numpy.arange(7)

我正在设计一个类似于Mathematica中的函数。我想通过在Pandas中修饰
groupby
函数可以很容易地实现。此函数将根据特定的给定特征函数对列表进行分组

设置

time1 = pd.date_range(start=datetime.datetime(2015, 1, 30), end=datetime.datetime(2015, 2, 5))
datedat = np.array([time1, 0.1 * numpy.arange(7), 0.2 * numpy.arange(7)]).T

print(datedat)
array([[Timestamp('2015-01-30 00:00:00', freq='D'), 0.0, 0.0],
   [Timestamp('2015-01-31 00:00:00', freq='D'), 0.1, 0.2],
   [Timestamp('2015-02-01 00:00:00', freq='D'), 0.2, 0.4],
   [Timestamp('2015-02-02 00:00:00', freq='D'), 0.3,
    0.6],
   [Timestamp('2015-02-03 00:00:00', freq='D'), 0.4, 0.8],
   [Timestamp('2015-02-04 00:00:00', freq='D'), 0.5, 1.0],
   [Timestamp('2015-02-05 00:00:00', freq='D'), 0.6,
    1.2]], dtype=object)
假设我想按年份和月份对它进行分组——你会看到有一月和二月的数据。所以我设计了一个特征函数:

gatherf = lambda x: ((x[0].year)*1000+x[0].month)
对于每次数据记录,此
gatheref
将计算
groupby
的值以区分时间

目标

我的最终目标是开发一个函数
gather\u by
,通过它

gather_by(datedat, gatherf)
应生成以下内容:

array([[[Timestamp('2015-01-30 00:00:00', freq='D'), 0.0, 0.0],
   [Timestamp('2015-01-31 00:00:00', freq='D'), 0.1, 0.2]],

   [[Timestamp('2015-02-01 00:00:00', freq='D'), 0.2, 0.4],
   [Timestamp('2015-02-02 00:00:00', freq='D'), 0.3,
    0.6],
   [Timestamp('2015-02-03 00:00:00', freq='D'), 0.4, 0.8],
   [Timestamp('2015-02-04 00:00:00', freq='D'), 0.5, 1.0],
   [Timestamp('2015-02-05 00:00:00', freq='D'), 0.6,
    1.2]]], dtype=object)

我的努力

在一般情况下,
datedat
的列可能多于3列。我不能把他们一个一个地分组。所以我试着:

datedatF2 =pandas.DataFrame({'dat':datedat,'gather_key':numpy.array(list(map(gatherf, datedat)))})


但这会导致
数据必须是一维的
错误。我该怎么办?

我想您可以使用
groupby
by映射函数
gatherf

datedatF2 = pd.DataFrame(datedat)

gatherf = lambda x: x[0].year*1000 + x[0].month

out = [x.values.tolist() for i, x in datedatF2.groupby(list(map(gatherf, datedat)))]
print (out)

[[[Timestamp('2015-01-30 00:00:00', freq='D'), 0.0, 0.0], 
  [Timestamp('2015-01-31 00:00:00', freq='D'), 0.1, 0.2]], 

[[Timestamp('2015-02-01 00:00:00', freq='D'), 0.2, 0.4], 
  [Timestamp('2015-02-02 00:00:00', freq='D'), 0.3, 0.6], 
  [Timestamp('2015-02-03 00:00:00', freq='D'), 0.4, 0.8], 
  [Timestamp('2015-02-04 00:00:00', freq='D'), 0.5, 1.0],
  [Timestamp('2015-02-05 00:00:00', freq='D'), 0.6, 1.2]]]
使用
系列的第一个解决方案

datedatF2 = pd.DataFrame(datedat)
dates = pd.to_datetime(datedatF2.iloc[:, 0])

s = dates.dt.year*1000 + dates.dt.month
print (s)
0    2015001
1    2015001
2    2015002
3    2015002
4    2015002
5    2015002
6    2015002
Name: dat0, dtype: int64

out = [x.values.tolist() for i, x in datedatF2.groupby(s)]
编辑:

第二种方法:

N = 100000
df = pd.DataFrame({1:pd.date_range('2015-01-01', periods=N, freq='15H'),
                   2:np.random.randint(100, size=N),
                   3:np.random.randint(100, size=N)})
datedat = df.values


In [75]: %%timeit
    ...: datedatF2 = pd.DataFrame(datedat)
    ...: dates = pd.to_datetime(datedatF2.iloc[:, 0])
    ...: s = dates.dt.year*1000 + dates.dt.month
    ...: out = [x.values.tolist() for i, x in datedatF2.groupby(s)]
    ...: 
1 loop, best of 3: 249 ms per loop

In [76]: %%timeit
    ...: datedatF2 = pd.DataFrame(datedat)
    ...: gatherf = lambda x: x[0].year*1000 + x[0].month
    ...: out = [x.values.tolist() for i, x in datedatF2.groupby(list(map(gatherf, datedat)))]
    ...: 
1 loop, best of 3: 359 ms per loop
警告

性能取决于数据帧的大小和值组的数量。但通常第二种解决方案比第一种更快。

输入-

datedat

array([[Timestamp('2015-01-30 00:00:00', freq='D'), 0.0, 0.0],
       [Timestamp('2015-01-31 00:00:00', freq='D'), 0.1, 0.2],
       [Timestamp('2015-02-01 00:00:00', freq='D'), 0.2, 0.4],
       [Timestamp('2015-02-02 00:00:00', freq='D'), 0.3, 0.6],
       [Timestamp('2015-02-03 00:00:00', freq='D'), 0.4, 0.8],
       [Timestamp('2015-02-04 00:00:00', freq='D'), 0.5, 1.0],
       [Timestamp('2015-02-05 00:00:00', freq='D'), 0.6, 1.2]], dtype=object)
gatherf

lambda x: ((x[0].year) * 1000 + x [0].month) 

基于当前方法的一种非常可靠的分组方法是将自定义列表/键传递给
groupby
(分组谓词不必属于数据帧!)-

或者,作为列表理解-

r = [g.values.tolist() for _, g in pd.DataFrame(datedat).groupby(key)]


这也适用于任何数量的列,前提是
gatheref
的编写要与之匹配。

您的变量名需要做一些工作。。。此外,您能否具体概述您的输入是什么,以及您对所述输入的预期输出是什么?输入是datedat、date dat记录列表和特征函数GARGETF。输出应为分组列表,包含原始列表中的所有信息@Cᴏʟᴅsᴘᴇᴇᴅ你能保证第一列总是日期吗?不,第一列可以是任何东西。我可以为不同的情况写不同的gatherf。@jezrael同意,但是在这种情况下,基于问题的性质,我认为这是不可能的:-)你已经彻底修改了你的答案,现在它几乎和我的完全一样。有什么想法吗?第二种解决方案更快,因为它使用更好的方法来计算关键点(年和月)?在一般情况下,第一列可能不需要是datetime。在pandas中,我的意见是不使用
映射
,因为速度慢。我认为itt更快,因为矢量化了。
key = list(map(gatherf, datedat))

r = []
for _, g in pd.DataFrame(datedat).groupby(key):
    r.append(g.values.tolist())
r = [g.values.tolist() for _, g in pd.DataFrame(datedat).groupby(key)]
np.array(r)

[[[Timestamp('2015-01-30 00:00:00', freq='D'), 0.0, 0.0],
  [Timestamp('2015-01-31 00:00:00', freq='D'), 0.1, 0.2]],
 [[Timestamp('2015-02-01 00:00:00', freq='D'), 0.2, 0.4],
  [Timestamp('2015-02-02 00:00:00', freq='D'), 0.3, 0.6],
  [Timestamp('2015-02-03 00:00:00', freq='D'), 0.4, 0.8],
  [Timestamp('2015-02-04 00:00:00', freq='D'), 0.5, 1.0],
  [Timestamp('2015-02-05 00:00:00', freq='D'), 0.6, 1.2]]]