【问题标题】:Techniques for increasing python pandas speed提高 python pandas 速度的技术
【发布时间】:2020-08-24 15:07:48
【问题描述】:

我有一个大(3MM 记录)文件。

该文件包含四列:[id, startdate, enddate, status] 每个id都会有多个状态变化,我的目标是转置这些数据并最终得到一个包含以下列的宽数据框:

[id, status1, status2, status3... statusN] 

其中行的值将是 id,以及列上状态的开始日期。

行的一个例子是:

["xyz", '2020-08-24 23:42:54', '(blank)', '2020-08-26 21:23:45'...(startdate value for status N)] 

我编写了一个执行以下操作的脚本:遍历第一个数据帧的所有行,并将状态存储在一个集合中,这样就没有重复,我可以获得所有状态的足够列表。

df = pd.read_csv('statusdata.csv')
columns = set()
columns.add('id')
for index, row in df.iterrows():
    columns.add(row['status'])

然后我创建一个新的数据框,其中包含“id”列,然后是从 Set 中获取的所有其他状态

columnslist = list(columns)
newdf = pd.DataFrame(columns = columnslist)
newdf = newdf[['id']+[c for c in newdf if c not in ['id']]] #this will make 'id' the first column

然后我遍历原始数据帧的所有列并在新数据帧中创建一条新记录,如果它正在读取的 id 尚未在数据帧中,然后将原始 df 中指示的状态的开始日期记录在其上新df中的匹配列。

for index, row in df.iterrows():
        if row['opportunityid'] not in newdf['id']:
            newdf.loc[len(newdf), 'id'] = row['opportunityid']
        newdf.loc[newdf['id'] == row['opportunityid'], row['status']] = row['startdate']

我担心的是代码的速度。以这种速度,将需要 13 多个小时来遍历原始数据帧的所有行,以将其转置到具有唯一键的新数据帧中。有没有办法让这更有效?有没有办法从我的计算机分配更多内存?或者有没有办法将此代码部署在 aws 或其他云计算软件上以使其运行得更快?我目前在 2020 年 13 英寸 mac book pro 上运行它,内存为 32 GB。

谢谢!

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    IIUC,您无需迭代即可做到这一点。首先,创建样本数据:

    from io import StringIO
    import pandas as 
    
    data = '''id, start, end, status
    A, 1, 10, X
    A, 2, 20, Y
    A, 3, 30, Z
    A, 9, 99, Z
    B, 4, 40, W
    B, 5, 50, X
    B, 6, 60, Y
    '''
    df = pd.read_csv(StringIO(data), sep=', ', engine='python')
    print(df)
    
      id  start  end status
    0  A      1   10      X
    1  A      2   20      Y
    2  A      3   30      Z
    3  A      9   99      Z  # <- same id + status as previous row
    4  B      4   40      W
    5  B      5   50      X
    6  B      6   60      Y
    

    其次,选择感兴趣的列(除end 之外的所有列);将 idstart 设置为行标签; squeeze() 确保将对象转换为熊猫系列;最后将status 作为列标签:

    t = (df[['id', 'start', 'status']]
         .groupby(['id','status'], as_index=False)['start'].max() # <- new
         .set_index(['id', 'status'], verify_integrity=True)
         .sort_index()
         .squeeze()
         .unstack(level='status')
        )
    print(t)
    status    W    X    Y    Z
    id                        
    A       NaN  1.0  2.0  9.0
    B       4.0  5.0  6.0  NaN
    

    NaN 值显示当status 中没有 100% 重叠时会发生什么。

    更新

    我添加了一行数据导致重复的 (id, status) 对。还添加了groupby() 方法来提取最新的(id, status) 对。

    【讨论】:

    • 首先,感谢您的及时响应,运行您非常优雅的脚本后,我收到了 ValueError,索引包含重复条目,无法重塑。由于这是我第一次看到这种类型的 df 操作,我不确定为什么会这样。您的示例 df 应涵盖我的 df 中的所有案例。你有重复的 id 和重复的状态,我可能要补充的一件事是“开始”也可能是重复的。
    • 编辑:我能想到的一件事是,可能存在 [id, status] 对存在两次的实例(例如,在状态回滚然后重新提升的情况下) ,我该如何处理?
    • 嗨,我添加了groupby() 以获取此案例的最新开始。您可以修改 groupby() 语句以获取最早开始、最晚结束等。
    • 您先生是个天才。谢谢!你从哪里学习?我愿意提高自己的技能。
    • 谢谢!我在 pandas 文档上花了很多时间,包括pandas.pydata.org/docs/user_guide/10min.html#min——我花了 _lot_more 超过 10 分钟。另一个来源是vita.had.co.nz/papers/tidy-data.pdf(它的重点是 R,但概念是翻译的)。
    猜你喜欢
    • 2011-07-15
    • 2021-09-18
    • 1970-01-01
    • 2015-09-27
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    相关资源
    最近更新 更多