V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
w12103
V2EX  ›  Python

pandas 代码请教

  •  
  •   w12103 · 2018-01-11 23:09:13 +08:00 · 2723 次点击
    这是一个创建于 2258 天前的主题,其中的信息可能已经有所发展或是发生改变。
    for i, row in dset.iterrows():
        hteam = row['home']
        vteam = row['visitor']
        row['hlastwin'] = won_last[hteam]
        row['vlastwin'] = won_last[vteam]
        dset.iloc[i] = row
    

    如上,dset 是一个 DataFrame,遍历每行并为每行增加两个元素,期望遍历结束后 dset 应该增加两列,但实际 dset 没有变化,最后一行代码为啥没效果,有大神能说一下原因吗(搜了一通没啥结果。。),多谢~

    第 1 条附言  ·  2018-01-12 10:43:00 +08:00
    循环里还有两句代码没写全,抱歉~
    如下:
    ```
    won_last[hteam] = row['homewin']
    won_last[vteam] = not row['homewin']
    ```
    row['homewin'] 类型是 bool。
    8 条回复    2018-01-12 22:53:59 +08:00
    shidenggui
        1
    shidenggui  
       2018-01-11 23:40:00 +08:00
    应该这样写是可以的 dset.assign(hlastwin=lambda x: won_last[x.home], vlastwin=lambda x: won_last[x.visitor])
    imn1
        2
    imn1  
       2018-01-11 23:50:29 +08:00   ❤️ 1
    iloc/loc 等一般只能用于读取,应该只是类似一个 copy 的性质
    改变 df 要另外赋值

    另外,这样轮循有点笨啊,应该整列复制,或者 join/merge
    zeq
        3
    zeq  
       2018-01-12 00:38:51 +08:00
    ```
    dest['hlastwin'] = dest['home'].map(lambda h: won_last[h])
    ```

    大概是这么一个思路
    neoblackcap
        4
    neoblackcap  
       2018-01-12 09:23:06 +08:00
    上面几楼都说了,我加一句,pandas 是调用 numpy 的接口的,因此不要自己写循环。自己的循环是没有 Pandas 里面的对 dataframe 的操作快的。
    fcfangcc
        5
    fcfangcc  
       2018-01-12 09:51:50 +08:00
    dset.loc[:, 'hlastwin'] = [won_last[i] for i in dset['home'].values]
    dset.loc[:, 'vlastwin'] = [won_last[i] for i in dset['visitor'].values]
    zyhuang
        6
    zyhuang  
       2018-01-12 09:54:56 +08:00
    ```
    import pandas as pd
    import numpy as np

    won_last = pd.DataFrame({'lastwin':["lastwin_{}".format(i) for i in range(10000)]})
    dset = pd.DataFrame(np.random.randint(10000, size=(10000, 2)),
    columns=['home', 'visitor'])
    In [2]:
    %timeit dset.merge(won_last, left_on='home', right_index=True,how='left').merge(won_last, left_on='visitor', right_index=True,how='left', suffixes="hv")

    7.16 ms ± 340 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


    In [3]:
    %timeit dset.assign(hlastwin=lambda x: [won_last.lastwin[ii] for ii in x.home], vlastwin=lambda x: [won_last.lastwin[ii] for ii in x.visitor])
    355 ms ± 34.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

    ```
    w12103
        7
    w12103  
    OP
       2018-01-12 10:29:30 +08:00
    @imn1 按行遍历是因为 won_last 字典不断变动,我把代码补全一下。。
    focusheart
        8
    focusheart  
       2018-01-12 22:53:59 +08:00
    你问的 iloc 那句不起作用,可以按楼上说的改,比如:

    dset[i, 'hlastwin'] = won_last[hteam]

    另外,看你的程序意思是每次循环里要给当前 row 填一个“主队上次赢”,“客队上次赢”这样的字段?
    由于每个 row 都依赖上一次某条的记录,所以 merge 不太容易吧。
    如果是这个情况的话,用 pandas 原地修改 dset 会比较慢,可以新开一个 list 来存;或者原始数据不放 pandas,直接用 list。
    这样用 for 循环遍历的表现可能会好一些。

    最后,这样一边迭代 dset,同时一边又修改 dset,感觉不太好。建议迭代 dset 的时候不要原地修改,而是将新 row 的数据放在其他变量里。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3531 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 10:57 · PVG 18:57 · LAX 03:57 · JFK 06:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.