【问题标题】:Pandas - call user defined function on subset dataframePandas - 在子集数据帧上调用用户定义的函数
【发布时间】:2019-07-16 21:39:50
【问题描述】:

我正在 Pandas DataFrame 的子集上创建一个计数函数,并打算导出仅包含 groupby 标准和计数结果的字典/电子表格数据。

In [1]: df = pd.DataFrame([[Buy, A, 123, NEW, 500, 20190101-09:00:00am], [Buy, A, 124, CXL, 500, 20190101-09:00:01am], [Buy, A, 125, NEW, 500, 20190101-09:00:03am], [Buy, A, 126, REPLACE, 300, 20190101-09:00:10am], [Buy, B, 210, NEW, 1000, 20190101-09:10:00am], [Sell, B, 345, NEW, 200, 20190101-09:00:00am], [Sell, C, 412, NEW, 100, 20190101-09:00:00am], [Sell, C, 413, NEW, 200, 20190101-09:01:00am], [Sell, C, 414, CXL, 50, 20190101-09:02:00am]], columns=['side', 'sender', 'id', 'type', ''quantity', 'receive_time'])
Out[1]: 
   side  sender  id    type     quantity  receive_time 
0  Buy   A       123   NEW      500       20190101-09:00:00am
1  Buy   A       124   CXL      500       20190101-09:00:01am
2  Buy   A       125   NEW      500       20190101-09:00:03am
3  Buy   A       126   REPLACE  300       20190101-09:00:10am
4  Buy   B       210   NEW      1000      20190101-09:10:00am
5  Buy   B       345   NEW      200       20190101-09:00:00am
6  Sell  C       412   NEW      100       20190101-09:00:00am
7  Sell  C       413   NEW      200       20190101-09:01:00am
8  Sell  C       414   CXL      50        20190101-09:02:00am

count函数如下(mydf作为dataframe的子集传入):

def ordercount(mydf):
   num = 0.0
   if mydf.type == 'NEW':
      num = num + mydf.qty
   elif mydf.type == 'REPLACE':
      num = mydf.qty
   elif mydf.type == 'CXL':
      num = num - mydf.qty
   else: 
      pass
   orderdict = dict.fromkeys([mydf.side, mydf.sender, mydf.id], num)
   return orderdict

从 csv 读取数据后,我按一些标准对其进行分组并按时间排序:

df = pd.read_csv('xxxxxxxxx.csv, sep='|', header=0, engine='python', names=col_names)
sorted_df = df.groupby(['side', 'sender', 'id']).apply(lambda_df:_df.sort_values(by=['time']))

然后在排序后的数据上调用之前定义的函数:

print(sorted_df.agg(ordercount))

但是值错误不断出现,说太多行无法调用。

统计数据的函数方式可能效率不高,但它是我能想到的最直接的方式来匹配订单类型和相应的统计数量。我希望程序输出一个表,其中只显示边、发件人、ID 和计数的数量。有没有办法实现这一目标?谢谢。

预期输出:

   side   sender   total_order_num   trade_date 
0  Buy    A        300               20190101
1  Buy    B        1200              20190101
2  Sell   C        250               20190101

【问题讨论】:

  • 似乎您只需要在多列上对数据框进行排序。 df.sort_values(['side', 'sender', 'id', 'time'])
  • 我不认为问题出在排序上,而是不能在子集上调用函数
  • df.groupby(['side','sender','id']).apply(ordercount) ?
  • 最好向这个问题添加一个小数据集和预期输出以获得更好的帮助。见this post
  • sorted_df = df.groupby(['side', 'sender', 'id'])['time'].apply(lambda df:df.sort_values())

标签: python pandas function dataframe pandas-groupby


【解决方案1】:

我相信您的功能不容易一次应用,因为您根据行执行不同的操作。如果您只有 +- 作为您的操作,但您在某个时间点使用 replace 的值,然后继续其他操作,这将是可以的。因此,循环可能会更简单,或者您可以花一些时间来拥有一个很好的函数来完成任务。

这就是我所拥有的。我真正所做的只是更改您的ordercount,以便它直接在一个子集上运行,您可以通过简单的分组获得该子集。您可以在分组之前按时间排序,也可以在 ordercount 函数中进行排序。希望这会有所帮助。

import pandas as pd
df = pd.DataFrame([['Buy', 'A', 123, 'NEW', 500, '20190101-09:00:00am'],
                   ['Buy', 'A', 124, 'CXL', 500, '20190101-09:00:01am'],
                   ['Buy', 'A', 125, 'NEW', 500, '20190101-09:00:03am'],
                   ['Buy', 'A', 126, 'REPLACE', 300, '20190101-09:00:10am'],
                   ['Buy', 'B', 210, 'NEW', 1000, '20190101-09:10:00am'],
                   ['Buy', 'B', 345, 'NEW', 200, '20190101-09:00:00am'],
                   ['Sell', 'C', 412, 'NEW', 100, '20190101-09:00:00am'],
                   ['Sell', 'C', 413, 'NEW', 200, '20190101-09:01:00am'],
                   ['Sell', 'C', 414, 'CXL', 50, '20190101-09:02:00am']],
columns=['side', 'sender', 'id', 'type', 'quantity', 'receive_time'])

df['receive_time'] = pd.to_datetime(df['receive_time'])
df['receive_date'] = df['receive_time'].dt.date # you do not need the time stamps


def ordercount(mydf):
    mydf_ = mydf.sort_values('receive_time')[['type', 'quantity']].copy()
    num = 0
    for val in mydf_.values:
        type_, quantity = val
        # val is going to be a list like ['NEW', 500]. All I am doing above is unpack the list into two variables.
        # You can find many resources on unpacking iterables
        if type_ == 'NEW':
            num += quantity
        elif type_ == 'REPLACE':
            num = quantity
        elif type_ == 'CXL':
            num -= quantity
        else:
            pass
    return num

mydf = df.groupby(['side', 'sender', 'receive_date']).apply(ordercount).reset_index()

输出:

|----|--------|----------|---------------------|------|
|    | side   | sender   | receive_date        |    0 |
|----|--------|----------|---------------------|------|
|  0 | Buy    | A        | 2019-01-01 00:00:00 |  300 |
|----|--------|----------|---------------------|------|
|  1 | Buy    | B        | 2019-01-01 00:00:00 | 1200 |
|----|--------|----------|---------------------|------|
|  2 | Sell   | C        | 2019-01-01 00:00:00 |  250 |
|----|--------|----------|---------------------|------|

您可以根据需要轻松地将列重命名为“0”。我仍然不确定您的trade_date 是如何定义的。您的数据是否只有一个日期?当你有多个约会对象时会发生什么?你在拿分钟吗?...

编辑:如果您尝试使用此数据框,您可以看到日期按预期工作的组。

df = pd.DataFrame([['Buy', 'A', 123, 'NEW', 500, '20190101-09:00:00am'],
                   ['Buy', 'A', 124, 'CXL', 500, '20190101-09:00:01am'],
                   ['Buy', 'A', 125, 'NEW', 500, '20190101-09:00:03am'],
                   ['Buy', 'A', 126, 'REPLACE', 300, '20190101-09:00:10am'],
                   ['Buy', 'B', 210, 'NEW', 1000, '20190101-09:10:00am'],
                   ['Buy', 'B', 345, 'NEW', 200, '20190101-09:00:00am'],
                   ['Sell', 'C', 412, 'NEW', 100, '20190101-09:00:00am'],
                   ['Sell', 'C', 413, 'NEW', 200, '20190101-09:01:00am'],
                   ['Sell', 'C', 414, 'CXL', 50, '20190101-09:02:00am'],
                   ['Buy', 'A', 123, 'NEW', 500, '20190102-09:00:00am'],
                   ['Buy', 'A', 124, 'CXL', 500, '20190102-09:00:01am'],
                   ['Buy', 'A', 125, 'NEW', 500, '20190102-09:00:03am'],
                   ['Buy', 'A', 126, 'REPLACE', 300, '20190102-09:00:10am'],
                   ['Buy', 'B', 210, 'NEW', 1000, '20190102-09:10:00am'],
                   ['Buy', 'B', 345, 'NEW', 200, '20190102-09:00:00am'],
                   ['Sell', 'C', 412, 'NEW', 100, '20190102-09:00:00am'],
                   ['Sell', 'C', 413, 'NEW', 200, '20190102-09:01:00am'],
                   ['Sell', 'C', 414, 'CXL', 50, '20190102-09:02:00am']],
columns=['side', 'sender', 'id', 'type', 'quantity', 'receive_time'])

【讨论】:

  • 我在许多文件上运行程序。每个交易日一个文件,一天内交易时间不同的多行。
  • 我想查看每天的总数。所以我对所有文件使用按时间值排序,然后应用相同的功能。但它似乎不起作用,我不断收到重新索引值错误
  • 您实际上应该创建一个仅包含日期的附加列。我将编辑我的示例
  • 我确实创建了一个仅包含日期的附加列。我实际上使用相同的代码:df['receive_date'] = df['receive_time'].dt.date,并将其作为计数函数的一部分重新格式化输出。当我尝试在数据文件列表上调用该函数时遇到重新索引错误时知道吗?
  • 你能在编辑中添加新代码到原来的问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多