烦请督促我的游戏功课喔!

游戏夜读 | RPG的美式和日式

文/良宵听雨。授权“游戏夜读”发表。

这个分法是从别人那里偷学来的,并没有经过任何的验证。重点不在谈分得对不对,而是为什么要这样分成两类。理由大致有四个方面。

美式RPG。日式RPG。

首先,人云亦云。比如刚才说的偷学。因为自己没有那么多的涉猎,没有办法思考,更没有能力进行游戏类型下的一级分类,索性套用现成的。

其次,市场导向。比如欧美市场,日韩市场。由于要面向特定区域的人群,也就形成了对特定区域的研究。以中国为轴心,一个在东,一个在西,自然分成了两大市场,又不轻易更换战场,也就逐渐形成了两大阵营,缺少沟通,就成了类别。

再者,爆款属性。比如多人在线,ACG。起初,可能只是几个疯狂的粉丝对峙,接着,就有更多的玩家加入其中,并被强制要求站队。一切的源头,是人类的组织能力,以及媒体的传播方向。

最后,学习模式。从教育方式的角度来说,比如填鸭式,DIY。一般来说,美式RPG的自由度高,日式RPG剧情紧凑。自我探索,命令执行,两者的渊源一下子说不清楚,大致与人口有关吧。

游戏夜读 | 《FPS关卡设计》

文/良宵听雨。授权“游戏夜读”发表。

FPS关卡设计,这是书名,也是作者的日常工作内容,但书的内容并不仅限于FPS,作者对此也做了一番解释,极具设计阅历和分享精神,摘抄如下。

正如书名所指出的,本书主要讲解第一人称射击(FPS)游戏的关卡设计。第一人称射击游戏是最常见的游戏类型,相比于其他类型的游戏,这种游戏的关卡设计尤为重要。所以,作为定义关卡设计的第一个游戏类型,我觉得选择第一人称射击游戏进行讲解是很合适的。并且,我一直从事第一人称与第三人称射击游戏的开发工作,只对这两类游戏比较熟悉,而对于讲解其他类型游戏的关卡设计没有多少信心。其实,对关卡设计的定义不受游戏类型影响,在所有游戏中都是一样的。所以如果以后有机会参与其他类型的游戏开发,我会努力针对相关类型的关卡设计进行定义。我个人认为,人们最近开始对2D横版游戏的关卡设计表现出浓厚的兴趣。

书并不厚,思路也并不复杂,但通读整本书后,对关卡设计就形成了一定的认识。对如何做好关卡设计,需要多久做好一个关卡,以及过程中会遇到的最棘手是困难等等,都有了感性的认识。

关卡设计的探索,就像即使在横向的流水线上,专业度也可以纵向发展。当我们把目光从剧情转到那一个个关卡,不得不惊叹,同样的空间大小,或者时间长度,竟然有那么多种可能,而且还是挺好玩的关卡,有些还是很耐玩的那种。这背后都是关卡设计师们的辛勤、脑细胞、硬盘和汗水。


顺祝圣诞

游戏夜读 | 游戏关卡设计师

文/良宵听雨。授权“游戏夜读”发表。

本来想取一个颇有吸引力的题目,这样就能有更多的人来了解这个行业和岗位。但是,要介绍的这是个苦差事,想了想,还是不要带有忽悠的成分好,中规中矩,是个正经儿的行当跟职业。

关卡设计师的苦,首先跟所有设计师一样,是需要积累的。时间长短不好说,总之不能没有。再者,还得耐得住性子,因为过程中需要面对反复无常的用户,以及同事们。最后,得按部就班,在游戏整体的规则设定好之后再动手,以防返工。

刚开始时,并不需要担心做太多准备工作。如果你是关卡设计新手,可以先从商业游戏地图的制作起步。这些游戏中,上述准备工作都已做好,只要熟记这些游戏中已经设置好的角色高度、掩体高度,就能自己动手制作地图,实现个性创意。

如果是少年英才,上面的统统都想不管不顾,那么下面这一条还是必要的,请务必牢记于心。

对关卡设计师而言,最重要的是尽早测试并发现乐趣。

没有比尽早测试更重要的了!如果有,那就是尽早发现乐趣,因为伴随测试的,必须是有乐趣。这可能是作为关卡设计师唯一可以自豪的点了。

尽管把关卡设计师描述的有点惨,但实际的情况是,从业的关卡设计师喜忧参半,有些人似乎轻轻松松,有些人心理压力超大。

差别在哪儿呢?

多半是因为积累的程度,比如编辑器的熟练程度,设计思路和技巧的总结,还有最重要的:素材。谁让他们是设计师呢!

游戏夜读 | 在游戏中打败人类

文/良宵听雨。授权“游戏夜读”发表。

一系列的惊喜!以及错愕,还有期待。

2017年3月,人工智能Libratus在宾夕法尼亚州挑战美国顶尖德州扑克游戏玩家,在12万手比赛后,Libratus完胜全部4个对手。Libratus使用的“强化学习”方式能让计算机生成更具创造性的策略,在信息不完全的情况下作出更好的决策。5月,强化版围棋人工智能AlphaGo在中国乌镇3:0战胜世界第一棋手柯洁,并与八段棋手协同作战在组队战中全胜5位顶尖九段棋手。AlphaGo的第一个版本使用来自人类专家的训练数据进行引导,通过自我下棋和对蒙特卡洛树搜索稍加改动进行进一步的改进。10月,横空出世的AlphaGo Zero仅通过40天的学习就战胜了自己的双胞胎兄弟AlphaGo Master。AlphaGo Zero采用无监督学习,从零开始,不需要任何人类的经验,并通过强化学习发现了新的围棋定式。AlphaGo Zero还优化了核心算法,将策略网络和值网络结合,并引入深度残差网络,用更少的算力得到了更好的结果。

2017年底,我们看到了AlphaGo Zero算法的另一个演绎:AlphaZero,它不仅精通围棋,还精通国际象棋和日本象棋,使用了一模一样的技术。有意思的是,这些软件走的步连经验最丰富的围棋选手都感到惊讶,激励围棋选手向AlphaGo学习,相应地调整自己的棋风。为了让这更容易,DeepMind还发布了AlphaGo 教学工具。围棋不是我们取得重大进展的唯一游戏。

强化学习的下一个领域似乎是更复杂的多人游戏,包括多人扑克,电子竞技。

DeepMind正在积极研究《星际争霸2》,发布了一种研究环境。与此同时,Libratus是卡内基•梅隆大学的研究人员开发的一个系统,它在为期20天的“一对一无限注德州扑克”(Heads-up, No-Limit Texas Hold’em)标赛中成功击败了顶尖扑克玩家。稍早些时候,查尔斯大学、捷克技术大学和艾伯塔大学的研究人员共同开发的DeepStack系统成为第一个击败职业扑克玩家的系统。请注意,这两个系统玩的都是单挑扑克比赛,这在两名玩家之间进行,比多个玩家扑克比赛容易得多。OpenAI在1v1 Dota 2中展示了初步的成功,目的在于在不远的将来能够玩转真正的5v5游戏。

然而,在这些激动人心的背后,是大把的钞票。比如DeepMind。

2017年,DeepMind亏损3.02亿英镑,相当于人民币27亿元。这个数字同比增长了221%。同期,DeepMind的员工成本大增。简单估算一下,这家公司员工的平均年薪:250万元(人民币)。不过,DeepMind的商业化能力还没有同步猛增。但是不用担心,虽然烧钱速度快得惊人,但Google依然支撑得起。DeepMind在报告中说,Google会在至少未来12个月时间里,继续向他们提供充足的财务支持,还写下了书面保证。

早在2016年,DeepMind在联合创始人穆斯塔法·苏莱曼(Mustafa Suleyman)的领导下,作为其应用团队的一部分成立了健康部门。该团队的目标一直是在现实环境中开发和部署人工智能技术,包括家庭医生诊所和医院,但到目前为止还没有商业产品,该部门尚未产生任何收入。此外,在英国和美国,该公司其他健康项目还包括一个医疗诊断应用程序,以及一个使用人工智能来分析医学扫描的(数据)流和程序。

2018年11月,DeepMind宣布将把其健康部门的控制权移交给加州一个新的谷歌健康部门,这表明该公司计划将努力进行扩张和商业化。在2019年3月的一次人工智能系统的现场演示中,DeepMind对一名患者进行了视网膜扫描,并对该女性患者的眼睛进行了实时诊断。扫描结果由谷歌云中的一组算法进行分析,这些算法在大约30秒内就给出了(疾病)紧急程度评级和详细诊断。

该系统能够检测包括青光眼、糖尿病性视网膜病变和老年性黄斑变性在内的一系列眼病,其准确度与世界领先专家水平相当。该产品原型是在过去三年中与伦敦Moorfields眼科医院合作开发的。有关这项研究的细节发表在去年8月的科学杂志《自然医学》(Nature Medicine)上。

只是,这些所谓的“商业应用”,均尚未进入业务应用领域。究其原因,还是在于现在的AI只是超级计算木偶人,只要游戏换个地图,就又要另外排一场戏。那么,后面的故事可能就像《权力的游戏》第八季一般,开始让媒体和大众觉得越来越无趣了吧!但真正的AI探险家们,仍在攀登。

游戏夜读 | 关卡设计新手必看

文/良宵听雨。授权“游戏夜读”发表。

作为一个新手,容易迷茫。这时候,可以给自己一点时间、空间去思考,或者用来发呆也不错。当然啦,直接下地干活最好了,不会有迷茫的问题。

上面说的是宏观的思路,谁都能说。但给到了具体的,特别是有时间限制的,一个事情,一个决定,一个任务,一个地图作业,就变得困难了。

随着时间一分一秒在流逝,困难的心理压强不断加剧。一方面,是因为作为新手,无法预估工时,或者是对自己的预估信心不足。另一方面,新手一般新在实践经历少,理论知识也可能有缺陷。这样一来二去,很多时候就变得狂躁不安。

一想到要动手设计关卡,大多数新手常见的做法是立刻打开地图编辑器动手制作,连素描图也不画。这种做法会使地图制作过程变得缓慢,毫无目的可言。这样制作好地图之后,自己玩的时候会觉得没什么意思,但又很难发现究竟哪里出了问题。于是到处修改,却发现越改问题越多。原本打算充分利用高差形成酣畅淋漓的战斗,但不知不自觉间地图变得很平,让人兴趣全无。

真想直接找一份参考答案!参考必须有,答案没有,这也是新人存在的价值。必须要着重强调的一点是,一个作业的好坏,并不看作者的新旧。

这正是每个设计师的机遇,也属于新人。

为了尽快实践最佳设计思路,要尽早开启流程。一个高效的设计思路,可以通过前期的准备获得,好在现在愿意分享思路的人越来越多了,应该可以很快获得。

大多数情况下,这些设计思路都会先建议,从找灵感开始,然后就是构思,再就是实现关键点,接着就是面向用户设计UCD的敏捷Angie开发。那上面说的“参考”呢?在什么位置上出现?

参考可以在任何位置出现。作为新手,积累不够的情况下,就是快速参考那些成熟作品,自己敲定某张地图的乐趣。记住,只有按照设计思路,才能让自己朝着更专业的路上狂奔。同时,尽可能通过参考加快速度,才能尽快开始后面的流程。这样实践,任务就能尽快交付了,又不至于新人还是新人,只是做了一次搬运。

几次下来,也就不再是新人了。要开始思考另外一个重要的问题:关卡设计的关键是什么?

游戏夜读 | 关卡设计的难点

文/良宵听雨。授权“游戏夜读”发表。

原先的计划是先入门,再讲关键点,再然后是难点,这应该算一个不错的进阶路径。但是,但是,但是,有一句话说的妙,叫“方向比努力重要”。

所以,看从入门到精通系列的里面,肯定有不少是围观者,是试探性的了解和咨询,即使我并不清楚这确切的比例,但这部分需求存在无疑了。

充分接受玩家的反馈意见。

兴趣总是在不经意之间就跑出来了!可是长久的热情和持久的热忱,却像干旱地区的花朵,开得异常真贵,以及艰辛。

关卡设计师之路,很长,很枯燥。凡是这样的工作,都是入门相对辛苦一点,然后就是轻松的中长期,想够着上面,却怎么蹦也不行,一不留神儿,就被人弯道超了车。

这当然跟创意,也就是想象力,跟联想能力是有强相关的。但是,但是,但是,凡事艺术搭边的事情,一到了市场上,就得听观众的口碑。

所以,终于啊,说到了关卡设计师的难点,那就是要不停的听别人的意见,而且还得听得进去。即使前前后后,都意见相左了,也是一种思路。

也许,这世界上也有不听人反馈的关卡设计师,那这个设计师一定是找到了上上乘的武功秘籍,获得了超级深厚的内功,引领风骚哈!

有谁不想自己有这样的好运气吗?

游戏夜读 | 做游戏选什么专业?

文/良宵听雨。授权“游戏夜读”发表。

高考是结业考,是入学考,是九年义务教育的终点站,除了分数,除了排名,除了奖学金,还将自动获得一把开启“专业自选超市”大门的钥匙。

作为一名游戏爱好者,可能会想了解选什么专业,才能成为一个“科班”。

海外看专业名称,海内存知己

有了解过海外留学项目的同学,肯定会发现有一个专业,正儿八经的,就叫做游戏设计与开发专业,偏向于艺术项目类,课程中除了设计理论,还需要涉及非常多的实践项目,能执行结合,成就一份满得要溢出的游戏项目经验登记册。

如果是海外留学,那么选专业没那么多纠结,做游戏选对口的专业即可。

但放到国内,游戏设计和开发的专业不是没有,只是还没有那么普遍,并且有些还会“名不副实”,需要一双慧眼和一颗强大的内心。在有游戏专业的院校里,一类是编程为主,一类是绘画为主,一类是设计为主,常见的是多媒体、动画制作等。

主要的原因,应该是因为不同地区游戏公司规模和制作流程的发展程度不同。

十年寒窗无人问,前途亦坎坷

欧美、日韩作为电子游戏的发源地,主张培养游戏设计与开发工程师。国内因为岗位和毕业生的供求关系,催生出了因时制宜的培养方式。在人才短缺的时候,以培养具体的工种为主,且门槛低,又很容易之后人才过剩,要做好心理准备。

选专业只是一个切入点。之后的事情愈发重要。

一般来说,打磨自己某一方面的技能或学识,能更快的融入一个电子游戏制作团队中去。而产业链激流勇进的状态下,运气和实力一样重要。

十年游戏无情人,心态要爆炸

没有极大的勇气和积累,不要尝试全职的独立游戏制作。重点是不要全职,理由是据说九成九点独立游戏制作人都很苦逼,另外零点一成不苦逼的是因为他们在自己的头衔上“偷换概念”。这个说法略显夸张,但这就是影射一个存在的现象。

但这都是老生常谈。试错没什么大不了。有兴趣就大胆尝试。只是,游戏本身容易“上瘾”。

迷上氪金,或者肝,可能会一发不可收拾。此处省略几万字,只提一句:因为大学里沉迷游戏,最后挂科太多,拿不到学位的,不在少数。

发现一款好玩的游戏,说明游戏制作人跟你的品味很相似。你想自己设计一款吗?如果这个问题很难回答,那就把“游戏”二字换成房子、车子、美食,唯一的区别,可能是前者的心更大(吧)。

游戏夜读 | 这是一款情绪游戏

文/良宵听雨。授权“游戏夜读”发表。

游戏的设计与开发必然会有一个目的,但游戏本身却不一定非要有终点。

这个说法像极了巧妙的废话,实现起来并不难,《苹果奥德赛》就是这样一款游戏。

是独特固执的理念,还是哗众取宠的概念?

据独立制作人介绍,这款游戏旨在让玩家陷入某种情绪,而非获得分数或取得通关。并在版本更新中强调,“分数、时间的限制会让这款游戏失去灵魂”。它是一款没有目标只有情绪的游戏,它被称为“情绪游戏”。

尽管此前从未听过“情绪游戏”这一类别,但这个设定并不难接受。只是,对这一游戏形式并不清楚,甚至可以说对细节还一无所知。暂且各做猜想,比如,最令人动容和印象深刻的游戏元素有哪些呢?

答案肯定会几乎涵盖所有元素。影响力应该主要来自台词、画面和音乐,此外,一段剧情或故事也会让玩家情绪波动。

可以说,陷入某种情绪在游戏过程中是再正常不过的体验了。这样一来,所谓的“情绪游戏”很可能只是哗众取宠,一只真的“疯苹果”。

半成品的突发奇想

面对质疑,独立制作人表示理解,并解释说“情绪游戏”的概念并不是在“疯苹果”成形之前就设定好的,而是半成品形成后的一个突发奇想。

起初,因为能力和条件所限,所以制作人就没打算制作出一款精美的游戏,最初的想法是拥有一款自己设计和制作的小游戏。

所以,在打开游戏编辑器后,创建了一个世界和一个角色,这个角色就是那只苹果。后面的事情也不复杂,苹果有了游走在浩瀚宇宙中的要求,它换着肤色,哼着奇怪的歌。以上就是这个半成品的全部元素。

未来仍在脚下

意识流地设计后,试玩时,准确地说,应该是在测试时,由于体验到了观看《2001: A Space Odyssey》时的那种奇妙感受,随之有了情绪游戏的点子。

除了对游戏名称进行了修改,还作了上文所说的更新说明。至此,有关情绪游戏的故事算是有了一些眉目,是一种意识流的致敬,它是小游戏,但还够不上游戏。

新年快乐 :)

游戏夜读 | Two Sum问题的八个解

文/良宵听雨。授权“游戏夜读”发表。

打开LeetCode找到一个小游戏

\1. Two Sum

Easy

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

自助使用Python3款答题纸

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:

开始答题……其他略。题目中有两个假设:

1 有且仅有一个解;

2 同一个元素不能被使用两次。

尝试的5种方法,失败了4次

        # 方法1:循环遍历列表中的数,一个一个找
        # for i in nums:
        #     for j in nums:
        #         if nums.index(i) != nums.index(j):
        #             if (i+j)==target:
        #                 return [nums.index(i), nums.index(j)]
        # 上述方法1有个漏洞:当i=j,比如遇到[3,3],.index()的判断就不好用了

        
        # 方法2:基于方法1,循环遍历列表的索引,这样就避免数值相同的bug啦
        # for i in range(len(nums)):
        #     for j in range(len(nums)):
        #         if i != j:
        #             if nums[i] + nums[j] == target:
        #                 return [i, j]
        # 上述方法2虽然可行,但是Time Limit Exceeded,说明效率太低,被淘汰了
        
        
        # 方法3:根据题目中说的假设(恰有一个答案),直接匹配差值是否在列表中,并对相同值的情况做处理
        # for i in nums:
        #     if (target - i) in nums:
        #         if i == (target - i):
        #             return [nums.index(i), nums.index(i, nums.index(i)+1)]
        #         else:
        #             return [nums.index(i), nums.index(target-i)]
        # 上述方法3有漏洞:相同的值被取了两次实际却只有一个,遇到[3,2,4]就歇菜了,i=3没有两个3返回null
        
                
        # 方法4:基于方法3,加一个符合条件的数值数量的判断,弥补漏洞
        # for i in nums:
        #     if (target - i) in nums:
        #         if i == (target - i) and nums.count(i) > 1:
        #             return [nums.index(i), nums.index(i, nums.index(i)+1)]
        #         else:
        #             return [nums.index(i), nums.index(target-i)]
        # 上述方法4还是有漏洞,遇到[3,2,4]没有歇菜,但是返回了[0,0],判断条件没搞清楚逻辑,画NS图自救,
        # 发现是漏掉了i==(target-i) and .count(i)<1 这一类情况,应当continue,而不是直接进上述的else
        
        
        # 方法5:基于方法3和方法4,围绕不能复用的条件,进行两层判断:先挖坑,再网鱼,步骤有先后手
        for i in nums:
            if (target - i) in nums:
                if i == (target-i):
                    if nums.count(i) > 1:
                        return [nums.index(i), nums.index(i, nums.index(i)+1)]
                else:
                    return [nums.index(i), nums.index(target-i)]
        # 成功accepted了!
        # Runtime: 788 ms, faster than 35.47% of Python3 online submissions for Two Sum.
        # Memory Usage: 13.8 MB, less than 70.43% of Python3 online submissions for Two Sum.

上述方法小结

  1. 总体思路混乱,语无伦次,可悲。
  2. 冷静一下,算法的思路主要分两大类:
    2.1 直接查找计算法(找到一个i和一个j,判断相应和是否为target);
    2.2 间接查找问询法(找到一个i,再判断target与i的差值是否存在)。
  3. 再冷静一下,查找的思路主要分两大类:
    3.1 基于item
    3.2 基于index

综上,在已有的认知范围内,理论上有四个方法可以解决LeetCode这个“Two Sum”的问题,分别是:

(1) 基于item的直接查找计算法

        for i in nums:
            for j in nums:
                # find it!
                if (i+j)==target:
                    # maybe twice?
                    if i==j:
                        # more than 1 elements!
                        if nums.count(i)>1:
                            # don't forget find the 2nd one's index
                            return [nums.index(i), nums.index(i, nums.index(i)+1)]
                    # not twice
                    else:        
                        return [nums.index(i), nums.index(j)]

果然啊!成功!
Runtime: 4604 ms, faster than 25.25% of Python3 online submissions for Two Sum.
Memory Usage: 13.8 MB, less than 68.81% of Python3 online submissions for Two Sum.

(2) 基于index的直接查找计算法

        for i in range(len(nums)):
            for j in range(len(nums)):
                if (nums[i]+nums[j])==target:
                    if i==j:
                        if nums.count(nums[i])>1:
                            return [i, nums.index(nums[i], i+1)]
                    else:
                        return [i, j]

果然啊!成功!就是慢了点。
Runtime: 7688 ms, faster than 5.01% of Python3 online submissions for Two Sum.
Memory Usage: 13.8 MB, less than 73.03% of Python3 online submissions for Two Sum.

(3) 基于item的间接查找问询法

        for i in nums:
            if (target-i) in nums:
                if i == (target-i):
                    if nums.count(i)>1:
                        return [nums.index(i), nums.index(i, nums.index(i)+1)]
                else:
                    return [nums.index(i), nums.index(target-i)]

果然啊!成功!快了不少。
Runtime: 776 ms, faster than 37.75% of Python3 online submissions for Two Sum.
Memory Usage: 13.8 MB, less than 67.25% of Python3 online submissions for Two Sum.

(4) 基于index的间接查找问询法

        for i in range(len(nums)):
            if (target - nums[i]) in nums:
                if i==nums.index(target-nums[i]):
                    if nums.count(nums[i])>1:
                        return [i, nums.index(nums[i], i+1)]
                else:
                    return [i, nums.index(target-nums[i])]

果然啊!成功!保持在高水准。
Runtime: 788 ms, faster than 35.47% of Python3 online submissions for Two Sum.
Memory Usage: 13.7 MB, less than 85.58% of Python3 online submissions for Two Sum.

####做一个回顾

首先恭喜自己,顺利通关。分数还行,Top 65%的位置,770ms,13.8MB,拿到了一颗星。

上述的四个方法,不管是“一手抓一手再抓”,还是“一手抓一手在摸”,在具体比较的时候都是“凭空”的,没有放在一个篮子或者秤上进行操作,总而言之就是有不可控的黑洞。

字典dictionary是一个比较喜欢的篮子。此外,几年前看过一个跷跷板的方法,结合起来:

(5) 基于item的字典dict跷跷板

        dict = {}
        for i in nums:
            if i in dict.keys():
                if i == dict.get(i):
                    return [nums.index(i), nums.index(i, nums.index(i)+1)]
                else:
                    # follow the queue number
                    return [nums.index(dict.get(i)), nums.index(i)]
            else:
                dict.update({target-i: i})

厉害了!成功!
Runtime: 36 ms, faster than 94.69% of Python3 online submissions for Two Sum.
Memory Usage: 14.2 MB, less than 50.40% of Python3 online submissions for Two Sum.

(6) 基于index的字典dict跷跷板

        dict = {}
        for i in range(len(nums)):
            if nums[i] in dict.keys():
                # ensure index return by the same number
                if i == nums.index(dict.get(nums[i])):
                    return [i, nums.index(dict.get(nums[i]), i+1)]
                else:
                    # follow the queue number
                    return [nums.index(dict.get(nums[i])), i]
            else:
                dict.update({target-nums[i]: nums[i]})

厉害了!不如上面的简洁。
Runtime: 40 ms, faster than 87.10% of Python3 online submissions for Two Sum.
Memory Usage: 14.2 MB, less than 53.05% of Python3 online submissions for Two Sum.

对比一下,新的分数还行,Top 5%的位置,36ms,14.2MB。

####写在最后

最重要的测试集,用例,三个有代表性的列表,以及目标值:

[2, 7, 11, 15]
9
[3, 3]
6
[3, 2, 4]
6

第二波的对比第一波:排名从前63到了前5,耗时从776ms到36ms,内存从13.8MB到14.2MB。

最后的最后,剩下的几种解法呢?

简单来说,就是暴利查找的时候,第二层循环index下标从i+1开始啊!具体示例如下:

(7) 基于index的直接切片查找法

        for i in nums:
            for j in nums[nums.index(i):]:
                # find it!
                if (i+j)==target:
                    # maybe twice?
                    if i==j:
                        # more than 1 elements!
                        if nums.count(i)>1:
                            # don't forget find the 2nd one's index
                            return [nums.index(i), nums.index(i, nums.index(i)+1)]
                    # not twice
                    else:        
                        return [nums.index(i), nums.index(j)]

成功!比原来的速度略有提升。
Runtime: 3856 ms, faster than 26.13% of Python3 online submissions for Two Sum.
Memory Usage: 13.7 MB, less than 85.58% of Python3 online submissions for Two Sum.

(8) 基于index的间接切片问询法

        for i in range(len(nums)):
            # begin from i's index + 1, hope more and faster
            if (target - nums[i]) in nums[i+1:]:
                if i==nums.index(target-nums[i]):
                    if nums.count(nums[i])>1:
                        return [i, nums.index(nums[i], i+1)]
                else:
                    return [i, nums.index(target-nums[i])]

成功!但是速度并没有跷跷板的快。
Runtime: 836 ms, faster than 33.40% of Python3 online submissions for Two Sum.
Memory Usage: 13.8 MB, less than 66.48% of Python3 online submissions for Two Sum.

有几点需要说明:

  1. 忽略从i+1开始,是因为直接被[3,3]带歪思路了,看来用例有时候也是把双刃剑。得瑟啥?可悲。
  2. 第一次遇见跷跷板的时候,惊为天人,现在没那么惊吓了,还是赞叹。天外有天,山外有山。
  3. 原本以为加了i+1开始,找的越来越快,能跟跷跷板比一比。发现还是差了档次,应是dict的硬伤。
  4. 虽然说有8个解法,其实核心思想是这几个:暴力查找、差值问询、临时存取、缩减范围。
  5. 文中引用的数据应该不精准,看个定性就好。游戏也挺好玩的。

游戏夜读 | Scikit-learn的2018自述

文/良宵听雨。授权“游戏夜读”发表。

R和Python的交谊舞

曾几何时,数据分析入门的一大讨论就是R和Python的选择。

当统计学家连上了互联网的那刻起,这种选择一直就存在,只是主演们在换。

上一代的主角,一方是R和S。大家选择R是因为它是免费的解决方案,又能用,还有一批人维护更新,而且下载即可。概括起来,就是“开源大法好”。另一方是Matlab和Python。可能会有很多的异议,不过这里也只是举个见识范围内的例子,愿意无条件接受任何的反驳。近年,Python的排名越来越高。

站在2019年,R和Python主演的选择大戏有结局了吗?

一条蟒蛇跟一个字母的故事,编剧被寄了刀片,剧情搁浅。没有结局的原因很简单,因为两个都是开源的,所以“诸事不决,选开源”的策略失效了。那该如何有理有据地抨击一款正被广泛使用的工具呢?

请务必从用户需求下手。

那就聊一聊机器学习模块,算法,模型,策略,评估,可视化……那些跟人工智能有关的需求。

Scikit-learn的初心是…

这里应该回忆一遍Scikit-learn(sklearn)是如何成长为Python的机器学习库的,哪怕是最快速的带过:2007年开始,距离2018年已经过去11年。(其他的废话准备另写一篇《Scikit-learn迎来0.21之前》。)

Python在数据科学领域的快速发展,归功于那些频繁提交commit的家伙们。

但夜以日继,不辞辛苦的,还有很多人,劲敌永远存在。翻开sklearn的文档,会发现除了主页常设的分类、回归、聚类、降维、模型选择、数据处理这六大主题之外,还有一个有关这个项目本身的Roadmap。

如果没有人关心这个项目的里程碑,会怎么样?

过去的11年里,机器学习的世界变化很多,但影响最微妙,可能也是“最致命”的,是开源贡献者的身份产生了变化。跟十年前那会儿很不同。

Statement of purpose: Scikit-learn in 2018

  • A more subtle change over the last decade is that, due to changing interests in ML, PhD students in machine learning are more likely to contribute to PyTorch, Dask, etc. than to Scikit-learn, so our contributor pool is very different to a decade ago.

在这最新一份的《Scikit-learn项目目标自述2018》里,还可以看到sklearn不变的初心:数据处理和机器学习的经典工具集合。

如今,机器学习博士生们“更乐意去为PyTorch、Dask等添砖加瓦”。sklearn也更开放,会提供更多的接口便利,也不排斥互通。

写在文档里的可能是实现不了的诺言,或者谎言。关于这一点疑虑,sklearn的开发者这样宣言:资源有限,所以列清单不等于许下承诺,而是指引我们前行的航标,也是我们急需帮助的不足之处。

争吵不是真相,真理落在实处

为什么不是Scikit了呢?又为什么是PyTorch、Dask呢?时代变迁,新的角色不断涌现,又会有一大波选择的大剧等待上演。选择不尽,争吵不休。

算法层出不穷,包或者模块的名字也在变化,甚至框架也可以有很多种选择,这个世界正在对数据科学领域开放大量的人力资源和发展机会。

scikit-learn在2007年问世时,NumPy、SciPy和matplotlib是不是在颤抖?有机会真该去看看它们那些年的项目文档,可能有精彩的故事。

选择开源,就注定不能一劳永逸。而拒绝开源,只会被潮水淹没。Scikit-learn的2018自述,讲述了开源的波折和信念,言辞恳切,不失风度。

游戏夜读 | Scikit-learn迎来0.21之前

文/良宵听雨。授权“游戏夜读”发表。

Scikit-learn(sklearn)是Python的机器学习库。它从2007年开始,距今2019年,已经服务12年。

那年Python正好18岁

如果说机器学习(ML)的研究热点变化,影响了sklearn的兴衰,那么有关Python的变化,与有存亡焉。

Python作为一门编程语言,诞生至今,一直在蓬勃发展,具有很强的生命力。其公认的是创始人是Guido,荷兰人。他在1989年圣诞夜的闲暇中,决定开发Python。有关命名也是一段趣事,这里不谈。

由于创始人独特的理念,以及开源后各地开发者的热情,随后的二十多年间,Python不断发展。Python 2于2000年10月16日发布,稳定版本是Python 2.7。Python 3于2008年12月3日发布,不完全兼容Python 2。

© 2007 - 2019, scikit-learn developers (BSD License).

Python诞生后的第18个年头,2007年,scikit-learn诞生了。故事就从这里开始。

与Python 2相知相守的12年

sklearn初期的版本由少数几位开发者维护,直到2010年后,开发者的名单慢慢变长,文档也越来越规范,更新的内容也都记录在册。那时Python 3小荷才露尖尖角,很多库都还是基于Python 2.x。

before August 26, 2010 (Earlier versions)

  • Earlier versions included contributions by Fred Mailhot, David Cooke, David Huard, Dave Morrill, Ed Schofield, Travis Oliphant, Pearu Peterson.

sklearn第一次开始支持Python3是在0.8版本,那是2011年5月。那时的sklearn正在快速补充数据科学工具箱内的物件:各种函数、模型,以及随之而来的各类bug。版本更新里,已经去掉了开发者的名单。

May 11, 2011 (Version 0.8)

开始拥抱Python 3之后,是sklearn的2与3共存时代。同时,也意味着sklearn开始了告别Python 2之旅。比如,发布于2012年1月的0.10版本,sklearn宣告Python 2.5被淘汰,支持从2.6开始。

January 11, 2012 (Version 0.10)

  • Python 2.5 compatibility was dropped; the minimum Python version needed to use scikit-learn is now 2.6.

2018年3月,创始人Guido在邮件列表上宣布Python 2.7将于2020年1月1日终止支持。2018年7月,创始人Guido发邮件表示退出决策层。作为一个发展中的Python库,sklearn也要做出一些选择。

0.20宣告决心:准备不再支持Python 2.7和3.4

在2018年9月25日发布的0.20版本中,sklearn做出了声明:将在0.21正式抛弃Python 2.7 和 Python 3.4。

作为一个从Python 2走出来的Python库,这样的反应不算迟钝。这一切要归功于辛勤的开发者们。

September 25, 2018 (Version 0.20.0)

  • Warning: Version 0.20 is the last version of scikit-learn to support Python 2.7 and Python 3.4. Scikit-learn 0.21 will require Python 3.5 or higher.

0.21正式分手,携手Python 3.5继续前行

终于,2019年5月,sklearn迎来了0.21版本,这应是一个接轨了Python未来的版本,并且从3.5开始支持。

从更新的内容来看,库没有大地震,包有众多更新,模块有新功能。并在其后陆续更新了几个小版本,修复了不少内容。有兴趣的,可以就0.21这个版本的更新内容做一个了解,也是个了解sklearn的好机会。

1赞

游戏夜读 | Scikit-learn迎来0.21版本

文/良宵听雨。授权“游戏夜读”发表。

2019年5月,Scikit-learn(sklearn)迎来了历史性的0.21版本,不再支持Python 2.7和3.4,仅支持Python 3.5及后续版本。此前,2018年9月0.20版本发布时,已对此做出了提前说明。

sklearn版本更新内容的六大分类

在了解这一次的版本更新内容前,先熟悉一下sklearn对更新内容的分类习惯。

sklearn将更新内容划分成六个大类,由四种颜色标识。分别是:

  1. 绿色,重大新功能 Major Feature;
  2. 绿色,新功能 Feature;
  3. 蓝色,效率提高 Efficiency;
  4. 蓝色,性能增强 Enhancement;
  5. 红色,缺陷修复 Fix;
  6. 橙色,接口改动 API Change。

在0.21版本发布后,陆续更新了几个以缺陷修复为主的小版本。考虑到0.21版本的更新内容不算少,所以,挑选绿色标识的内容,主要关注一下新增的功能。

0.21的绿色功能更新内容摘要

一共有24个绿色标签的功能性改动,涉及到了14个类别。其中,13类是具体模块,剩下的1类,是牵涉多个模块的基础性改动。

sklearn.cluster 新增了1项
  • 一个聚类算法 cluster.OPTICS,比cluster.DBSCAN更方便调参。
sklearn.ensemble 新增了2项
  • 两个实验性质的梯度下降树GBT,分别是ensemble.HistGradientBoostingClassifier 和 ensemble.HistGradientBoostingRegressor,据说是受到了LightGBM的启发。当样本数量大于数万个时,会比ensemble.GradientBoostingRegressor 和 ensemble.GradientBoostingClassifier要快。但因为是实验性质的,功能还不健全,sklearn也可能随时修改这一项更新的内容,对结果不做一致性的保证。
  • 添加了ensemble.VotingRegressor,它为回归问题提供了等效的ensemble.VotingClassifier。
sklearn.impute 新增了2项
  • 添加了缺失值处理的新方法 impute.IterativeImputer,实验性质。
  • impute.SimpleImputer 和 impute.IterativeImputer 新增了一个参数 “add_indicator”,实现了impute.MissingIndicator的转换输出。这样一来,预测模型也可以解释缺失值了。
sklearn.inspection 新增了1项
  • 号外!号外!现在凡是有 “predict_proba”方法的回归或者分类器都支持部分依赖图(inspection.plot_partial_dependence)啦!
sklearn.isotonic 新增了1项
  • 允许在 isotonic.IsotonicRegression 处理不同的数据类型了,比如:float32。
sklearn.linear_model 新增了2项
  • 通过选择“saga”解算器,linear_model.LogisticRegression 和 linear_model.LogisticRegressionCV 现在支持Elastic-Net惩罚约束了。
  • 添加了 linear_model.lars_path 的加强版 linear_model.lars_path_gram,可以直接不提供 X 和 y 就开搞。
sklearn.metrics 新增了4项
  • 为单输出回归提供了 metrics.max_error 指标,以及相应的 “max_error”得分参数。
  • 可以计算每个类别的混淆矩阵了!新增的 metrics.multilabel_confusion_matrix 有助于调参。
  • 新增的 metrics.jaccard_score 可以用来计算 Jaccard系数,操作方式跟 metrics.f1_score 差不多。
  • 之前“Haversine距离”可以通过最近邻计算得到,现在新增了metrics.pairwise.haversine_distances ,可以通过 metrics.pairwise_distances 设置“metric=‘pairwise’”实现。
sklearn.model_selection 新增了1项
  • 新增了两个类,分别是:GridSearchCV, RandomizedSearchCV。现在允许“refit=callable”来加强查找的可伸缩性,具体可以参考《模型复杂度和交叉验证分数的平衡之道》。
sklearn.neighbors 新增了1项
  • 添加了 neighbors.NeighborhoodComponentsAnalysis,它实现了近领成分分析算法。
sklearn.pipeline 新增了2项
  • pipeline.Pipeline 现在可以使用索引切片了!比如:my_pipleline[0:-1]。提取的子序列可以作为另一个Pipeline实例。还可以直接索引管道的特定步骤,跟通过“named_steps”一样的效果,但更方便。比如:my_pipeline[‘svc’]。
  • 为pipeline.Pipeline,compose.ColumnTransformer 和 pipeline.FeatureUnion以及相应的“make_” 添加了可选参数“verbose”,用来显示每个步骤的进度和时间。
sklearn.preprocessing 新增了1项
  • preprocessing.OneHotEncoder 现在支持通过“drop”删除某个类别的特征。这在存在共线性的时候比较实用,例如:将结果数据输入神经网络或非规则化回归时。
sklearn.tree 新增了3项
  • 决策树更容易画出来了!现在可以基于“matplotlib”,通过 tree.plot_tree作图,不再依赖难安装的“dot”库了。
  • 现在可以通过 tree.export_text 导出阅读性良好的“文本格式”决策树了。
  • tree.BaseDecisionTree 新增了 get_n_leaves() 和 get_depth() 两个方法。重点是:基于这个基础算法的那些模型都同步更新了这两个方法。比如:tree.DecisionTreeClassifier,tree.DecisionTreeRegressor,tree.ExtraTreeClassifier,tree.ExtraTreeRegressor。
sklearn.utils 新增了1项
  • utils.resample 现在可以通过新增的“stratify”参数,设置根据分布分层取样。
涉及多个模块的基础更新,新增有2项
  • 完全重写了“_repr_()”方法,现在用的是Python标准库的打印方式,很优雅。这个方法用在调用 print(estimator) 的时候。但想改的话也可以,通过修改 sklearn.set_config 的 “print_changed_only”参数。
  • 引入了Estimator Tags 估算器标签,字典形式存储,通过调用“_get_tags()”方法获取。像sklearn.utils.estimator_checks.check_estimator 可以使用这些标签决定运行哪些测试以及输入哪些数据是合适的。标签可以依赖于估算器的参数设置,甚至系统控制,一般只在运行的时候才真正生效。标签作为注释,可以标识具体某个估算器的功能、数据要求、支持的输出类型、支持的方法等信息。

以上就是sklearn的0.21版本绿色功能性改动部分的摘要,更详细准确的内容就必须前往官方文档查阅了。

游戏夜读 | 写游戏用什么语言?

文/良宵听雨。授权“游戏夜读”发表。

写几句题记

这个标题如果用英文表达,可能更贴切,比如:Beginning game programming,What language should I use? 用简洁的中文似乎表达不出重点。

之所以用了“写游戏”,是为了照顾“语言”,更是考虑到大部分的问题需求确实是为了“写”。而“做”游戏的范围又太大。

话题范围足够小的时候,即使表述的不准确,也并不影响理解力。现在话题是较为明确的,也很常见,场景比如:入门、新手、咨询,搭配游戏名称或爱好。

如果对这个话题有兴趣,建议在中文搜索之上,再辅以英文。

一个方面:如何做选择?

先把这个问题,看成是一个悬而未决的决策。那下面就简单介绍一下策略:如何做出这个决定。最容易的选择,就是盯着评价指标勾勾叉叉。

那么选择某种语言的理由可以有哪些呢?

有三个主要的方面:知名度,热度,上手难易程度。先说前两个,其中知名度高的,一般是历史悠久的;然后热度高的,一般是当下的主流;两者有联系也有区别,两方面都占的,基本上就可以锁定价值了。

关于“上手难易程度”,也可以简单说成“门槛”。这可能是讨论最多,主观意见最容易发酵的危险地带。也是可以细分理由的。

门槛和“普适性”大体上是负相关的,越大众的门槛越低。门槛和“专业性”一般是正相关的,越专业门槛越高,即使学习曲线一开始平缓,后面肯定会陡峭,否则体现不了“专业度”。这里面内容庞杂,不建议深究。

直接对比“知名度”和“热度”,再权衡需求即可。

说到门槛本身的话,比方说:前置条件、知识储备,硬件条件,软件条件等。其中软件条件需要特别注意。大部分的讨论和建议就集中于此。

想要精打细算的,具体要考虑:对某种语言的好感度,是否能适应现有的集成环境,对编辑器的个人爱好能否实现等等。几番了解后,就大致有了数。

另一方面:用哪些语言?

要把选择落在实处,即是看中了某一个语言。如此,才算问题得到了解决。

落到“游戏”上面。子曰:“贤哉,回也!一箪食,一瓢饮,在陋巷,人不堪其忧,回也不改其乐。”那么做游戏的也有类似。

自然语言。一支笔、一页纸、一粒骰子,做个简单的桌游应该不成问题了。

计算机语言。命令行式的,通过一个黑色或者蓝色的终端,跟电脑进行互动,进行文字、图片的交流,比如:文字游戏,冒险类的,选择类的。

不同的编程形式。大多数的电子游戏都是这样诞生的,大多数的问题正是问这些游戏背后的语言。比如:面向对象的,结构式的,过程式的,元素式的。

游戏引擎,准现成的解决方案。直接去看专门描述引擎效果的广告文案吧。

66666,Mark

1赞

(^▽^)很开心得到关注哦!

游戏夜读 | 工具游戏的辉煌

有网络之前,故事很精彩。

单机游戏成就了一个人的狂欢,街机更是让人战斗力十足,只是这些还不是普通人玩得起。

网络的普及可能从有线电话开始,随后是智能手机爆发,再后来是无线网络的全覆盖……

然而,通网只是开始。

因为一开始的网络并不快,于是,局域网联机成就了你我他的恩怨情仇,网吧成就了逃课。

等到全民、天天这些系列游戏流行的时候,中国的游戏行业迎来了属于自己的高光时刻:移动端游戏的市场一片热闹!

都说外行看热闹,内行看门道。千禧年一代所经历的正是人类历史上的移动游戏第一次大爆发!

大量的手机使用者接入了网络,每个人都有属于自己的空闲时刻,不论是按天算的,还是按分钟算的,大量的时间!

大把时光除了学习、工作、发呆之外,还需要娱乐!他们需要娱乐!娱乐!谁会排斥“单纯的快乐和幸福感”呢?电子游戏可谓是一剂猛药。

这一时期的游戏内容不如游戏渠道重要,因为大把的人从来都没有玩过游戏,能玩上就很好!要是能玩上全民都在玩的,大家天天玩的,更好!

不是说这一时期没有重内容的游戏。商业游戏的制作历来都是设计驱动和商业数据驱动并行。只是,21世纪初的这二十年,有大量的游戏是作为流量的变现工具而存在。

流量、眼球,自然是这一时期的宝贵财富,作为变现工具之一的游戏,也可以说是“工具游戏”!但这并非是游戏唯一应有的角色和立场。

商场变化多端,时间来到2020年,已经能明显感觉到电子游戏产品内容创造上的迸发了!

从游戏行业的发展来看也应是如此。

回想一下,从街机,到家用游戏机,再到掌机、移动手机,再到触屏操作的各类电子产品,游戏机制的创新并不容易,但随着形式的变化,游戏规则可以快速复制和微创新。至于游戏内容,则是要跟着大家的认知和生活水平一起发展。

所谓一方水土,养一方人。游戏也是要耕耘。

文/良宵听雨。授权“游戏夜读”发表。

游戏夜读 | 关于构图的困难

构图,这个词通常频繁出现在美术工作者和摄影爱好者的口中。通常意义上,构图是《影视听语言》中的重要组成部分。那在游戏中呢?电子游戏业发端以来,视频游戏就应运而生——一种集结了众多艺术表现形式的“游戏化”现象。

一个游戏制作团队中,美术组应该是最关心“构图”的了。而上线后的视觉效果,将直接影响整个团队的工作业绩。

构图是有章法的,有标准,有范式,但要用到位却不容易。关键在于守中有变,先学会如何观察变化,再通过模仿、练习,最终懂得如何创造变化。这样的能力,不仅限于构图,在用色上也差不多,只是用色还讲究主题、统一。

倘使仅仅抄袭古人,移东搬西,不能变化,怎能创得出社会主义新风格出来?——《关于构图问题》潘天寿

构图也可以讲究统一,但容易造成视觉疲劳。这样说起来,眼睛如此,耳朵也是,值此盛夏,蛙叫、虫鸣伴着入睡。清晨的鸟叫倒是丰富多彩,令人神清气爽,婉转丰富的形式让内容更出色。这么些好处,当用,可又不生搬硬套,难。

克服困难,即是成长。构图的困难主要体现在两个方面。一方面是师徒关系,一方面是分析方法。

不用细说,由于学徒人数的大曝光,中国传统的师徒关系已经不能满足需要,随之而来的是师生关系,现在又有了同学关系的趋势,比方说视频弹幕伴着培训、写作业等等。“师父领进门,修行在个人”,这句话的后半句是越来越地道。

分析方法的确是很关键的,自我修行的一方面就是琢磨这个,并且略有小成也是因为有所悟道。容易卡壳的地方通常是看得到画面中的器物,却看不见画面中的气势。而所谓构图,就是依着气势构建。气势用白话讲,就是组织规律。

都说一图胜千言,关于构图的研究,这方面的知识还很浅薄。关于构图的困难,几句粗语感悟,仅一家之言,见笑。

文/良宵听雨。授权“游戏夜读”发表。


突然发现论坛里面讲“自己研发的第一款小游戏”、“软著申请注意事项”这一类东东,还是很实用的……希望自己在不久的将来也可以加入到大家的奋斗当中!!!

游戏夜读 | 跟风说一说爬虫

爬虫,原本是一类动物的指代。但对熟悉计算机网络的人来说,说起爬虫,第一个想到的就是网络数据的采集行为。

计算机网络不是直观的事物,它不像自行车一样一目了然。对于自行车,我们不仅熟悉车把、链条、坐垫、脚踏板、轮胎、轴承等配件,也能亲身体验速度、惯性、平衡的物理奥妙。但计算机网络不同,除了电缆、光纤,其他的都神秘。

想要化身电流的一份子:电子。体验一趟趟云霄飞车、电击、拥挤、千锤百炼……不妨想象一下超大型过山车的感受。

网络不仅是一种技术,更是我们用来存储、获取、交流信息的工具。其中跟我们关心的信息,关系最紧密的一个概念,可能非“网络协议”莫属了。网络协议本身的内容挺复杂,也有不少的标准,实际操作中一般都会提到:网络协议三要素。

是哪三要素呢?常见的说法是,语法,语义,时序。语法会定义计算机网络语言,基本上是一些数据符号的事情,通常被解释为“怎么讲”。语义,就跟我们所理解的信息内容非常接近了,基本上是讲怎么把那些干涩的数据符号吃透:弄明白今天的一个字母代表的是苹果,到了明天这个字母就是代表香蕉了,诸如此类,通常被解释成“讲什么”。时序,有时也全称为时序规则,主要是时间上的考量和分析,一般不直接挂钩被传递的信息内容。

说到这里,我们日常在计算机网络上搜索、讨论、发文件等等,除了网速快慢,主要涉及语法、语义。话说回来,爬虫就是模仿人类上网冲浪的行为,可以把一个个爬虫程序理解成是一个个网络机器人,由此,爬虫工程师也就不那么神秘了。

文/良宵听雨。授权“游戏夜读”发表。

游戏夜读 | 数据整理的难题?

文/良宵听雨。授权“游戏夜读”发表。

数据处理涉及面比较广,数据清理是一些手段和步骤,整理范围相对更小。基于这个认识,开始聊下面的。

一个模糊的提问
整理数据的时候遇到困难,往往是针对现有的数据结构不满。比如常见的三种期望:每种统计量是一列,每次观测值是一行,每一类实验数据单独一个表。

实际遇到的数据,往往不够理想。

这个时候能力不足无法解决,或者虽然有了笨办法,但又想知道更高效、实用的,怎么办呢?

肯定是搜索和提问。

难就难在不知道怎么描述。可能七七八八说了个大概,总体上还是一个模糊的提问。

行列变换,reshape(重塑)
常见的用词是“行列变换”。

说起行列变换,可能说中了大部分的数据整理问题!只是因为行列变换这四个字,模模糊糊地描述出了可能的解决办法。

但实际上,这个数据整理的难题,跟线性方程组、矩阵、行列式的初等变换不太一样。

另一个说到点子上的词是 reshape 重组。

说起reshape,可能第一个反应是 numpy.reshape ,其常见的应用如下所示了。但这里要说的不是这个。而是pandas官方文档里的图例。对应的操作,在R语言也比较成熟。

a = np.arange(6).reshape((3, 2))
a
array([[0, 1],
[2, 3],
[4, 5]])
数据整理的难题:reshape 重组
数据重组(reshape)就是对数据的统计结构进行变换,枚举的变成计数的,分类的改成变量。

部分效果跟Excel透视表是差不多的。这类问题在pandas的官方文档里也有专题,还有有一个统称,叫“数据重塑和透视表”。

英文是 Reshaping and Pivot Tables。一共介绍了重塑数据框的三大类方法:透视pivot,堆叠stack和平铺unstack,熔化melt。

首先是透视(pivot)。透视是指小而美的个性化重组。需要提前设定好需要的横向标签index、纵向标签column、被观察的数据value。

Reshaping by pivoting DataFrame objects
然后是堆叠(stack)和平铺(unstack)。堆叠是“横向变成纵向标签”,往垂直方向堆叠。平铺是“纵向标签变成横向”,往水平方向平铺。

Reshaping by stacking and unstacking -1
堆叠和平铺都是指简单粗暴的索引重组。只需要执行命令即可,优点是“矫揉造作”:伸缩自如,循环往复。

Reshaping by stacking and unstacking -2.1
其中,平铺unstack可以指定把现有的哪一个层级拉出来溜溜,只需要通过一个参数确定。默认情况下,就是对最末尾的那个索引下手。

Reshaping by stacking and unstacking -2.2
Reshaping by stacking and unstacking -2.3
最后是熔化(melt)。先熔化(melt)已待利用。操作也非常简单粗暴,就是完全打散,退化成“键值对”形式的重组。

兼具解释性强和便利性的优点。解释性强指的是能直白感受到信息的完全保留。便利性体现在保留了拒绝打散的权力。

Reshaping by Melt
数据整理的经典论文《Tidy Data》。
绝大部分的R使用者,大部分的数据处理工作者,应该都有机会接触到这篇论文。可能是直接看论文中的例子,也可能是通过转了几手的笔记间接习得。如果早些年阅读过这篇论文,那在提问的时候,可能带上一些模糊的印象。

但如果没有这些储备的知识呢?当遇到此类数据整理的问题时,该如何表达自我?该如何描述问题?一个实用的提问方法是:找到一个相对活跃的论坛,然后把具体的现状、期待的状态摆出来。

有不少的教材、笔记,是翻译过来的。早前还出现过“数据整容”这样词,现在几乎搜不到了。

这篇论文现在是开放下载的。

Authors: Hadley Wickham
Title: Tidy Data
Abstract: A huge amount of effort is spent cleaning data to get it ready for analysis, but there has been little research on how to make data cleaning as easy and effective as possible. This paper tackles a small, but important, component of data cleaning: data tidying. Tidy datasets are easy to manipulate, model and visualize, and have a specific structure: each variable is a column, each observation is a row, and each type of observational unit is a table. This framework makes it easy to tidy messy datasets because only a small set of tools are needed to deal with a wide range of un-tidy datasets. This structure also makes it easier to develop tidy tools for data analysis, tools that both input and output tidy datasets. The advantages of a consistent data structure and matching tools are demonstrated with a case study free from mundane data manipulation chores.
Submitted: 2013-02-20. Published: 2014-09-12.
https://www.jstatsoft.org/article/view/v059i10