跳转到帖子

搜索论坛

显示结果为标签'python'、'数据'、'语言'、'NumPy'、'ipython'、'shell'或'科学家'。

  • 用标签来搜索

    用逗号分隔标签类型
  • 用作者来搜索

内容类型


论坛

  • 漏洞与黑客攻击防御安全领域
    • 黑客攻防业务合作
    • 世界黑客新闻动态
    • WEB和服务器安全漏洞
    • CHT漏洞数据库
    • Linux Kali高级学习教程
    • CTF&密码学与社会工程
    • 木马病毒分析
    • 黑客世界会员中心
  • 问题讨论中心
    • 问答中心
    • 交流中心
  • 编程开发
    • 各种编程技术
    • ios /安卓开发
  • CHT官方团队介绍及比赛制度
    • CTF攻防系统[供会员使用]
    • 积分商场
    • 积分跳马系统
    • 积分统计系统

产品组

  • Hacker attack and defense security hardware series
  • Internet Security Book Recommendations

博客

没有结果。

没有结果。

类别

  • Hacker Attack and Defense & Network Security Videos

查找结果在…

查找包含的结果…


创建日期

  • 开始

    结束


最后更新

  • 开始

    结束


按数量过滤…

注册日期

  • 开始

    结束


用户组


About Me

找到14个结果

  1. 我们了解什么叫大数据分析么? 麦肯锡给大数据定义: “一种规模大到在获取、存储、管理、分析方面大大超出了传统数据库软件工具能力范围的数据集合,具有海量的数据规模、快速的数据流转、多样的数据类型和价值密度低四大特征。“ 基于我对以上定义的理解,我总结的大数据分析就是,将获取的数据,打通,整合,找寻规律,立即得出决策信息。 数据获取 我总结的数据源可分类三类: (1)一方数据:用户事实数据 例如用户在某金融机构购买的理财产品,时间,哪个出单口,姓名,电话等,或者运营数据,例如某互联金融app,用户操作行为数据 (3)三方数据:行业数据,也叫公开数据 例如行协的数据,或者互联网行为数据,例如某互联网公司用户在此网站的行为数据,或者嵌入sdk的app后我们能采集到的安装活跃列表,以及可采集到线下数据。 打通:其实就是利用关键点的采集整合一二三方数据。例如我们可以通过手机号将一方和三方数据整合,或者利用cookie,或者imei号等将二方、三方数据整合。但是由于现在监管制度对手机号敏感数据的控制,以及互联网和移动端数据的跨平台打通技术难点,我们现实的匹配率很低,例如一方和三方的数据匹配达到20%其实就算比较不错的情况,当然运营商数据除外。 找寻规律:目标就是数据清理,从非结构化数据变成结构化数据,以便统计,数据探索,找寻规律,形成数据分析报告观点。本文将会在第三部分阐述。 立即决策:将数据分析报告中的观点系统化或产品化,目前而言,大部分公司还是会依靠人工决策。 为什么需要大数据分析?看上去大数据分析似乎按照这些步骤来,但是从第一步的数据源来说,其实已经反应了大数据的特点,就是杂乱无章,那么怎么从这些数据找寻规律,分析的内容和目标是否对应上,似乎就是我们需要大数据分析的理由 现在,大数据的分析通常采用的数据报表来反映企业运营状况,同时,对于热点,人群分析,我们看到的统计值,目标核心都是用数据分析报告提炼的观点来指导运营,那么问题来了,怎么用数据分析来指导数据决策呢? 数据分析的报告思路(本文从移动端的角度进行切入) 基于我对数据分析的理解,我将数据报告会分成三大类:市场分析、运营分析、用户行为分析。 市场分析 由于市场分析一般而言是定性、定量分析,最近热播剧《我的前半生》贺函和唐晶的职业就是来去咨询公司的一般会以访谈、问卷调查来一份市场分析报告去告诉客户他们的市场占有量,消费者观点等。 这里,我们以移动互联网数据的市场分析为例,通常来说,数据源是公开数据,或者在第三方数据。正如我们所讲,将sdk嵌入开发者应用,就可以收集到安装以及使用列表,那么开发者使用的sdk越多,我们能收集的数据源也越多,这样就可以形成安装app排名,使用app排名,这里面所说的覆盖率、活跃率也是这个意思,例如:即此款应用安装量、使用量在整体金融类的安装量、使用量占比。 同时,根据市场的走势图,我们能发现潜在的竞争对手,例如:我们能看出下图中的工商银行由于手机属于高覆盖高活跃组,即安装xxapp活跃人群也是最高的,因此,无疑xx银行是所有银行组潜在竞争对手。需要更加注意他们的市场策略 运营分析 移动互联网提出的方法论:3A3R,笔者之前在做咨询的时候,此方法论也可以将网站分析套用,总结来说3A3R就是: 感知 → 获取 → 活跃 → 获取 → 营收 → 传播 → 感知 这里需要注明下,运营分析只是一个公司的baseline,让产品经理,运营人员,市场人员根据自己本公司的数据参考做出合理的决定,同时,运营的数据只是参考或者叫警示,若要具体,需要特定细节的分析,例如是否app改版,怎么改?需要增加哪家渠道合作? (1)Awareness 感知 (2)Acquisition 获客 目的1:衡量第一步提供的数据是否准确,即是否渠道作弊 目的2:判断渠道是否好坏 目的3:判断营销活动是否有效 例如下图中,我们发现4成用户是搜索流量较上个月增加了6%,是不是我们需要增加和sem的合作呢?而在媒体引荐渠道中,我们通过渠道衡量客户转化率,点击-用户激活的,激活的注册转化,可否重点对某应用商店增加合作 (3)Activities 活跃 获客后,我们想看看我们的新增、活跃用户的表现情况,那么就到了第三步 活跃,其实就是为产品经理改版app或者页面提供数据支持 活跃分析可参考以下三个步骤: 第一:从页面浏览次数,独立访问人数,来圈定主要页面分析。 例如某款app首页是pv,uv最高,我们会重点分析首页。 第二:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 第三:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 (4)Retention留存分析& Revenue & Refer 这几个实际上在企业运用的并不多,这里简要说明下。 ① Retention 用户积累到一定数量后,我们想看下用户粘性,那么我们就来到retention,一般是衡量活动效果时候运用的比较多,来看此次活动过后,是否用户依旧会使用我们的app,但是由于金融app属性不会像游戏应用每天进行访问,因此Retention 在实际应用中不会太多,下面的例子是个展示,不做赘述 ② Revenue 这些留下来的客户给公司贡献多少现金呢?会看收入步骤, 一般公司不会将现金流数据放入在统计平台中,但是我们需要提出用户贡献的流水金额数据供我们使用,便于人群划分,例如下面简要分析: Refer 传播: 用户分析 若说大数据分析的核心,其实就是在于用户分析,正如我们前面所讲,用户分析的步骤流程如下: 即在力所能及的搜集数据范围内,打通数据,客户用户,精准营销。 第一,我们可以筛选的条件列表,我们可以通过应用条件,位置,标签条件将数据整合,整合的目的就是刻画客户,定出营销策略。 例如:我们想筛选金融客户(应用条件筛选),出现在五星级酒店(位置条件),且为母婴人群(标签) 但是需要注意的是,条件越多,用户轮廓越清晰,人群会越少。 第二,根据筛选的人群,我们将线上/线上统计化,或者建模多维度分析。 例如,我们根据筛选的人群,发现男性多于女性,苹果手机属性最高,常手机工具使用,那么我们可以将这部分目标人群用增加手机工具合作、或者和苹果合作获客或者促活。 第三,整合以上数据分析,形成人群画像。 结束语 这篇文章基于我多年数据分析的经验,总结的一体化数据分析框架,其实就是简单介绍下数据分析能分析能落地的几点。当然,这里面需要大量的数据清洗工作,以及对行业的认知,此篇只是从数据分析角度的概要,内容上的细化,其实可以单拿出来细细分析,尤其用户画像那章节。 我们了解什么叫大数据分析么? 麦肯锡给大数据定义: “一种规模大到在获取、存储、管理、分析方面大大超出了传统数据库软件工具能力范围的数据集合,具有海量的数据规模、快速的数据流转、多样的数据类型和价值密度低四大特征。“ 基于我对以上定义的理解,我总结的大数据分析就是,将获取的数据,打通,整合,找寻规律,立即得出决策信息。 数据获取 我总结的数据源可分类三类: (1)一方数据:用户事实数据 例如用户在某金融机构购买的理财产品,时间,哪个出单口,姓名,电话等,或者运营数据,例如某互联金融app,用户操作行为数据 (3)三方数据:行业数据,也叫公开数据 例如行协的数据,或者互联网行为数据,例如某互联网公司用户在此网站的行为数据,或者嵌入sdk的app后我们能采集到的安装活跃列表,以及可采集到线下数据。 打通:其实就是利用关键点的采集整合一二三方数据。例如我们可以通过手机号将一方和三方数据整合,或者利用cookie,或者imei号等将二方、三方数据整合。但是由于现在监管制度对手机号敏感数据的控制,以及互联网和移动端数据的跨平台打通技术难点,我们现实的匹配率很低,例如一方和三方的数据匹配达到20%其实就算比较不错的情况,当然运营商数据除外。 找寻规律:目标就是数据清理,从非结构化数据变成结构化数据,以便统计,数据探索,找寻规律,形成数据分析报告观点。本文将会在第三部分阐述。 立即决策:将数据分析报告中的观点系统化或产品化,目前而言,大部分公司还是会依靠人工决策。 为什么需要大数据分析?看上去大数据分析似乎按照这些步骤来,但是从第一步的数据源来说,其实已经反应了大数据的特点,就是杂乱无章,那么怎么从这些数据找寻规律,分析的内容和目标是否对应上,似乎就是我们需要大数据分析的理由 现在,大数据的分析通常采用的数据报表来反映企业运营状况,同时,对于热点,人群分析,我们看到的统计值,目标核心都是用数据分析报告提炼的观点来指导运营,那么问题来了,怎么用数据分析来指导数据决策呢? 数据分析的报告思路(本文从移动端的角度进行切入) 基于我对数据分析的理解,我将数据报告会分成三大类:市场分析、运营分析、用户行为分析。 市场分析 由于市场分析一般而言是定性、定量分析,最近热播剧《我的前半生》贺函和唐晶的职业就是来去咨询公司的一般会以访谈、问卷调查来一份市场分析报告去告诉客户他们的市场占有量,消费者观点等。 这里,我们以移动互联网数据的市场分析为例,通常来说,数据源是公开数据,或者在第三方数据。正如我们所讲,将sdk嵌入开发者应用,就可以收集到安装以及使用列表,那么开发者使用的sdk越多,我们能收集的数据源也越多,这样就可以形成安装app排名,使用app排名,这里面所说的覆盖率、活跃率也是这个意思,例如:即此款应用安装量、使用量在整体金融类的安装量、使用量占比。 同时,根据市场的走势图,我们能发现潜在的竞争对手,例如:我们能看出下图中的工商银行由于手机属于高覆盖高活跃组,即安装xxapp活跃人群也是最高的,因此,无疑xx银行是所有银行组潜在竞争对手。需要更加注意他们的市场策略 运营分析 移动互联网提出的方法论:3A3R,笔者之前在做咨询的时候,此方法论也可以将网站分析套用,总结来说3A3R就是: 感知 → 获取 → 活跃 → 获取 → 营收 → 传播 → 感知 这里需要注明下,运营分析只是一个公司的baseline,让产品经理,运营人员,市场人员根据自己本公司的数据参考做出合理的决定,同时,运营的数据只是参考或者叫警示,若要具体,需要特定细节的分析,例如是否app改版,怎么改?需要增加哪家渠道合作? (1)Awareness 感知 (2)Acquisition 获客 目的1:衡量第一步提供的数据是否准确,即是否渠道作弊 目的2:判断渠道是否好坏 目的3:判断营销活动是否有效 例如下图中,我们发现4成用户是搜索流量较上个月增加了6%,是不是我们需要增加和sem的合作呢?而在媒体引荐渠道中,我们通过渠道衡量客户转化率,点击-用户激活的,激活的注册转化,可否重点对某应用商店增加合作 (3)Activities 活跃 获客后,我们想看看我们的新增、活跃用户的表现情况,那么就到了第三步 活跃,其实就是为产品经理改版app或者页面提供数据支持 活跃分析可参考以下三个步骤: 第一:从页面浏览次数,独立访问人数,来圈定主要页面分析。 例如某款app首页是pv,uv最高,我们会重点分析首页。 第二:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 第三:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 (4)Retention留存分析& Revenue & Refer 这几个实际上在企业运用的并不多,这里简要说明下。 ① Retention 用户积累到一定数量后,我们想看下用户粘性,那么我们就来到retention,一般是衡量活动效果时候运用的比较多,来看此次活动过后,是否用户依旧会使用我们的app,但是由于金融app属性不会像游戏应用每天进行访问,因此Retention 在实际应用中不会太多,下面的例子是个展示,不做赘述 ② Revenue 这些留下来的客户给公司贡献多少现金呢?会看收入步骤, 一般公司不会将现金流数据放入在统计平台中,但是我们需要提出用户贡献的流水金额数据供我们使用,便于人群划分,例如下面简要分析: Refer 传播: 用户分析 若说大数据分析的核心,其实就是在于用户分析,正如我们前面所讲,用户分析的步骤流程如下: 即在力所能及的搜集数据范围内,打通数据,客户用户,精准营销。 第一,我们可以筛选的条件列表,我们可以通过应用条件,位置,标签条件将数据整合,整合的目的就是刻画客户,定出营销策略。 例如:我们想筛选金融客户(应用条件筛选),出现在五星级酒店(位置条件),且为母婴人群(标签) 但是需要注意的是,条件越多,用户轮廓越清晰,人群会越少。 第二,根据筛选的人群,我们将线上/线上统计化,或者建模多维度分析。 例如,我们根据筛选的人群,发现男性多于女性,苹果手机属性最高,常手机工具使用,那么我们可以将这部分目标人群用增加手机工具合作、或者和苹果合作获客或者促活。 第三,整合以上数据分析,形成人群画像。 结束语 这篇文章基于我多年数据分析的经验,总结的一体化数据分析框架,其实就是简单介绍下数据分析能分析能落地的几点。当然,这里面需要大量的数据清洗工作,以及对行业的认知,此篇只是从数据分析角度的概要,内容上的细化,其实可以单拿出来细细分析,尤其用户画像那章节。 我们了解什么叫大数据分析么? 麦肯锡给大数据定义: “一种规模大到在获取、存储、管理、分析方面大大超出了传统数据库软件工具能力范围的数据集合,具有海量的数据规模、快速的数据流转、多样的数据类型和价值密度低四大特征。“ 基于我对以上定义的理解,我总结的大数据分析就是,将获取的数据,打通,整合,找寻规律,立即得出决策信息。 数据获取 我总结的数据源可分类三类: (1)一方数据:用户事实数据 例如用户在某金融机构购买的理财产品,时间,哪个出单口,姓名,电话等,或者运营数据,例如某互联金融app,用户操作行为数据 (3)三方数据:行业数据,也叫公开数据 例如行协的数据,或者互联网行为数据,例如某互联网公司用户在此网站的行为数据,或者嵌入sdk的app后我们能采集到的安装活跃列表,以及可采集到线下数据。 打通:其实就是利用关键点的采集整合一二三方数据。例如我们可以通过手机号将一方和三方数据整合,或者利用cookie,或者imei号等将二方、三方数据整合。但是由于现在监管制度对手机号敏感数据的控制,以及互联网和移动端数据的跨平台打通技术难点,我们现实的匹配率很低,例如一方和三方的数据匹配达到20%其实就算比较不错的情况,当然运营商数据除外。 找寻规律:目标就是数据清理,从非结构化数据变成结构化数据,以便统计,数据探索,找寻规律,形成数据分析报告观点。本文将会在第三部分阐述。 立即决策:将数据分析报告中的观点系统化或产品化,目前而言,大部分公司还是会依靠人工决策。 为什么需要大数据分析?看上去大数据分析似乎按照这些步骤来,但是从第一步的数据源来说,其实已经反应了大数据的特点,就是杂乱无章,那么怎么从这些数据找寻规律,分析的内容和目标是否对应上,似乎就是我们需要大数据分析的理由 现在,大数据的分析通常采用的数据报表来反映企业运营状况,同时,对于热点,人群分析,我们看到的统计值,目标核心都是用数据分析报告提炼的观点来指导运营,那么问题来了,怎么用数据分析来指导数据决策呢? 数据分析的报告思路(本文从移动端的角度进行切入) 基于我对数据分析的理解,我将数据报告会分成三大类:市场分析、运营分析、用户行为分析。 市场分析 由于市场分析一般而言是定性、定量分析,最近热播剧《我的前半生》贺函和唐晶的职业就是来去咨询公司的一般会以访谈、问卷调查来一份市场分析报告去告诉客户他们的市场占有量,消费者观点等。 这里,我们以移动互联网数据的市场分析为例,通常来说,数据源是公开数据,或者在第三方数据。正如我们所讲,将sdk嵌入开发者应用,就可以收集到安装以及使用列表,那么开发者使用的sdk越多,我们能收集的数据源也越多,这样就可以形成安装app排名,使用app排名,这里面所说的覆盖率、活跃率也是这个意思,例如:即此款应用安装量、使用量在整体金融类的安装量、使用量占比。 同时,根据市场的走势图,我们能发现潜在的竞争对手,例如:我们能看出下图中的工商银行由于手机属于高覆盖高活跃组,即安装xxapp活跃人群也是最高的,因此,无疑xx银行是所有银行组潜在竞争对手。需要更加注意他们的市场策略 运营分析 移动互联网提出的方法论:3A3R,笔者之前在做咨询的时候,此方法论也可以将网站分析套用,总结来说3A3R就是: 感知 → 获取 → 活跃 → 获取 → 营收 → 传播 → 感知 这里需要注明下,运营分析只是一个公司的baseline,让产品经理,运营人员,市场人员根据自己本公司的数据参考做出合理的决定,同时,运营的数据只是参考或者叫警示,若要具体,需要特定细节的分析,例如是否app改版,怎么改?需要增加哪家渠道合作? (1)Awareness 感知 (2)Acquisition 获客 目的1:衡量第一步提供的数据是否准确,即是否渠道作弊 目的2:判断渠道是否好坏 目的3:判断营销活动是否有效 例如下图中,我们发现4成用户是搜索流量较上个月增加了6%,是不是我们需要增加和sem的合作呢?而在媒体引荐渠道中,我们通过渠道衡量客户转化率,点击-用户激活的,激活的注册转化,可否重点对某应用商店增加合作 (3)Activities 活跃 获客后,我们想看看我们的新增、活跃用户的表现情况,那么就到了第三步 活跃,其实就是为产品经理改版app或者页面提供数据支持 活跃分析可参考以下三个步骤: 第一:从页面浏览次数,独立访问人数,来圈定主要页面分析。 例如某款app首页是pv,uv最高,我们会重点分析首页。 第二:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 第三:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 (4)Retention留存分析& Revenue & Refer 这几个实际上在企业运用的并不多,这里简要说明下。 ① Retention 用户积累到一定数量后,我们想看下用户粘性,那么我们就来到retention,一般是衡量活动效果时候运用的比较多,来看此次活动过后,是否用户依旧会使用我们的app,但是由于金融app属性不会像游戏应用每天进行访问,因此Retention 在实际应用中不会太多,下面的例子是个展示,不做赘述 ② Revenue 这些留下来的客户给公司贡献多少现金呢?会看收入步骤, 一般公司不会将现金流数据放入在统计平台中,但是我们需要提出用户贡献的流水金额数据供我们使用,便于人群划分,例如下面简要分析: Refer 传播: 用户分析 若说大数据分析的核心,其实就是在于用户分析,正如我们前面所讲,用户分析的步骤流程如下: 即在力所能及的搜集数据范围内,打通数据,客户用户,精准营销。 第一,我们可以筛选的条件列表,我们可以通过应用条件,位置,标签条件将数据整合,整合的目的就是刻画客户,定出营销策略。 例如:我们想筛选金融客户(应用条件筛选),出现在五星级酒店(位置条件),且为母婴人群(标签) 但是需要注意的是,条件越多,用户轮廓越清晰,人群会越少。 第二,根据筛选的人群,我们将线上/线上统计化,或者建模多维度分析。 例如,我们根据筛选的人群,发现男性多于女性,苹果手机属性最高,常手机工具使用,那么我们可以将这部分目标人群用增加手机工具合作、或者和苹果合作获客或者促活。 第三,整合以上数据分析,形成人群画像。 结束语 这篇文章基于我多年数据分析的经验,总结的一体化数据分析框架,其实就是简单介绍下数据分析能分析能落地的几点。当然,这里面需要大量的数据清洗工作,以及对行业的认知,此篇只是从数据分析角度的概要,内容上的细化,其实可以单拿出来细细分析,尤其用户画像那章节。
  2. 数据库加密字段的模糊搜索 This post was originally published on the and reposted here with their permission. 该帖子最初发布在并在获得其许可的情况下在此处重新发布。 We [ParagonIE] get asked the same question a lot (or some remix of it). 我们[ParagonIE]经常被问到相同的问题(或对其进行一些混音)。 This question shows up from time to time in . This was one of the “weird problems” covered in (titled Building Defensible Solutions to Weird Problems), and we’ve previously dedicated a small section to it in . 这个问题会不时出现在 。 这是 提到的“怪异问题”之一(标题为“ 为怪异问题构建防御解决方案” ),我们以前在专门针对了其中一小部分。 You know how to , but the question is, How do we securely encrypt database fields but still use these fields in search queries? 您知道如何 ,但问题是, 我们如何安全地加密数据库字段,但仍在搜索查询中使用这些字段? Our secure solution is rather straightforward, but the path between most teams asking that question and discovering our straightforward solution is fraught with peril: bad designs, academic research projects, misleading marketing, and poor . 我们的安全解决方案相当简单,但是大多数团队在提出问题和发现我们的简单解决方案之间的道路充满着危险:不良的设计,学术研究项目,误导性的营销以及不良的 。 If you’re in a hurry, feel free to . 如果您很着急,请随时 。 迈向可搜索的加密 (Towards Searchable Encryption) Let’s start with a simple scenario (which might be particularly relevant for a lot of local government or health care applications): 让我们从一个简单的场景开始(这可能与许多地方政府或医疗保健应用特别相关): You are building a new system that needs to collect social security numbers (SSNs) from its users. 您正在构建一个新系统,该系统需要从其用户那里收集社会保险号(SSN)。 Regulations and common sense both dictate that users’ SSNs should be encrypted at rest. 法规和常识都规定用户的SSN应该在静止状态下进行加密。 Staff members will need to be able to look up users’ accounts, given their SSN. 给定用户的SSN,工作人员将需要能够查找用户的帐户。 Let’s first explore the flaws with the obvious answers to this problem. 首先,让我们用明显的答案来解决这些缺陷。 不安全(或其他不良建议)的答案 (Insecure (or otherwise ill-advised) Answers) 非随机加密 (Non-randomized Encryption) The most obvious answer to most teams (particularly teams that don’t have security or cryptography experts) would be to do something like this: 对于大多数团队(特别是没有安全性或加密专家的团队),最明显的答案是这样做: <?php class InsecureExampleOne { protected $db; protected $key; public function __construct(PDO $db, string $key = ) { $this->db = $db; $this->key = $key; } public function searchByValue(string $query): array { $stmt = $this->db->prepare(SELECT * FROM table WHERE column = ?); $stmt->execute([ $this->insecureEncryptDoNotUse($query) ]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } protected function insecureEncryptDoNotUse(string $plaintext): string { return in2hex( openssl_encrypt( $plaintext, aes-128-ecb, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING ) ); } } In the above snippet, the same plaintext always produces the same ciphertext when encrypted with the same key. But more concerning with ECB mode is that every 16-byte chunk is , which can have some . 在以上代码段中,当使用相同的密钥加密时,相同的明文始终会产生相同的密文。 但是,与ECB模式有关的更多问题是,每个16字节的块分别进行了 ,这可能会带来一些 。 Formally, these constructions are not semantically secure: If you encrypt a large message, you will see blocks repeat in the ciphertext. 形式上,这些构造在语义上不是安全的:如果对大消息进行加密,则会在密文中看到块重复。 In order to be secure, encryption must be indistinguishable from random noise to anyone that does not hold the decryption key. Insecure modes include ECB mode and CBC mode with a static (or empty) IV. 为了安全起见,对于不持有解密密钥的任何人,加密必须与随机噪声没有区别。 不安全模式包括带有静态(或空)IV的ECB模式和CBC模式。 You want non-deterministic encryption, which means each message uses a unique nonce or initialization vector that never repeats for a given key. 您需要非确定性加密,这意味着每条消息都使用一个唯一的随机数或初始化矢量,该矢量永远不会重复给定密钥。 实验性学术设计 (Experimental Academic Designs) There is a lot of academic research going into such topics as , , and encryption techniques. 有很多学术研究涉及 , 和加密技术等主题。 As interesting as this work is, the current designs are nowhere near secure enough to use in a production environment. 尽管这项工作很有趣,但是当前的设计远没有足够的安全性可以在生产环境中使用。 For example, . 例如, 。 Homomorphic encryption schemes are often repackaging vulnerabilities (practical chosen-ciphertext attacks) as features. 同态加密方案通常将漏洞(实用的选择密文攻击)重新打包为功能。 Unpadded RSA is homomorphic . 填充的RSA是同态的。 If you multiply a ciphertext by an integer, the plaintext you get will be equal to the original message multiplied by the same integer. There are , which is why RSA in the real world uses padding (although often ). 如果将密文乘以整数,则得到的明文将等于原始消息乘以相同的整数。 填充的RSA有 ,这就是为什么RSA在现实世界中使用填充(尽管通常 )的原因。 Unpadded RSA is homomorphic . 填充的RSA是同态的。 AES in Counter Mode is homomorphic . 计数器模式下的AES 是同态的。 This is why nonce-reuse defeats the confidentiality of your message in CTR mode (and non-NMR stream ciphers in general). 这就是为什么随机数重用会破坏您在CTR模式下(通常是非NMR流密码)机密性的原因。 AES in Counter Mode is homomorphic . 计数器模式下的AES 是同态的。 As we’ve covered , when it comes to real-world cryptography, confidentiality without integrity is the same as no confidentiality. What happens if an attacker gains access to the database, alters ciphertexts, and studies the behavior of the application upon decryption? 正如我们 ,当涉及到现实世界的加密时, 没有完整性的机密就等于没有机密性 。 如果攻击者获得对数据库的访问权,更改密文并在解密后研究应用程序的行为,会发生什么? There’s potential for ongoing cryptography research to one day produce an innovative encryption design that doesn’t undo decades of research into safe cryptography primitives and cryptographic protocol designs. However, we’re not there yet, and you don’t need to invest into a needlessly complicated research prototype to solve the problem. 正在进行的密码学研究有一天有可能产生一种创新的加密设计,这种设计不会撤销对安全密码学原语和密码协议设计的数十年研究。 但是,我们还不存在,您不需要投资不必要的复杂研究原型来解决问题。 丢人的提法:解密每一行 (Dishonorable Mention: Decrypt Every Row) I don’t expect most engineers to arrive at this solution without a trace of sarcasm. The bad idea here is, because you need secure encryption (see below), your only recourse is to query every ciphertext in the database and then iterate through them, decrypting them one-by-one and performing your search operation in the application code. 我不希望大多数工程师都能毫不讽刺地提出这个解决方案。 这里的一个坏主意是,因为需要安全加密(请参见下文),所以唯一的办法就是查询数据库中的每个密文,然后对其进行遍历,然后将其解密,然后对它们进行解密,然后在应用程序代码中执行搜索操作。 If you go down this route, you will open your application to denial of service attacks. It will be slow for your legitimate users. This is a cynic’s answer, and you can do much better than that, as we’ll demonstrate below. 如果沿着这条路线走,您将打开应用程序以拒绝服务攻击。 对于您的合法用户,这将很慢。 这是一个愤世嫉俗的答案,您可以做的比这更好,我们将在下面演示。 安全的可搜索加密变得轻松 (Secure Searchable Encryption Made Easy) Let’s start by avoiding all the problems outlined in the insecure/ill-advised section in one fell swoop: All ciphertexts will be the result of an authenticated encryption scheme, preferably with large nonces (generated from a ). 让我们一口气避免不安全/不明智的部分中概述的所有问题:所有密文都是经过身份验证的加密方案的结果,最好是使用大随机数(由 )。 With an authenticated encryption scheme, ciphertexts are non-deterministic (same message and key, but different nonce, yields a different ciphertext) and protected by an authentication tag. Some suitable options include: XSalsa20-Poly1305, XChacha20-Poly1305, and (assuming it’s not broken before CAESAR concludes) NORX64-4-1. If you’re using NaCl or libsodium, you can just use crypto_secretbox here. 使用经过身份验证的加密方案,密文是不确定的(相同的消息和密钥,但是不同的随机数,会产生不同的密文),并且受身份验证标签保护。 一些合适的选项包括:XSalsa20-Poly1305,XChacha20-Poly1305,以及(假设在CAESAR得出结论之前没有损坏)NORX64-4-1。 如果您使用的是NaCl或libsodium,则可以在此处使用crypto_secretbox 。 Consequently, our ciphertexts are indistinguishable from random noise, and protected against chosen-ciphertext attacks. That’s how secure, boring encryption ought to be. 因此,我们的密文与随机噪声是无法区分的 ,并且可以防止选择密文攻击 。 那应该是多么安全,无聊的加密。 However, this presents an immediate challenge: We can’t just encrypt arbitrary messages and query the database for matching ciphertexts. Fortunately, there is a clever workaround. 但是,这提出了直接的挑战:我们不能只加密任意消息并查询数据库以查找匹配的密文。 幸运的是,有一个聪明的解决方法。 重要提示:威胁模型您的加密使用情况 (Important: Threat Model Your Usage of Encryption) Before you begin, make sure that encryption is actually making your data safer. It is important to emphasize that “encrypted storage” isn’t the solution to securing a CRUD app that’s vulnerable to SQL injection. Solving the actual problem (i.e. ) is the only way to go. 在开始之前,请确保加密实际上使您的数据更安全。 需要强调的是,“加密存储”并不是保护易受SQL注入攻击的CRUD应用程序的解决方案。 解决实际问题(即 )是唯一的方法。 If encryption is a suitable security control to implement, this implies that the cryptographic keys used to encrypt/decrypt data are not accessible to the database software. In most cases, it makes sense to keep the application server and database server on separate hardware. 如果加密是要实施的合适安全控制措施,则意味着用于加密/解密数据的加密密钥不可被数据库软件访问。 在大多数情况下,将应用程序服务器和数据库服务器保持在单独的硬件上是有意义的。 实施加密数据的文字搜索 (Implementing Literal Search of Encrypted Data) Possible use-case: Storing social security numbers, but still being able to query them. 可能的用例:存储社会安全号码,但仍然能够查询它们。 In order to store encrypted information and still use the plaintext in SELECT queries, we’re going to follow a strategy we call blind indexing. The general idea is to store a keyed hash (e.g. HMAC) of the plaintext in a separate column. It is important that the blind index key be distinct from the encryption key and unknown to the database server. 为了存储加密信息并仍在SELECT查询中使用纯文本,我们将遵循一种称为盲索引的策略。 一般想法是将明文的键控哈希(例如HMAC)存储在单独的列中。 重要的是,盲索引密钥必须与加密密钥不同,并且数据库服务器不知道。 For very sensitive information, instead of a simple HMAC, you will want to use a key-stretching algorithm (PBKDF2-SHA256, scrypt, Argon2) with the key acting as a static salt, to slow down attempts at enumeration. We aren’t worried about offline brute-force attacks in either case, unless an attacker can obtain the key (which must not stored in the database). 对于非常敏感的信息,而不是简单的HMAC,您将希望使用键拉伸算法(PBKDF2-SHA256,scrypt,Argon2),并将键用作静态盐,以减慢枚举的尝试。 在任何一种情况下,我们都不必担心脱机暴力攻击,除非攻击者可以获得密钥(密钥不能存储在数据库中)。 So if your table schema looks like this (in PostgreSQL flavor): 因此,如果您的表模式如下所示(采用PostgreSQL风格): CREATE TABLE humans ( humanid BIGSERIAL PRIMARY KEY, first_name TEXT, last_name TEXT, ssn TEXT, /* encrypted */ ssn_bidx TEXT /* blind index */ ); CREATE INDEX ON humans (ssn_bidx); You would store the encrypted value in humans.ssn. A blind index of the plaintext SSN would go into humans.ssn_bidx. A naive implementation might look like this: 您将把加密后的值存储在humans.ssn 。 明文SSN的盲索引将进入humans.ssn_bidx 。 天真的实现可能看起来像这样: <?php /* This is not production-quality code. * Its optimized for readability and understanding, not security. */ function encryptSSN(string $ssn, string $key): string { $nonce = random_bytes(24); $ciphertext = sodium_crypto_secretbox($ssn, $nonce, $key); return bin2hex($nonce . $ciphertext); } function decryptSSN(string $ciphertext, string $key): string { $decoded = hex2bin($ciphertext); $nonce = mb_substr($decoded, 0, 24, 8bit); $cipher = mb_substr($decoded, 24, null, 8bit); return sodium_crypto_secretbox_open($cipher, $nonce, $key); } function getSSNBlindIndex(string $ssn, string $indexKey): string { return bin2hex( sodium_crypto_pwhash( 32, $ssn, $indexKey, SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE, SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE ) ); } function findHumanBySSN(PDO $db, string $ssn, string $indexKey): array { $index = getSSNBlindIndex($ssn, $indexKey); $stmt = $db->prepare(SELECT * FROM humans WHERE ssn_bidx = ?); $stmt->execute([$index]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } A more comprehensive proof-of-concept is included in the . It’s released under the Creative Commons CC0 license, which for most people means the same thing as “public domain”. 中的包含更全面的概念证明。 它是根据知识共享CC0许可证发布的,对于大多数人来说,该许可证与“公共领域”具有相同的含义。 安全分析和局限性 (Security Analysis and Limitations) Depending on your exact threat model, this solution leaves two questions that must be answered before it can be adopted: 根据您的确切威胁模型,此解决方案留下两个必须采用的问题,然后才能被采用: Is it safe to use, or does it leak data like a sieve? 使用安全吗,还是像筛子一样泄漏数据? What are the limitations on its usefulness? (This one is sort of answered already.) 其用途有哪些限制? (这个已经回答了。) Given our example above, assuming your encryption key and your blind index key are separate, both keys are stored in the webserver, and the database server doesn’t have any way of obtaining these keys, then any attacker that only compromises the database server (but not the web server) will only be able to learn if several rows share a social security number, but not what the shared SSN is. This duplicate entry leak is necessary in order for indexing to be possible, which in turn allows fast SELECT queries from a user-provided value. 在上面的示例中,假设您的加密密钥和盲索引密钥是分开的,两个密钥都存储在Web服务器中,并且数据库服务器没有任何获取这些密钥的方式,那么任何只会破坏数据库服务器的攻击者( (而不是Web服务器)将只能知道是否有几行共享一个社会保险号,而不是共享的SSN是什么。 为了使索引成为可能,此重复的条目泄漏是必需的,这反过来又允许从用户提供的值进行快速的SELECT查询。 Furthermore, if an attacker is capable of both observing/changing plaintexts as a normal user of the application while observing the blind indices stored in the database, they can leverage this into a chosen-plaintext attack, where they iterate every possible value as a user and then correlate with the resultant blind index value. This is more practical in the HMAC scenario than in the e.g. Argon2 scenario. For high-entropy or low-sensitivity values (not SSNs), can be on our side. 此外,如果攻击者既可以作为应用程序的普通用户来观察/更改纯文本,又可以观察数据库中存储的盲索引,则他们可以将其利用为选择明文攻击 ,在这种情况下,他们以用户身份遍历每个可能的值。然后与所得的盲指标值相关。 这在HMAC方案中比在例如Argon2方案中更实用。 对于高熵或低灵敏度值(不是SSN), 可以在我们这一边。 A much more practical attack for such a criminal would be to substitute values from one row to another then access the application normally, which will reveal the plaintext unless a distinct per-row key was employed (e.g. hash_hmac(sha256, $rowID, $masterKey, true) could even be an effective mitigation here, although others would be preferable). The best defense here is to use an AEAD mode (passing the primary key as additional associated data) so that the ciphertexts are tied to a particular database row. (This will not prevent attackers from deleting data, which is .) 对于这样的犯罪分子,更实际的攻击是将值从一行替换为另一行,然后正常访问应用程序, 除非使用不同的逐行密钥(例如hash_hmac(sha256, $rowID, $masterKey, true)甚至可以在这里hash_hmac(sha256, $rowID, $masterKey, true)有效的缓解作用,尽管其他方式更可取)。 最好的防御方法是使用AEAD模式(将主键作为附加关联数据传递),以便将密文绑定到特定的数据库行。 (这不会阻止攻击者删除数据,这是 。) Compared to the amount of information leaked by other solutions, most applications’ threat models should find this to be an acceptable trade-off. As long as you’re using authenticated encryption for encryption, and either HMAC (for blind indexing non-sensitive data) or a (for blind indexing sensitive data), it’s easy to reason about the security of your application. 与其他解决方案泄漏的信息量相比,大多数应用程序的威胁模型应该认为这是可以接受的折衷方案。 只要您使用经过身份验证的加密进行加密,并且使用HMAC(用于对非敏感数据进行盲索引)或 (用于对敏感数据进行盲索引),就很容易推断出应用程序的安全性。 However, it does have one very serious limitation: It only works for exact matches. If two strings differ in a meaningless way but will always produce a different cryptographic hash, then searching for one will never yield the other. If you need to do more advanced queries, but still want to keep your decryption keys and plaintext values out of the hands of the database server, we’re going to have to get creative. 但是,它确实有一个非常严重的局限性:它仅适用于完全匹配。 如果两个字符串毫无意义地不同,但始终会产生不同的密码哈希,那么搜索一个字符串将永远不会产生另一个字符串。 如果您需要执行更高级的查询,但仍然希望使解密密钥和纯文本值不受数据库服务器的影响,我们将必须发挥创意。 It is also worth noting that, while HMAC/Argon2 can prevent attackers that do not possess the key from learning the plaintext values of what is stored in the database, it might reveal metadata (e.g. two seemingly-unrelated people share a street address) about the real world. 还值得注意的是,尽管HMAC / Argon2可以阻止不掌握密钥的攻击者了解数据库中存储内容的明文值,但它可能会泄露有关以下内容的元数据(例如,两个看似无关的人共享街道地址)现实中。 实施模糊搜索以加密数据 (Implementing Fuzzier Searching for Encrypted Data) Possible use-case: Encrypting peoples’ legal names, and being able to search with only partial matches. 可能的用例:加密人们的法定姓名,并且仅能进行部分匹配来进行搜索。 Let’s build on the previous section, where we built a blind index that allows you to query the database for exact matches. 让我们在上一节的基础上进行构建,在上一节中,我们建立了一个盲目索引,该索引使您可以查询数据库中的精确匹配项。 This time, instead of adding columns to the existing table, we’re going to store extra index values into a join table. 这次,我们不是将列添加到现有表中,而是将额外的索引值存储到联接表中。 CREATE TABLE humans ( humanid BIGSERIAL PRIMARY KEY, first_name TEXT, /* encrypted */ last_name TEXT, /* encrypted */ ssn TEXT, /* encrypted */ ); CREATE TABLE humans_filters ( filterid BIGSERIAL PRIMARY KEY, humanid BIGINT REFERENCES humans (humanid), filter_label TEXT, filter_value TEXT ); /* Creates an index on the pair. If your SQL expert overrules this, feel free to omit it. */ CREATE INDEX ON humans_filters (filter_label, filter_value); The reason for this change is to normalize our data structures. You can get by with just adding columns to the existing table, but it’s likely to get messy. 进行此更改的原因是为了规范化我们的数据结构。 您只需在现有表中添加列即可解决问题,但这很可能会变得凌乱。 The next change is that we’re going to store a separate, distinct blind index per column for every different kind of query we need (each with its own key). For example: 下一个更改是,我们将为所需的每种不同类型的查询(每个都有自己的键)在每列存储一个单独的,不同的盲索引。 例如: Need a case-insensitive lookup that ignores whitespace? 是否需要忽略空格的不区分大小写的查找? Store a blind index of preg_replace(/[^a-z]/, , strtolower($value)). 存储preg_replace(/[^az]/, , strtolower($value))的盲索引。 Need to query the first letter of their last name? 是否需要查询其姓氏的首字母? Store a blind index of strtolower(mb_substr($lastName, 0, 1, $locale)). 存储strtolower(mb_substr($lastName, 0, 1, $locale))的盲索引。 Need to match “beings with this letter, ends with that letter”? 是否需要匹配“以这个字母存在,以那个字母结尾”? Store a blind index of strtolower($string[0] . $string[-1]). 存储strtolower($string[0] . $string[-1])的盲索引。 Need to query the first three letters of their last name and the first letter of their first name? 需要查询姓氏的前三个字母和姓氏的第一个字母吗? You guessed it! Build another index based on partial data. 你猜到了! 基于部分数据构建另一个索引。 Every index needs to have a distinct key, and great pains should be taken to prevent blind indices of subsets of the plaintext from leaking real plaintext values to a criminal with a knack for crossword puzzles. Only create indexes for serious business needs, and log access to these parts of your application aggressively. 每个索引都需要有一个独特的键,并且应该竭尽全力以防止明文子集的盲目索引将真实的明文值泄漏给具有填字游戏难题的犯罪分子。 仅创建满足严重业务需求的索引,并积极记录对应用程序这些部分的访问。 交易时间记忆 (Trading Memory for Time) Thus far, all of the design propositions have been in favor of allowing developers to write carefully considered SELECT queries, while minimizing the number of times the decryption subroutine is invoked. Generally, that is where the train stops and most peoples’ goals have been met. 到目前为止,所有设计主张都支持允许开发人员编写经过仔细考虑的SELECT查询,同时最大程度地减少解密子例程的调用次数。 通常,这是火车停下来的地方,大多数人的目标已经实现。 However, there are situations where a mild performance hit in search queries is acceptable if it means saving a lot of disk space. 但是,在某些情况下,如果这意味着节省大量磁盘空间,则在搜索查询中出现性能下降的情况是可以接受的。 The trick here is simple: Truncate your blind indexes to e.g. 16, 32, or 64 bits, and treat them as a : 这里的技巧很简单:将盲索引截断为16、32或64位,然后将它们视为 : If the blind indices involved in the query match a given row, the data is probably a match. 如果查询中涉及的盲索引匹配给定的行,则数据可能是匹配的。 Your application code will need to perform the decryption for each candidate row and then only serve the actual matches. 您的应用程序代码将需要为每个候选行执行解密,然后仅提供实际的匹配项。 If the blind indices involved in the query match a given row, the data is probably a match. 如果查询中涉及的盲索引匹配给定的行,则数据可能是匹配的。 If the blind indices involved in the query do not match a given row, then the data is definitely not a match. 如果查询中涉及的盲索引与给定行不匹配,则该数据绝对不是匹配项。 It may also be worth converting these values from a string to an integer, if your database server will end up storing it more efficiently. 如果您的数据库服务器最终将更有效地存储这些值,那么也可能需要将这些值从字符串转换为整数。 结论 (Conclusion) I hope I’ve adequately demonstrated that it is not only possible to build a system that uses secure encryption while allowing fast queries (with minimal information leakage against very privileged attackers), but that it’s possible to build such a system simply, out of the components provided by modern cryptography libraries with very little glue. 我希望我已经充分证明了,不仅可以构建一个使用安全加密同时允许快速查询的系统(对特权较高的攻击者的信息泄漏最少),而且还可以简单地构建一个这样的系统,现代密码学库提供的几乎不需要胶水的组件。 If you’re interested in implementing encrypted database storage into your software, we’d love to provide you and your company with our consulting services. if you’re interested.
  3. 前言 我们在进行网络通信时,需要数据包在不同网络设备之间传输。这个过程就需要数据包进行封装与解封装。 一、数据封装与解封装过程 1.1、数据封装过程 应用层传输过程: 在应用层,数据“翻译”为网络世界使用的语音——二进制编码数据。 传输层传输过程: 在传输层,上层数据被分割成小的数据段,并为每个分段后的数据封装TCP报文头部。在TCP头部有一个关键的字段信息——端口号,他用于标识上层的协议或应用程序,确保上层应用数据的正常通信。 网络层传输过程: 在网络层,上层数据被封装上新的报文头部——IP头部。(这里所说的上层数据包括TCP头部。) 数据链路层传输过程: 在数据链路层,上层数据被封装一个MAC头部,其内部有一个关键的字段信息——MAC地址。 物理层传输过程: 无论是之前每一层封装的头部还是上层数据信息都是由二进制组成的,物理层将这些二进制数字组成的比特流转换成电信号在网络中传输。 封装过程图示: 1. 2、数据解封装过程 数据被封装完毕通过网络传输到接收方后,将进入的数据解封装,这将是封装过程的一个逆过程。 如图示: 1.3、相关数据传输的一些基本概念 1.3.1 PDU图示 PDU——协议数据单元 PDU是指同层之间传递的数据单位。 应用层:消息/报文(上层数据)。 传输层:数据段(TCP头部、上层数据)。 网络层:数据包(IP头部、TCP头部、上层数据)。 数据链路层:数据帧(MAC头部、IP头部、TCP头部、上层数据) 物理层:比特流 PDU图示: 1. 3.2 常见硬件设备与五层模型的对应关系层名称 应用层 传输层 网络层 数据链路层 物理层 典型设备 计算机 防火墙 路由器 交换机 网卡 二、数据封装与解封装过程 首先要明确一个问题,发送方与接收方各层必须采用相同的协议才能建立连接,实现正常的通信。 如图示: 总结 综上所述,数据封装与解封装在网络通信中占据非常重要的地位。
  4. NLP学习路线 开始记录学习nlp,学习路线参考博主的建议,后续把这部分的内容进行整理。 前言要学好NLP,下面3个是缺一不可的: 1. 机器学习基础 人工智能很多技术和模块是搭建在机器学习基础上的,无论是CV,NLP,语音识别。可以直接去学习一个方向,也能学到东西。 但是可能不能很好的理解技术和模型背后的细节。 2. 数据结构与算法 在工程上写一个算法,如果不懂数据结构和算法,写出来的程序可能效率不高,达不到上线的要求。所以要懂数据结构和算法,才能写出最优化,性能高的程序。 3. 良好的编程基础 有良好的编程基础才能写出好的程序,不只是会讲讲理论,还能够实现出来,达到落地的地步。 在有了上面的基础后,学完自然语言的基础知识。然后需要在NLP里选择一个技术路线或者应用领域。比如预训练模型BERT,图神经网络。或者选择一个领域,智能对话系统,自然语言生成等,在某一个领域深入下去,把领域内的方方面面知识点都搞明白能够串起来。我们要使自己成为一个T字型的人才,有一个的知识的宽度,同时一定要在某方面有深度。 同时我们要养成读论文的习惯,比如在工作中突然来了一个新的需求,这时候就需要去读读论文,看看别人的思路,做一个baseline出来,然后再此基础上进行改进。 1、自然语言处理 自然语言处理 = Natural Language Processing = NLP 自然语言理解 = Natural Language Understanding = NLU = 理解文本中的意思 自然语言生成 = Natural Language Generation = NLG = 根据意思生成文本 例1) 一个人在看百度贴吧看帖子的时候, 首先是看帖子,这是一个理解文本内容(NLU)的过程, 然后回答帖子,这是一个生成文本(NLG)的过程。 例2) 人类在语言交流的时候 1) 听到对方的声音讯号, 根据从小学习的语文, 转换成一串文字。 (语音识别) 2) 对这段文字进行理解。 (NLU) 3) 回复对方。 (NLG) 1.1 为什么自然语言处理难? 图片:所见即所得。 文字:看到的是文字,要理解背后的含义。 1) CV的图像,一眼看过去,图片内容很直观明了。比如图片中一只狗在追一只猫,看图片就知道内容,很少有要揣摩图片意思的应用场景, 基本都是图片分类,目标检测等。 2) 自然语言的理解,想想我们从小学习的古诗还有阅读理解,要进行前后文内容的结合,才能回答问题; 还有一词多义, 一句多义等。 还有一个场景,有人突然说了一句话,听的多个人听完后可能理解的意思是不一样的。 1.2 自然语言处理技术的三个维度 自然语言理解是从上到下的一个过程:单词->句子结构->句子含义 Morphology(单词) :构成语言的最小单位,单词本身含义,词性 Syntax(句子结构):句子剖析,主语+谓语+宾语,语法树 Semantic(语义):这句话的含义, 最终的目的地 1.3 NLP基础任务 nlp基础任务主要分为以下几点: 1、分词(Word Segmentation):单词是句子最小的单位,要把句子切分完后做特征工程,中文比英文要难些,英文天生空格或其他符号就能切分,中文要借助一些算法才能分出一个比较好的结果。分词是NLP任务的第一步,是已经解决的问题。 2. 词性分析(Part-of-Speech Tagging):对后续单词理解是有帮助的,词性也可以作为后续任务的特征。非常基础的工作,是已经解决的比较好的问题。 3. 语义理解(Semantic Understanding):理解一句话的含义,NLP领域的核心。例如Bert本身也是为了很好的理解一个单词,以达到更好的理解一句话。 4. 命名实体识别(Named Entity Recognition):比较基础的任务,现实生活中实际存在的一个物体,比如人,地名,公司名,组织名,时间。 医疗领域:科室,药名。 实体是在一个领域里比较有含义的单词,通常是给一个文本,任务是把实体标记出来。 像聊天机器人,意图识别,知识图谱等场景中,命名实体识别对后续的任务有非常大的帮助。 5. 依存文法分析(Dependecy Parsing):语法分析领域的重要技术,单词之间的依存关系。 6. 句法分析(Parsing):对一句话的结构,主谓宾来进行剖析,语法树。实际应用场景比较少,即使有也对系统提升比较小。 依存文法分析通常价值比句法分析大。 7. 自然语言处理技术概览 1.4 算法复杂度 对于复杂度的理解是至关重要的。写完任何一个程序,我们都需要仔细思考程序的效率如何。这个效率可以从两个方面来考虑,一方面是时间复杂度,另外一方面是空间复杂度。 算法复杂度衡量的是一个算法的效率,比如一个算法运行下来需要多长时间?需要消耗多少资源?根据算法复杂度,我们可以评估一个算法的优劣。在算法复杂度的衡量上,我们经常使用Big O表示法 复杂度的理解是必修课。在从事AI工作中经常会碰到各种各样程序效率低的问题,一个模型训练起来可能需要几天甚至几个月。这时候最直接的解决方式就是加机器,但也是最笨的方法。作为一名AI工程师,我们首先需要想到如何从根本上优化算法,比如检查是否使用了合理的数据结构? 如果一个程序需要经常做数据的查询,那这时候你要考虑用像哈希等合理的数据结构了。相反,如果你用的是列表(list),查询速度就会变得很慢。 再比如,假设我们需要寻找一堆数据中的最大的几个数,很多人可能会选择先把所有的数做排序,之后在提取最大的前几个。但有没有比这个更高效的做法呢? 实际上,在这个场景,我们可以使用一个优先队列(priority queue)来更快速地做查询。 所以,你可以看到每一个小的细节决定了整个程序的效率。这也是为什么一定要重视算法复杂度的原因。 算法复杂度不是衡量程序跑了几秒,而是分析算法效率的级别,线性与问题的大小,平方与问题大小,三次方与问题大小。 复杂度从下面两个角度去衡量1)时间复杂度:用了多少时间; 2)空间复杂度:用了多少内存空间 1) 时间复杂度 随着n的增加,时间增长的趋势 // O(1)的时间复杂度 int x = 0; int y = 1; // O(n)时间复杂度 for (int i = 1; i < =n;i++){ x++; } // O(n^2)时间复杂度 for (int i = 1; i < =n;i++){ for (int j= 1; j< =n;j++){ x++; } } // // O(n+n^2) = O(n^2)时间复杂度 for (int i = 1; i < =n;i++){ x++; } for (int i = 1; i < =n;i++){ for (int j= 1; j< =n;j++){ x++; } } //O(LogN)的算法复杂度 int i = 1; while (i<n) i = i * 2; //O(NLogN)的算法复杂度 for (int i = 1; i < =n;i++){ int i = 1; while (i<n) i = i * 2; } 空间复杂度 随着n的增加,空间增长的趋势 // O(1)的空间复杂度 int x = 0; int y = 1; // O(n)的空间复杂度 int[] nums = new int[n]; for(int i = 0; i< n;i++){ nums[i]=i; } //O(n^2)的空间复杂度 matrix,矩阵分配空间,下面为一个n*n的方阵的内存分配 void malloc2D_1(int **&a, int n) { a = new int*[n]; for(int i=0;i<n;i++) a[i] = new int[n]; } 3) 斐波那契数列的时间复杂度 O(2^n) :计算加法所执行的次数 F[n]=F[n-1]+F 实现: def fb(n): if n==0: return 0 if n==1: return 1 return fb(n-1)+fb(n-2) if __name__ == "__main__": s=fb(9) print(s) 4) 斐波那契数列的空间复杂度 O(n) : 计算时最多入栈的数据的数量,递归调用函数时,会进行上下文切换,对当前函数中的状态进行入栈操作,当调用函数返回时,进行出栈操作。 1.5 动态规划算法 动态规划的核心思想:把计算结果存入内存, 需要的时候从内存里取出来。 为了解决一个大的问题,我们从小问题开始解决。 但一旦解决了小问题,我们就把这些问题的答案存放在内存空间为后续提供使用。所以对于动态规划算法有几个关键点: 1、子问题:思考如何把一个问题拆解成更小的子问题? 并把大问题以子问题的形式表示出来? 2、结果存放:如何存放过程结果? 实际例子:最大递增子串 import numpy as np import sys def max_subseq_sum(arr): max_so_far = -sys.maxsize #取系统的最大值 max_current = 0 #当前最长子序列的和 for i in range(0, len(arr)): #1)当前位置的最长子序列的和有两种可能,分别是下面的if和else if max_current + arr[i] >= arr[i]: #第一种可能:到i-1位置和>=0,到i位置的和就是i-1加上当前位置 max_current = max_current + arr[i] else: #第二种可能:i-1位置是负数,i位置就是自己的值 max_current = arr[i] #2) 如果本轮循环加上i位置的值比上一轮要大,则更新 #否则不更新(例如本轮加了一个负值,就会比上一轮小,就不要更新) if max_so_far < max_current: max_so_far = max_current return max_so_far print (max_subseq_sum(np.array([-2, -3, 4, -1, -2, 1, 5, -3]))) print (max_subseq_sum(np.array([-1,1,2,3,4,-5,2,4]))) 上面代码思路说明: 1)分解子问题: 当前位置最长子序列 = Max(当前位置的值,前一个位置的最长子序列和+当前位置的值) 2)存放子问题结果:存放在max_current中 3)本轮结束时会读取子问题的结果max_current,并和上一轮的结果max_so_far比较,选取较大值更新到max_so_far中 import sys # m是硬币的种类,coins代表具体的面值,V是想换取的纸钞面值。 def minCoins(coins, m, C): # coins: 硬币的面值 # m : 硬币的个数 = len(coins) # C: 需要换的纸币面值 # table[i] 存储换取面值为i的纸币,需要用到的最少量的硬币数 table = [0 for i in range(C + 1)] # Base case table[0] = 0 # 初始化 for i in range(1, C + 1): table[i] = sys.maxsize # 对于每一种价值i来计算,最少用多少硬币可以换取? for i in range(1, C + 1): # Go through all coins smaller than i for j in range(m): if (coins[j] <= i): sub_res = table[i - coins[j]] if (sub_res != sys.maxsize and #在所有coin[j]中找最好的 sub_res + 1 < table[i]): table[i] = sub_res + 1 #上图中m(j)的值+1 return table[C] arr = [1, 2, 3] m = len(arr) n = 6 print(minCoins(arr, m, n)) 2、吃瓜教程——西瓜书+南瓜书 机器学习中监督学习的基本任务 分类任务 回归任务 监督学习 非监督学习 半监督学习 一部分数据有“标记”或者“答案”,另一部分数据没有 更常见:各种原因产生的标记缺失。 增强学习 知道这些概念后,现在开始步入机器学习的第一步。 2.1 线性回归 2.2 逻辑回归 2.2.1 逻辑回归有什么用 逻辑回归,虽然名字叫“回归”,但是它并不是用来回归的。什么是回归?我们之前有介绍过,回归问题解决的是因变量(即Y)是连续值的情况。 而逻辑回归是解决Y是离散变量的问题,即分类。 通常而言,逻辑回归主要解决的是二分类的问题,即分类的结果只有两个类别。比如【男,女】、【有钱,没钱】、【感染病毒,没感染病毒】、【垃圾邮件,不是垃圾邮件】……等等。 从上面的例子中,我们其实可以想象出,其实逻辑回归的应用场景是比较多的。比如基于邮件的特征,去判断一封邮件是否是垃圾邮件;基于用户行为,判断用户的性别等。 2.2.2 逻辑回归的本质 逻辑回归,虽然是一种分类算法,但确实和“回归”有一些关联。如果用一个公式表达: 逻辑回归=线性回归+sigmoid函数 对,这里的关键,就是sigmoid函数。这个函数就是我们之前讲回归和分类时候的激活函数。激活函数是为了将线性回归的连续性结果映射到离散值上,这样就是分类问题了。 在网上看到一张图展示逻辑回归的原理: 2.2.3 算法逻辑 (1)sigmoid函数 我们先看一看下面的函数(单位越阶函数)作为激活函数: 这个是不是可以将连续的z(z=wx+b)映射到离散的y了?是的。 但是,如果将这个函数如果作为激活函数,将会导致函数是不连续不可导的。 因此,我们需要找到一个可以替代这个函数的函数,使其单调可微。什么函数呢?对,这就是sigmoid函数的一种:对数几率函数。 这个函数是连续的,极限取值是0-1,且可以按照0.5的阈值进行二分类。 用了这个函数以后,y和x的函数关系变为 其中: 2.2.4 损失函数 将输入的值映射到0,1之间,0,1之间就可以看成概率值。 反向传播要求导,求导的结果就是g(z)*(1-g(z)),比较好计算。 红色虚线是求导后函数的图形,当z=0时取最大值0.25;当z取值比较大(两端),梯度接近为0,这就是神经网络中sigmoid作为激活函数梯度消失的原因。 ok,既然有了上述的预测函数,下一步,我们要定义具体的损失函数。这里,我们通常用对数似然损失来作为损失函数: 这个公式比较好理解,就不展开了。 这个代价函数呢,叫做交叉熵,其中y(i)指的是预测的结果,而hθ(xi)指的是xi这个点原本的值。 那么它具体是什么意思呢,为什么叫做交叉熵?我们举两个极端的例子看看就明白了: 1、xi原始值hθ=1,预测结果,yi=1的情况 这个时候,代价函数的加号右边会被消掉,因为右边(1-y(i))是0,左边部分呢,因为hθ(xi)=1,故而 log(1)=0。 y(i)log(hθ(xi)) = 1 * log(0) = 0 也就是说,若xi原始值是1,当预测值y=1的时候,代价函数是0的。这个也比较好理解,代价函数为0就是说预测结果和原始结果完全一致的,没有半点出差错。 2、计算结果,yi=0,原始值hθ=0 因为1-hθ(xi),最终结果还是等于0。 也就是说,这个损失函数,只要原始值与预测结果越相符,损失函数就越大,反之,损失函数就会越小。 以上说的只是一个点的情况,实际的代价函数,是要计算所有点的损失函数的均值,如下所示: 2.2.5 损失函数推导 由于: 假设逻辑回归的cost函数如下,我们如何理解这个公式呢? 将逻辑回归的cost函数简化,即得出: 所以就有: 我们可以利用梯度下降算法来求得J(θ)的值最小,根据梯度下降法可得θ的更新过程。j=0 时,代表更新j向量的第0分量,j=1 时,代表更新j向量的第1分量,以此类推,为了方便理解,可以把j看成数组vector_j,j=0,就是更新vector_j[0]。α为学习步长。 经过一些数学推导的最终形式如下(推导过程为对θ求偏导数)。 针对求导过程: ps:xj为x向量的第j分量,还可以理解为x数组的第j项,其实下图是对θ数组的第j项进行更新的算式,然而真正代码角度是对整个θ数组进行更新,也就是下下图的样子。 当我们把上式向量化处理就得到了代码可以处理的形式。 2.2.6 逻辑回归案例 学习了原理之后,看看这个到底怎么使用。 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets iris = datasets.load_iris() X = iris.data y = iris.target plt.scatter(X[y==0,0], X[y==0,1], color="red") plt.scatter(X[y==1,0], X[y==1,1], color="blue") plt.show() 首先对数据进行切分: import numpy as np from sklearn import datasets def train_test_split(X, y, test_ratio=0.2, seed=None): """将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test""" assert X.shape[0] == y.shape[0], "the size of X must be equal to the size of y" assert 0.0 <= test_ratio <= 1.0, "test_ration must be valid" if seed: np.random.seed(seed) shuffled_indexes = np.random.permutation(len(X)) test_size = int(len(X) * test_ratio) test_indexes = shuffled_indexes[:test_size] train_indexes = shuffled_indexes[test_size:] X_train = X[train_indexes] y_train = y[train_indexes] X_test = X[test_indexes] y_test = y[test_indexes] return X_train, X_test, y_train, y_test if __name__=="__main__": iris = datasets.load_iris() X = iris.data y = iris.target X_train, X_test, y_train, y_test = train_test_split(X, y, seed=666) print(X_train.shape) #(120, 4) 接下来编写逻辑回归类: import numpy as np class LogisticRegression: def __init__(self): """初始化Logistic Regression模型""" self.coef_ = None self.intercept_ = None self._theta = None def _sigmoid(self, t): return 1. / (1. + np.exp(-t)) def fit(self, X_train, y_train, eta=0.01, n_iters=1e4): """根据训练数据集X_train, y_train, 使用梯度下降法训练Logistic Regression模型""" assert X_train.shape[0] == y_train.shape[0], "the size of X_train must be equal to the size of y_train" def J(theta, X_b, y): y_hat = self._sigmoid(X_b.dot(theta)) try: return - np.sum(y * np.log(y_hat) + (1 - y) * np.log(1 - y_hat)) / len(y) except: return float(inf) def dJ(theta, X_b, y): return X_b.T.dot(self._sigmoid(X_b.dot(theta)) - y) / len(y) def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8): theta = initial_theta cur_iter = 0 while cur_iter < n_iters: gradient = dJ(theta, X_b, y) last_theta = theta theta = theta - eta * gradient if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon): break cur_iter += 1 return theta X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) initial_theta = np.zeros(X_b.shape[1]) self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters) self.intercept_ = self._theta[0] self.coef_ = self._theta[1:] return self def predict_proba(self, X_predict): """给定待预测数据集X_predict,返回表示X_predict的结果概率向量""" assert self.intercept_ is not None and self.coef_ is not None, "must fit before predict!" assert X_predict.shape[1] == len(self.coef_), "the feature number of X_predict must be equal to X_train" X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict]) return self._sigmoid(X_b.dot(self._theta)) def predict(self, X_predict): """给定待预测数据集X_predict,返回表示X_predict的结果向量""" assert self.intercept_ is not None and self.coef_ is not None, "must fit before predict!" assert X_predict.shape[1] == len(self.coef_), "the feature number of X_predict must be equal to X_train" proba = self.predict_proba(X_predict) return np.array(proba >= 0.5, dtype=int) def score(self, X_test, y_test): """根据测试数据集 X_test 和 y_test 确定当前模型的准确度""" y_predict = self.predict(X_test) return self.accuracy_score(y_test, y_predict) def __repr__(self): return "LogisticRegression()" # 准确率计算 def accuracy_score(y_true, y_predict): """计算y_true和y_predict之间的准确率""" assert len(y_true) == len(y_predict), "the size of y_true must be equal to the size of y_predict" return np.sum(y_true == y_predict) / len(y_true) 通过调用进行预测: import numpy as np from sklearn import datasets import LogisticRegression def train_test_split(X, y, test_ratio=0.2, seed=None): """将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test""" assert X.shape[0] == y.shape[0], "the size of X must be equal to the size of y" assert 0.0 <= test_ratio <= 1.0, "test_ration must be valid" if seed: np.random.seed(seed) shuffled_indexes = np.random.permutation(len(X)) test_size = int(len(X) * test_ratio) test_indexes = shuffled_indexes[:test_size] train_indexes = shuffled_indexes[test_size:] X_train = X[train_indexes] y_train = y[train_indexes] X_test = X[test_indexes] y_test = y[test_indexes] return X_train, X_test, y_train, y_test if __name__=="__main__": iris = datasets.load_iris() X = iris.data y = iris.target X_train, X_test, y_train, y_test = train_test_split(X, y, seed=666) log_reg = LogisticRegression() log_reg.fit(X_train, y_train) log_reg.score(X_test, y_test) log_reg.predict_proba(X_test) print(y_test) 在jupter上展示: 3 Pytorch 深度学习 3.1 numpy 1 保存数组 import numpy as np nd9 =np.random.random([5, 5]) np.savetxt(X=nd9, fname=./test1.txt) nd10 = np.loadtxt(./test1.txt) print(nd10) 2 numpy数组运算 3 修改数组的形状 4 展平 5 合并数组 6 批量处理 3.2 pytorch基础 1 测试 CUDA import torch print("Support CUDA ?: ", torch.cuda.is_available()) x = torch.tensor([10.0]) x = x.cuda() print(x) 2 add 3 torch.view与torch.reshpae的异同 4 矩阵计算 7 对照表 8 求导 9 使用Numpy实现机器学习 10 使用Tensor及antograd实现机器学习 11 使用TensorFlow架构 # -*- coding: utf-8 -*- import tensorflow as tf import numpy as np #生成训练数据 np.random.seed(100) x = np.linspace(-1, 1, 100).reshape(100,1) y = 3*np.power(x, 2) +2+ 0.2*np.random.rand(x.size).reshape(100,1) # 创建两个占位符,分别用来存放输入数据x和目标值y #运行计算图时,导入数据. x1 = tf.placeholder(tf.float32, shape=(None, 1)) y1 = tf.placeholder(tf.float32, shape=(None, 1)) # 创建权重变量w和b,并用随机值初始化. # TensorFlow 的变量在整个计算图保存其值. w = tf.Variable(tf.random_uniform([1], 0, 1.0)) b = tf.Variable(tf.zeros([1])) # 前向传播,计算预测值. y_pred = np.power(x,2)*w + b # 计算损失值 loss=tf.reduce_mean(tf.square(y-y_pred)) # 计算有关参数w、b关于损失函数的梯度. grad_w, grad_b = tf.gradients(loss, [w, b]) #用梯度下降法更新参数. # 执行计算图时给 new_w1 和new_w2 赋值 # 对TensorFlow 来说,更新参数是计算图的一部分内容 # 而PyTorch,这部分是属于计算图之外. learning_rate = 0.01 new_w = w.assign(w - learning_rate * grad_w) new_b = b.assign(b - learning_rate * grad_b) # 已构建计算图, 接下来创建TensorFlow session,准备执行计算图. with tf.Session() as sess: # 执行之前需要初始化变量w、b sess.run(tf.global_variables_initializer()) for step in range(2000): # 循环执行计算图. 每次需要把x1,y1赋给x和y. # 每次执行计算图时,需要计算关于new_w和new_b的损失值, # 返回numpy多维数组 loss_value, v_w, v_b = sess.run([loss, new_w, new_b], feed_dict={ x1: x, y1: y}) if step%200==0: #每200次打印一次训练结果 print("损失值、权重、偏移量分别为{:.4f},{},{}".format(loss_value,v_w,v_b)) # 可视化结果 plt.figure() plt.scatter(x,y) plt.plot (x, v_b + v_w*x**2)
  5. 我们了解什么叫大数据分析么? 麦肯锡给大数据定义: “一种规模大到在获取、存储、管理、分析方面大大超出了传统数据库软件工具能力范围的数据集合,具有海量的数据规模、快速的数据流转、多样的数据类型和价值密度低四大特征。“ 基于我对以上定义的理解,我总结的大数据分析就是,将获取的数据,打通,整合,找寻规律,立即得出决策信息。 数据获取 我总结的数据源可分类三类: (1)一方数据:用户事实数据 例如用户在某金融机构购买的理财产品,时间,哪个出单口,姓名,电话等,或者运营数据,例如某互联金融app,用户操作行为数据 (3)三方数据:行业数据,也叫公开数据 例如行协的数据,或者互联网行为数据,例如某互联网公司用户在此网站的行为数据,或者嵌入sdk的app后我们能采集到的安装活跃列表,以及可采集到线下数据。 打通:其实就是利用关键点的采集整合一二三方数据。例如我们可以通过手机号将一方和三方数据整合,或者利用cookie,或者imei号等将二方、三方数据整合。但是由于现在监管制度对手机号敏感数据的控制,以及互联网和移动端数据的跨平台打通技术难点,我们现实的匹配率很低,例如一方和三方的数据匹配达到20%其实就算比较不错的情况,当然运营商数据除外。 找寻规律:目标就是数据清理,从非结构化数据变成结构化数据,以便统计,数据探索,找寻规律,形成数据分析报告观点。本文将会在第三部分阐述。 立即决策:将数据分析报告中的观点系统化或产品化,目前而言,大部分公司还是会依靠人工决策。 为什么需要大数据分析?看上去大数据分析似乎按照这些步骤来,但是从第一步的数据源来说,其实已经反应了大数据的特点,就是杂乱无章,那么怎么从这些数据找寻规律,分析的内容和目标是否对应上,似乎就是我们需要大数据分析的理由 现在,大数据的分析通常采用的数据报表来反映企业运营状况,同时,对于热点,人群分析,我们看到的统计值,目标核心都是用数据分析报告提炼的观点来指导运营,那么问题来了,怎么用数据分析来指导数据决策呢? 数据分析的报告思路(本文从移动端的角度进行切入) 基于我对数据分析的理解,我将数据报告会分成三大类:市场分析、运营分析、用户行为分析。 市场分析 由于市场分析一般而言是定性、定量分析,最近热播剧《我的前半生》贺函和唐晶的职业就是来去咨询公司的一般会以访谈、问卷调查来一份市场分析报告去告诉客户他们的市场占有量,消费者观点等。 这里,我们以移动互联网数据的市场分析为例,通常来说,数据源是公开数据,或者在第三方数据。正如我们所讲,将sdk嵌入开发者应用,就可以收集到安装以及使用列表,那么开发者使用的sdk越多,我们能收集的数据源也越多,这样就可以形成安装app排名,使用app排名,这里面所说的覆盖率、活跃率也是这个意思,例如:即此款应用安装量、使用量在整体金融类的安装量、使用量占比。 同时,根据市场的走势图,我们能发现潜在的竞争对手,例如:我们能看出下图中的工商银行由于手机属于高覆盖高活跃组,即安装xxapp活跃人群也是最高的,因此,无疑xx银行是所有银行组潜在竞争对手。需要更加注意他们的市场策略 运营分析 移动互联网提出的方法论:3A3R,笔者之前在做咨询的时候,此方法论也可以将网站分析套用,总结来说3A3R就是: 感知 → 获取 → 活跃 → 获取 → 营收 → 传播 → 感知 这里需要注明下,运营分析只是一个公司的baseline,让产品经理,运营人员,市场人员根据自己本公司的数据参考做出合理的决定,同时,运营的数据只是参考或者叫警示,若要具体,需要特定细节的分析,例如是否app改版,怎么改?需要增加哪家渠道合作? (1)Awareness 感知 (2)Acquisition 获客 目的1:衡量第一步提供的数据是否准确,即是否渠道作弊 目的2:判断渠道是否好坏 目的3:判断营销活动是否有效 例如下图中,我们发现4成用户是搜索流量较上个月增加了6%,是不是我们需要增加和sem的合作呢?而在媒体引荐渠道中,我们通过渠道衡量客户转化率,点击-用户激活的,激活的注册转化,可否重点对某应用商店增加合作 (3)Activities 活跃 获客后,我们想看看我们的新增、活跃用户的表现情况,那么就到了第三步 活跃,其实就是为产品经理改版app或者页面提供数据支持 活跃分析可参考以下三个步骤: 第一:从页面浏览次数,独立访问人数,来圈定主要页面分析。 例如某款app首页是pv,uv最高,我们会重点分析首页。 第二:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 第三:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 (4)Retention留存分析& Revenue & Refer 这几个实际上在企业运用的并不多,这里简要说明下。 ① Retention 用户积累到一定数量后,我们想看下用户粘性,那么我们就来到retention,一般是衡量活动效果时候运用的比较多,来看此次活动过后,是否用户依旧会使用我们的app,但是由于金融app属性不会像游戏应用每天进行访问,因此Retention 在实际应用中不会太多,下面的例子是个展示,不做赘述 ② Revenue 这些留下来的客户给公司贡献多少现金呢?会看收入步骤, 一般公司不会将现金流数据放入在统计平台中,但是我们需要提出用户贡献的流水金额数据供我们使用,便于人群划分,例如下面简要分析: Refer 传播: 用户分析 若说大数据分析的核心,其实就是在于用户分析,正如我们前面所讲,用户分析的步骤流程如下: 即在力所能及的搜集数据范围内,打通数据,客户用户,精准营销。 第一,我们可以筛选的条件列表,我们可以通过应用条件,位置,标签条件将数据整合,整合的目的就是刻画客户,定出营销策略。 例如:我们想筛选金融客户(应用条件筛选),出现在五星级酒店(位置条件),且为母婴人群(标签) 但是需要注意的是,条件越多,用户轮廓越清晰,人群会越少。 第二,根据筛选的人群,我们将线上/线上统计化,或者建模多维度分析。 例如,我们根据筛选的人群,发现男性多于女性,苹果手机属性最高,常手机工具使用,那么我们可以将这部分目标人群用增加手机工具合作、或者和苹果合作获客或者促活。 第三,整合以上数据分析,形成人群画像。 结束语 这篇文章基于我多年数据分析的经验,总结的一体化数据分析框架,其实就是简单介绍下数据分析能分析能落地的几点。当然,这里面需要大量的数据清洗工作,以及对行业的认知,此篇只是从数据分析角度的概要,内容上的细化,其实可以单拿出来细细分析,尤其用户画像那章节。 我们了解什么叫大数据分析么? 麦肯锡给大数据定义: “一种规模大到在获取、存储、管理、分析方面大大超出了传统数据库软件工具能力范围的数据集合,具有海量的数据规模、快速的数据流转、多样的数据类型和价值密度低四大特征。“ 基于我对以上定义的理解,我总结的大数据分析就是,将获取的数据,打通,整合,找寻规律,立即得出决策信息。 数据获取 我总结的数据源可分类三类: (1)一方数据:用户事实数据 例如用户在某金融机构购买的理财产品,时间,哪个出单口,姓名,电话等,或者运营数据,例如某互联金融app,用户操作行为数据 (3)三方数据:行业数据,也叫公开数据 例如行协的数据,或者互联网行为数据,例如某互联网公司用户在此网站的行为数据,或者嵌入sdk的app后我们能采集到的安装活跃列表,以及可采集到线下数据。 打通:其实就是利用关键点的采集整合一二三方数据。例如我们可以通过手机号将一方和三方数据整合,或者利用cookie,或者imei号等将二方、三方数据整合。但是由于现在监管制度对手机号敏感数据的控制,以及互联网和移动端数据的跨平台打通技术难点,我们现实的匹配率很低,例如一方和三方的数据匹配达到20%其实就算比较不错的情况,当然运营商数据除外。 找寻规律:目标就是数据清理,从非结构化数据变成结构化数据,以便统计,数据探索,找寻规律,形成数据分析报告观点。本文将会在第三部分阐述。 立即决策:将数据分析报告中的观点系统化或产品化,目前而言,大部分公司还是会依靠人工决策。 为什么需要大数据分析?看上去大数据分析似乎按照这些步骤来,但是从第一步的数据源来说,其实已经反应了大数据的特点,就是杂乱无章,那么怎么从这些数据找寻规律,分析的内容和目标是否对应上,似乎就是我们需要大数据分析的理由 现在,大数据的分析通常采用的数据报表来反映企业运营状况,同时,对于热点,人群分析,我们看到的统计值,目标核心都是用数据分析报告提炼的观点来指导运营,那么问题来了,怎么用数据分析来指导数据决策呢? 数据分析的报告思路(本文从移动端的角度进行切入) 基于我对数据分析的理解,我将数据报告会分成三大类:市场分析、运营分析、用户行为分析。 市场分析 由于市场分析一般而言是定性、定量分析,最近热播剧《我的前半生》贺函和唐晶的职业就是来去咨询公司的一般会以访谈、问卷调查来一份市场分析报告去告诉客户他们的市场占有量,消费者观点等。 这里,我们以移动互联网数据的市场分析为例,通常来说,数据源是公开数据,或者在第三方数据。正如我们所讲,将sdk嵌入开发者应用,就可以收集到安装以及使用列表,那么开发者使用的sdk越多,我们能收集的数据源也越多,这样就可以形成安装app排名,使用app排名,这里面所说的覆盖率、活跃率也是这个意思,例如:即此款应用安装量、使用量在整体金融类的安装量、使用量占比。 同时,根据市场的走势图,我们能发现潜在的竞争对手,例如:我们能看出下图中的工商银行由于手机属于高覆盖高活跃组,即安装xxapp活跃人群也是最高的,因此,无疑xx银行是所有银行组潜在竞争对手。需要更加注意他们的市场策略 运营分析 移动互联网提出的方法论:3A3R,笔者之前在做咨询的时候,此方法论也可以将网站分析套用,总结来说3A3R就是: 感知 → 获取 → 活跃 → 获取 → 营收 → 传播 → 感知 这里需要注明下,运营分析只是一个公司的baseline,让产品经理,运营人员,市场人员根据自己本公司的数据参考做出合理的决定,同时,运营的数据只是参考或者叫警示,若要具体,需要特定细节的分析,例如是否app改版,怎么改?需要增加哪家渠道合作? (1)Awareness 感知 (2)Acquisition 获客 目的1:衡量第一步提供的数据是否准确,即是否渠道作弊 目的2:判断渠道是否好坏 目的3:判断营销活动是否有效 例如下图中,我们发现4成用户是搜索流量较上个月增加了6%,是不是我们需要增加和sem的合作呢?而在媒体引荐渠道中,我们通过渠道衡量客户转化率,点击-用户激活的,激活的注册转化,可否重点对某应用商店增加合作 (3)Activities 活跃 获客后,我们想看看我们的新增、活跃用户的表现情况,那么就到了第三步 活跃,其实就是为产品经理改版app或者页面提供数据支持 活跃分析可参考以下三个步骤: 第一:从页面浏览次数,独立访问人数,来圈定主要页面分析。 例如某款app首页是pv,uv最高,我们会重点分析首页。 第二:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 第三:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 (4)Retention留存分析& Revenue & Refer 这几个实际上在企业运用的并不多,这里简要说明下。 ① Retention 用户积累到一定数量后,我们想看下用户粘性,那么我们就来到retention,一般是衡量活动效果时候运用的比较多,来看此次活动过后,是否用户依旧会使用我们的app,但是由于金融app属性不会像游戏应用每天进行访问,因此Retention 在实际应用中不会太多,下面的例子是个展示,不做赘述 ② Revenue 这些留下来的客户给公司贡献多少现金呢?会看收入步骤, 一般公司不会将现金流数据放入在统计平台中,但是我们需要提出用户贡献的流水金额数据供我们使用,便于人群划分,例如下面简要分析: Refer 传播: 用户分析 若说大数据分析的核心,其实就是在于用户分析,正如我们前面所讲,用户分析的步骤流程如下: 即在力所能及的搜集数据范围内,打通数据,客户用户,精准营销。 第一,我们可以筛选的条件列表,我们可以通过应用条件,位置,标签条件将数据整合,整合的目的就是刻画客户,定出营销策略。 例如:我们想筛选金融客户(应用条件筛选),出现在五星级酒店(位置条件),且为母婴人群(标签) 但是需要注意的是,条件越多,用户轮廓越清晰,人群会越少。 第二,根据筛选的人群,我们将线上/线上统计化,或者建模多维度分析。 例如,我们根据筛选的人群,发现男性多于女性,苹果手机属性最高,常手机工具使用,那么我们可以将这部分目标人群用增加手机工具合作、或者和苹果合作获客或者促活。 第三,整合以上数据分析,形成人群画像。 结束语 这篇文章基于我多年数据分析的经验,总结的一体化数据分析框架,其实就是简单介绍下数据分析能分析能落地的几点。当然,这里面需要大量的数据清洗工作,以及对行业的认知,此篇只是从数据分析角度的概要,内容上的细化,其实可以单拿出来细细分析,尤其用户画像那章节。 我们了解什么叫大数据分析么? 麦肯锡给大数据定义: “一种规模大到在获取、存储、管理、分析方面大大超出了传统数据库软件工具能力范围的数据集合,具有海量的数据规模、快速的数据流转、多样的数据类型和价值密度低四大特征。“ 基于我对以上定义的理解,我总结的大数据分析就是,将获取的数据,打通,整合,找寻规律,立即得出决策信息。 数据获取 我总结的数据源可分类三类: (1)一方数据:用户事实数据 例如用户在某金融机构购买的理财产品,时间,哪个出单口,姓名,电话等,或者运营数据,例如某互联金融app,用户操作行为数据 (3)三方数据:行业数据,也叫公开数据 例如行协的数据,或者互联网行为数据,例如某互联网公司用户在此网站的行为数据,或者嵌入sdk的app后我们能采集到的安装活跃列表,以及可采集到线下数据。 打通:其实就是利用关键点的采集整合一二三方数据。例如我们可以通过手机号将一方和三方数据整合,或者利用cookie,或者imei号等将二方、三方数据整合。但是由于现在监管制度对手机号敏感数据的控制,以及互联网和移动端数据的跨平台打通技术难点,我们现实的匹配率很低,例如一方和三方的数据匹配达到20%其实就算比较不错的情况,当然运营商数据除外。 找寻规律:目标就是数据清理,从非结构化数据变成结构化数据,以便统计,数据探索,找寻规律,形成数据分析报告观点。本文将会在第三部分阐述。 立即决策:将数据分析报告中的观点系统化或产品化,目前而言,大部分公司还是会依靠人工决策。 为什么需要大数据分析?看上去大数据分析似乎按照这些步骤来,但是从第一步的数据源来说,其实已经反应了大数据的特点,就是杂乱无章,那么怎么从这些数据找寻规律,分析的内容和目标是否对应上,似乎就是我们需要大数据分析的理由 现在,大数据的分析通常采用的数据报表来反映企业运营状况,同时,对于热点,人群分析,我们看到的统计值,目标核心都是用数据分析报告提炼的观点来指导运营,那么问题来了,怎么用数据分析来指导数据决策呢? 数据分析的报告思路(本文从移动端的角度进行切入) 基于我对数据分析的理解,我将数据报告会分成三大类:市场分析、运营分析、用户行为分析。 市场分析 由于市场分析一般而言是定性、定量分析,最近热播剧《我的前半生》贺函和唐晶的职业就是来去咨询公司的一般会以访谈、问卷调查来一份市场分析报告去告诉客户他们的市场占有量,消费者观点等。 这里,我们以移动互联网数据的市场分析为例,通常来说,数据源是公开数据,或者在第三方数据。正如我们所讲,将sdk嵌入开发者应用,就可以收集到安装以及使用列表,那么开发者使用的sdk越多,我们能收集的数据源也越多,这样就可以形成安装app排名,使用app排名,这里面所说的覆盖率、活跃率也是这个意思,例如:即此款应用安装量、使用量在整体金融类的安装量、使用量占比。 同时,根据市场的走势图,我们能发现潜在的竞争对手,例如:我们能看出下图中的工商银行由于手机属于高覆盖高活跃组,即安装xxapp活跃人群也是最高的,因此,无疑xx银行是所有银行组潜在竞争对手。需要更加注意他们的市场策略 运营分析 移动互联网提出的方法论:3A3R,笔者之前在做咨询的时候,此方法论也可以将网站分析套用,总结来说3A3R就是: 感知 → 获取 → 活跃 → 获取 → 营收 → 传播 → 感知 这里需要注明下,运营分析只是一个公司的baseline,让产品经理,运营人员,市场人员根据自己本公司的数据参考做出合理的决定,同时,运营的数据只是参考或者叫警示,若要具体,需要特定细节的分析,例如是否app改版,怎么改?需要增加哪家渠道合作? (1)Awareness 感知 (2)Acquisition 获客 目的1:衡量第一步提供的数据是否准确,即是否渠道作弊 目的2:判断渠道是否好坏 目的3:判断营销活动是否有效 例如下图中,我们发现4成用户是搜索流量较上个月增加了6%,是不是我们需要增加和sem的合作呢?而在媒体引荐渠道中,我们通过渠道衡量客户转化率,点击-用户激活的,激活的注册转化,可否重点对某应用商店增加合作 (3)Activities 活跃 获客后,我们想看看我们的新增、活跃用户的表现情况,那么就到了第三步 活跃,其实就是为产品经理改版app或者页面提供数据支持 活跃分析可参考以下三个步骤: 第一:从页面浏览次数,独立访问人数,来圈定主要页面分析。 例如某款app首页是pv,uv最高,我们会重点分析首页。 第二:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 第三:根据圈定页面,制作点击热力图,便于产品经理对后续页面改造提供数据支持,例如我们可以将点击量小的按钮在下次改版删除,对点击量大的重新排序 (4)Retention留存分析& Revenue & Refer 这几个实际上在企业运用的并不多,这里简要说明下。 ① Retention 用户积累到一定数量后,我们想看下用户粘性,那么我们就来到retention,一般是衡量活动效果时候运用的比较多,来看此次活动过后,是否用户依旧会使用我们的app,但是由于金融app属性不会像游戏应用每天进行访问,因此Retention 在实际应用中不会太多,下面的例子是个展示,不做赘述 ② Revenue 这些留下来的客户给公司贡献多少现金呢?会看收入步骤, 一般公司不会将现金流数据放入在统计平台中,但是我们需要提出用户贡献的流水金额数据供我们使用,便于人群划分,例如下面简要分析: Refer 传播: 用户分析 若说大数据分析的核心,其实就是在于用户分析,正如我们前面所讲,用户分析的步骤流程如下: 即在力所能及的搜集数据范围内,打通数据,客户用户,精准营销。 第一,我们可以筛选的条件列表,我们可以通过应用条件,位置,标签条件将数据整合,整合的目的就是刻画客户,定出营销策略。 例如:我们想筛选金融客户(应用条件筛选),出现在五星级酒店(位置条件),且为母婴人群(标签) 但是需要注意的是,条件越多,用户轮廓越清晰,人群会越少。 第二,根据筛选的人群,我们将线上/线上统计化,或者建模多维度分析。 例如,我们根据筛选的人群,发现男性多于女性,苹果手机属性最高,常手机工具使用,那么我们可以将这部分目标人群用增加手机工具合作、或者和苹果合作获客或者促活。 第三,整合以上数据分析,形成人群画像。 结束语 这篇文章基于我多年数据分析的经验,总结的一体化数据分析框架,其实就是简单介绍下数据分析能分析能落地的几点。当然,这里面需要大量的数据清洗工作,以及对行业的认知,此篇只是从数据分析角度的概要,内容上的细化,其实可以单拿出来细细分析,尤其用户画像那章节。
  6. 数据库加密字段的模糊搜索 This post was originally published on the and reposted here with their permission. 该帖子最初发布在并在获得其许可的情况下在此处重新发布。 We [ParagonIE] get asked the same question a lot (or some remix of it). 我们[ParagonIE]经常被问到相同的问题(或对其进行一些混音)。 This question shows up from time to time in . This was one of the “weird problems” covered in (titled Building Defensible Solutions to Weird Problems), and we’ve previously dedicated a small section to it in . 这个问题会不时出现在 。 这是 提到的“怪异问题”之一(标题为“ 为怪异问题构建防御解决方案” ),我们以前在专门针对了其中一小部分。 You know how to , but the question is, How do we securely encrypt database fields but still use these fields in search queries? 您知道如何 ,但问题是, 我们如何安全地加密数据库字段,但仍在搜索查询中使用这些字段? Our secure solution is rather straightforward, but the path between most teams asking that question and discovering our straightforward solution is fraught with peril: bad designs, academic research projects, misleading marketing, and poor . 我们的安全解决方案相当简单,但是大多数团队在提出问题和发现我们的简单解决方案之间的道路充满着危险:不良的设计,学术研究项目,误导性的营销以及不良的 。 If you’re in a hurry, feel free to . 如果您很着急,请随时 。 迈向可搜索的加密 (Towards Searchable Encryption) Let’s start with a simple scenario (which might be particularly relevant for a lot of local government or health care applications): 让我们从一个简单的场景开始(这可能与许多地方政府或医疗保健应用特别相关): You are building a new system that needs to collect social security numbers (SSNs) from its users. 您正在构建一个新系统,该系统需要从其用户那里收集社会保险号(SSN)。 Regulations and common sense both dictate that users’ SSNs should be encrypted at rest. 法规和常识都规定用户的SSN应该在静止状态下进行加密。 Staff members will need to be able to look up users’ accounts, given their SSN. 给定用户的SSN,工作人员将需要能够查找用户的帐户。 Let’s first explore the flaws with the obvious answers to this problem. 首先,让我们用明显的答案来解决这些缺陷。 不安全(或其他不良建议)的答案 (Insecure (or otherwise ill-advised) Answers) 非随机加密 (Non-randomized Encryption) The most obvious answer to most teams (particularly teams that don’t have security or cryptography experts) would be to do something like this: 对于大多数团队(特别是没有安全性或加密专家的团队),最明显的答案是这样做: <?php class InsecureExampleOne { protected $db; protected $key; public function __construct(PDO $db, string $key = ) { $this->db = $db; $this->key = $key; } public function searchByValue(string $query): array { $stmt = $this->db->prepare(SELECT * FROM table WHERE column = ?); $stmt->execute([ $this->insecureEncryptDoNotUse($query) ]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } protected function insecureEncryptDoNotUse(string $plaintext): string { return in2hex( openssl_encrypt( $plaintext, aes-128-ecb, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING ) ); } } In the above snippet, the same plaintext always produces the same ciphertext when encrypted with the same key. But more concerning with ECB mode is that every 16-byte chunk is , which can have some . 在以上代码段中,当使用相同的密钥加密时,相同的明文始终会产生相同的密文。 但是,与ECB模式有关的更多问题是,每个16字节的块分别进行了 ,这可能会带来一些 。 Formally, these constructions are not semantically secure: If you encrypt a large message, you will see blocks repeat in the ciphertext. 形式上,这些构造在语义上不是安全的:如果对大消息进行加密,则会在密文中看到块重复。 In order to be secure, encryption must be indistinguishable from random noise to anyone that does not hold the decryption key. Insecure modes include ECB mode and CBC mode with a static (or empty) IV. 为了安全起见,对于不持有解密密钥的任何人,加密必须与随机噪声没有区别。 不安全模式包括带有静态(或空)IV的ECB模式和CBC模式。 You want non-deterministic encryption, which means each message uses a unique nonce or initialization vector that never repeats for a given key. 您需要非确定性加密,这意味着每条消息都使用一个唯一的随机数或初始化矢量,该矢量永远不会重复给定密钥。 实验性学术设计 (Experimental Academic Designs) There is a lot of academic research going into such topics as , , and encryption techniques. 有很多学术研究涉及 , 和加密技术等主题。 As interesting as this work is, the current designs are nowhere near secure enough to use in a production environment. 尽管这项工作很有趣,但是当前的设计远没有足够的安全性可以在生产环境中使用。 For example, . 例如, 。 Homomorphic encryption schemes are often repackaging vulnerabilities (practical chosen-ciphertext attacks) as features. 同态加密方案通常将漏洞(实用的选择密文攻击)重新打包为功能。 Unpadded RSA is homomorphic . 填充的RSA是同态的。 If you multiply a ciphertext by an integer, the plaintext you get will be equal to the original message multiplied by the same integer. There are , which is why RSA in the real world uses padding (although often ). 如果将密文乘以整数,则得到的明文将等于原始消息乘以相同的整数。 填充的RSA有 ,这就是为什么RSA在现实世界中使用填充(尽管通常 )的原因。 Unpadded RSA is homomorphic . 填充的RSA是同态的。 AES in Counter Mode is homomorphic . 计数器模式下的AES 是同态的。 This is why nonce-reuse defeats the confidentiality of your message in CTR mode (and non-NMR stream ciphers in general). 这就是为什么随机数重用会破坏您在CTR模式下(通常是非NMR流密码)机密性的原因。 AES in Counter Mode is homomorphic . 计数器模式下的AES 是同态的。 As we’ve covered , when it comes to real-world cryptography, confidentiality without integrity is the same as no confidentiality. What happens if an attacker gains access to the database, alters ciphertexts, and studies the behavior of the application upon decryption? 正如我们 ,当涉及到现实世界的加密时, 没有完整性的机密就等于没有机密性 。 如果攻击者获得对数据库的访问权,更改密文并在解密后研究应用程序的行为,会发生什么? There’s potential for ongoing cryptography research to one day produce an innovative encryption design that doesn’t undo decades of research into safe cryptography primitives and cryptographic protocol designs. However, we’re not there yet, and you don’t need to invest into a needlessly complicated research prototype to solve the problem. 正在进行的密码学研究有一天有可能产生一种创新的加密设计,这种设计不会撤销对安全密码学原语和密码协议设计的数十年研究。 但是,我们还不存在,您不需要投资不必要的复杂研究原型来解决问题。 丢人的提法:解密每一行 (Dishonorable Mention: Decrypt Every Row) I don’t expect most engineers to arrive at this solution without a trace of sarcasm. The bad idea here is, because you need secure encryption (see below), your only recourse is to query every ciphertext in the database and then iterate through them, decrypting them one-by-one and performing your search operation in the application code. 我不希望大多数工程师都能毫不讽刺地提出这个解决方案。 这里的一个坏主意是,因为需要安全加密(请参见下文),所以唯一的办法就是查询数据库中的每个密文,然后对其进行遍历,然后将其解密,然后对它们进行解密,然后在应用程序代码中执行搜索操作。 If you go down this route, you will open your application to denial of service attacks. It will be slow for your legitimate users. This is a cynic’s answer, and you can do much better than that, as we’ll demonstrate below. 如果沿着这条路线走,您将打开应用程序以拒绝服务攻击。 对于您的合法用户,这将很慢。 这是一个愤世嫉俗的答案,您可以做的比这更好,我们将在下面演示。 安全的可搜索加密变得轻松 (Secure Searchable Encryption Made Easy) Let’s start by avoiding all the problems outlined in the insecure/ill-advised section in one fell swoop: All ciphertexts will be the result of an authenticated encryption scheme, preferably with large nonces (generated from a ). 让我们一口气避免不安全/不明智的部分中概述的所有问题:所有密文都是经过身份验证的加密方案的结果,最好是使用大随机数(由 )。 With an authenticated encryption scheme, ciphertexts are non-deterministic (same message and key, but different nonce, yields a different ciphertext) and protected by an authentication tag. Some suitable options include: XSalsa20-Poly1305, XChacha20-Poly1305, and (assuming it’s not broken before CAESAR concludes) NORX64-4-1. If you’re using NaCl or libsodium, you can just use crypto_secretbox here. 使用经过身份验证的加密方案,密文是不确定的(相同的消息和密钥,但是不同的随机数,会产生不同的密文),并且受身份验证标签保护。 一些合适的选项包括:XSalsa20-Poly1305,XChacha20-Poly1305,以及(假设在CAESAR得出结论之前没有损坏)NORX64-4-1。 如果您使用的是NaCl或libsodium,则可以在此处使用crypto_secretbox 。 Consequently, our ciphertexts are indistinguishable from random noise, and protected against chosen-ciphertext attacks. That’s how secure, boring encryption ought to be. 因此,我们的密文与随机噪声是无法区分的 ,并且可以防止选择密文攻击 。 那应该是多么安全,无聊的加密。 However, this presents an immediate challenge: We can’t just encrypt arbitrary messages and query the database for matching ciphertexts. Fortunately, there is a clever workaround. 但是,这提出了直接的挑战:我们不能只加密任意消息并查询数据库以查找匹配的密文。 幸运的是,有一个聪明的解决方法。 重要提示:威胁模型您的加密使用情况 (Important: Threat Model Your Usage of Encryption) Before you begin, make sure that encryption is actually making your data safer. It is important to emphasize that “encrypted storage” isn’t the solution to securing a CRUD app that’s vulnerable to SQL injection. Solving the actual problem (i.e. ) is the only way to go. 在开始之前,请确保加密实际上使您的数据更安全。 需要强调的是,“加密存储”并不是保护易受SQL注入攻击的CRUD应用程序的解决方案。 解决实际问题(即 )是唯一的方法。 If encryption is a suitable security control to implement, this implies that the cryptographic keys used to encrypt/decrypt data are not accessible to the database software. In most cases, it makes sense to keep the application server and database server on separate hardware. 如果加密是要实施的合适安全控制措施,则意味着用于加密/解密数据的加密密钥不可被数据库软件访问。 在大多数情况下,将应用程序服务器和数据库服务器保持在单独的硬件上是有意义的。 实施加密数据的文字搜索 (Implementing Literal Search of Encrypted Data) Possible use-case: Storing social security numbers, but still being able to query them. 可能的用例:存储社会安全号码,但仍然能够查询它们。 In order to store encrypted information and still use the plaintext in SELECT queries, we’re going to follow a strategy we call blind indexing. The general idea is to store a keyed hash (e.g. HMAC) of the plaintext in a separate column. It is important that the blind index key be distinct from the encryption key and unknown to the database server. 为了存储加密信息并仍在SELECT查询中使用纯文本,我们将遵循一种称为盲索引的策略。 一般想法是将明文的键控哈希(例如HMAC)存储在单独的列中。 重要的是,盲索引密钥必须与加密密钥不同,并且数据库服务器不知道。 For very sensitive information, instead of a simple HMAC, you will want to use a key-stretching algorithm (PBKDF2-SHA256, scrypt, Argon2) with the key acting as a static salt, to slow down attempts at enumeration. We aren’t worried about offline brute-force attacks in either case, unless an attacker can obtain the key (which must not stored in the database). 对于非常敏感的信息,而不是简单的HMAC,您将希望使用键拉伸算法(PBKDF2-SHA256,scrypt,Argon2),并将键用作静态盐,以减慢枚举的尝试。 在任何一种情况下,我们都不必担心脱机暴力攻击,除非攻击者可以获得密钥(密钥不能存储在数据库中)。 So if your table schema looks like this (in PostgreSQL flavor): 因此,如果您的表模式如下所示(采用PostgreSQL风格): CREATE TABLE humans ( humanid BIGSERIAL PRIMARY KEY, first_name TEXT, last_name TEXT, ssn TEXT, /* encrypted */ ssn_bidx TEXT /* blind index */ ); CREATE INDEX ON humans (ssn_bidx); You would store the encrypted value in humans.ssn. A blind index of the plaintext SSN would go into humans.ssn_bidx. A naive implementation might look like this: 您将把加密后的值存储在humans.ssn 。 明文SSN的盲索引将进入humans.ssn_bidx 。 天真的实现可能看起来像这样: <?php /* This is not production-quality code. * Its optimized for readability and understanding, not security. */ function encryptSSN(string $ssn, string $key): string { $nonce = random_bytes(24); $ciphertext = sodium_crypto_secretbox($ssn, $nonce, $key); return bin2hex($nonce . $ciphertext); } function decryptSSN(string $ciphertext, string $key): string { $decoded = hex2bin($ciphertext); $nonce = mb_substr($decoded, 0, 24, 8bit); $cipher = mb_substr($decoded, 24, null, 8bit); return sodium_crypto_secretbox_open($cipher, $nonce, $key); } function getSSNBlindIndex(string $ssn, string $indexKey): string { return bin2hex( sodium_crypto_pwhash( 32, $ssn, $indexKey, SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE, SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE ) ); } function findHumanBySSN(PDO $db, string $ssn, string $indexKey): array { $index = getSSNBlindIndex($ssn, $indexKey); $stmt = $db->prepare(SELECT * FROM humans WHERE ssn_bidx = ?); $stmt->execute([$index]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } A more comprehensive proof-of-concept is included in the . It’s released under the Creative Commons CC0 license, which for most people means the same thing as “public domain”. 中的包含更全面的概念证明。 它是根据知识共享CC0许可证发布的,对于大多数人来说,该许可证与“公共领域”具有相同的含义。 安全分析和局限性 (Security Analysis and Limitations) Depending on your exact threat model, this solution leaves two questions that must be answered before it can be adopted: 根据您的确切威胁模型,此解决方案留下两个必须采用的问题,然后才能被采用: Is it safe to use, or does it leak data like a sieve? 使用安全吗,还是像筛子一样泄漏数据? What are the limitations on its usefulness? (This one is sort of answered already.) 其用途有哪些限制? (这个已经回答了。) Given our example above, assuming your encryption key and your blind index key are separate, both keys are stored in the webserver, and the database server doesn’t have any way of obtaining these keys, then any attacker that only compromises the database server (but not the web server) will only be able to learn if several rows share a social security number, but not what the shared SSN is. This duplicate entry leak is necessary in order for indexing to be possible, which in turn allows fast SELECT queries from a user-provided value. 在上面的示例中,假设您的加密密钥和盲索引密钥是分开的,两个密钥都存储在Web服务器中,并且数据库服务器没有任何获取这些密钥的方式,那么任何只会破坏数据库服务器的攻击者( (而不是Web服务器)将只能知道是否有几行共享一个社会保险号,而不是共享的SSN是什么。 为了使索引成为可能,此重复的条目泄漏是必需的,这反过来又允许从用户提供的值进行快速的SELECT查询。 Furthermore, if an attacker is capable of both observing/changing plaintexts as a normal user of the application while observing the blind indices stored in the database, they can leverage this into a chosen-plaintext attack, where they iterate every possible value as a user and then correlate with the resultant blind index value. This is more practical in the HMAC scenario than in the e.g. Argon2 scenario. For high-entropy or low-sensitivity values (not SSNs), can be on our side. 此外,如果攻击者既可以作为应用程序的普通用户来观察/更改纯文本,又可以观察数据库中存储的盲索引,则他们可以将其利用为选择明文攻击 ,在这种情况下,他们以用户身份遍历每个可能的值。然后与所得的盲指标值相关。 这在HMAC方案中比在例如Argon2方案中更实用。 对于高熵或低灵敏度值(不是SSN), 可以在我们这一边。 A much more practical attack for such a criminal would be to substitute values from one row to another then access the application normally, which will reveal the plaintext unless a distinct per-row key was employed (e.g. hash_hmac(sha256, $rowID, $masterKey, true) could even be an effective mitigation here, although others would be preferable). The best defense here is to use an AEAD mode (passing the primary key as additional associated data) so that the ciphertexts are tied to a particular database row. (This will not prevent attackers from deleting data, which is .) 对于这样的犯罪分子,更实际的攻击是将值从一行替换为另一行,然后正常访问应用程序, 除非使用不同的逐行密钥(例如hash_hmac(sha256, $rowID, $masterKey, true)甚至可以在这里hash_hmac(sha256, $rowID, $masterKey, true)有效的缓解作用,尽管其他方式更可取)。 最好的防御方法是使用AEAD模式(将主键作为附加关联数据传递),以便将密文绑定到特定的数据库行。 (这不会阻止攻击者删除数据,这是 。) Compared to the amount of information leaked by other solutions, most applications’ threat models should find this to be an acceptable trade-off. As long as you’re using authenticated encryption for encryption, and either HMAC (for blind indexing non-sensitive data) or a (for blind indexing sensitive data), it’s easy to reason about the security of your application. 与其他解决方案泄漏的信息量相比,大多数应用程序的威胁模型应该认为这是可以接受的折衷方案。 只要您使用经过身份验证的加密进行加密,并且使用HMAC(用于对非敏感数据进行盲索引)或 (用于对敏感数据进行盲索引),就很容易推断出应用程序的安全性。 However, it does have one very serious limitation: It only works for exact matches. If two strings differ in a meaningless way but will always produce a different cryptographic hash, then searching for one will never yield the other. If you need to do more advanced queries, but still want to keep your decryption keys and plaintext values out of the hands of the database server, we’re going to have to get creative. 但是,它确实有一个非常严重的局限性:它仅适用于完全匹配。 如果两个字符串毫无意义地不同,但始终会产生不同的密码哈希,那么搜索一个字符串将永远不会产生另一个字符串。 如果您需要执行更高级的查询,但仍然希望使解密密钥和纯文本值不受数据库服务器的影响,我们将必须发挥创意。 It is also worth noting that, while HMAC/Argon2 can prevent attackers that do not possess the key from learning the plaintext values of what is stored in the database, it might reveal metadata (e.g. two seemingly-unrelated people share a street address) about the real world. 还值得注意的是,尽管HMAC / Argon2可以阻止不掌握密钥的攻击者了解数据库中存储内容的明文值,但它可能会泄露有关以下内容的元数据(例如,两个看似无关的人共享街道地址)现实中。 实施模糊搜索以加密数据 (Implementing Fuzzier Searching for Encrypted Data) Possible use-case: Encrypting peoples’ legal names, and being able to search with only partial matches. 可能的用例:加密人们的法定姓名,并且仅能进行部分匹配来进行搜索。 Let’s build on the previous section, where we built a blind index that allows you to query the database for exact matches. 让我们在上一节的基础上进行构建,在上一节中,我们建立了一个盲目索引,该索引使您可以查询数据库中的精确匹配项。 This time, instead of adding columns to the existing table, we’re going to store extra index values into a join table. 这次,我们不是将列添加到现有表中,而是将额外的索引值存储到联接表中。 CREATE TABLE humans ( humanid BIGSERIAL PRIMARY KEY, first_name TEXT, /* encrypted */ last_name TEXT, /* encrypted */ ssn TEXT, /* encrypted */ ); CREATE TABLE humans_filters ( filterid BIGSERIAL PRIMARY KEY, humanid BIGINT REFERENCES humans (humanid), filter_label TEXT, filter_value TEXT ); /* Creates an index on the pair. If your SQL expert overrules this, feel free to omit it. */ CREATE INDEX ON humans_filters (filter_label, filter_value); The reason for this change is to normalize our data structures. You can get by with just adding columns to the existing table, but it’s likely to get messy. 进行此更改的原因是为了规范化我们的数据结构。 您只需在现有表中添加列即可解决问题,但这很可能会变得凌乱。 The next change is that we’re going to store a separate, distinct blind index per column for every different kind of query we need (each with its own key). For example: 下一个更改是,我们将为所需的每种不同类型的查询(每个都有自己的键)在每列存储一个单独的,不同的盲索引。 例如: Need a case-insensitive lookup that ignores whitespace? 是否需要忽略空格的不区分大小写的查找? Store a blind index of preg_replace(/[^a-z]/, , strtolower($value)). 存储preg_replace(/[^az]/, , strtolower($value))的盲索引。 Need to query the first letter of their last name? 是否需要查询其姓氏的首字母? Store a blind index of strtolower(mb_substr($lastName, 0, 1, $locale)). 存储strtolower(mb_substr($lastName, 0, 1, $locale))的盲索引。 Need to match “beings with this letter, ends with that letter”? 是否需要匹配“以这个字母存在,以那个字母结尾”? Store a blind index of strtolower($string[0] . $string[-1]). 存储strtolower($string[0] . $string[-1])的盲索引。 Need to query the first three letters of their last name and the first letter of their first name? 需要查询姓氏的前三个字母和姓氏的第一个字母吗? You guessed it! Build another index based on partial data. 你猜到了! 基于部分数据构建另一个索引。 Every index needs to have a distinct key, and great pains should be taken to prevent blind indices of subsets of the plaintext from leaking real plaintext values to a criminal with a knack for crossword puzzles. Only create indexes for serious business needs, and log access to these parts of your application aggressively. 每个索引都需要有一个独特的键,并且应该竭尽全力以防止明文子集的盲目索引将真实的明文值泄漏给具有填字游戏难题的犯罪分子。 仅创建满足严重业务需求的索引,并积极记录对应用程序这些部分的访问。 交易时间记忆 (Trading Memory for Time) Thus far, all of the design propositions have been in favor of allowing developers to write carefully considered SELECT queries, while minimizing the number of times the decryption subroutine is invoked. Generally, that is where the train stops and most peoples’ goals have been met. 到目前为止,所有设计主张都支持允许开发人员编写经过仔细考虑的SELECT查询,同时最大程度地减少解密子例程的调用次数。 通常,这是火车停下来的地方,大多数人的目标已经实现。 However, there are situations where a mild performance hit in search queries is acceptable if it means saving a lot of disk space. 但是,在某些情况下,如果这意味着节省大量磁盘空间,则在搜索查询中出现性能下降的情况是可以接受的。 The trick here is simple: Truncate your blind indexes to e.g. 16, 32, or 64 bits, and treat them as a : 这里的技巧很简单:将盲索引截断为16、32或64位,然后将它们视为 : If the blind indices involved in the query match a given row, the data is probably a match. 如果查询中涉及的盲索引匹配给定的行,则数据可能是匹配的。 Your application code will need to perform the decryption for each candidate row and then only serve the actual matches. 您的应用程序代码将需要为每个候选行执行解密,然后仅提供实际的匹配项。 If the blind indices involved in the query match a given row, the data is probably a match. 如果查询中涉及的盲索引匹配给定的行,则数据可能是匹配的。 If the blind indices involved in the query do not match a given row, then the data is definitely not a match. 如果查询中涉及的盲索引与给定行不匹配,则该数据绝对不是匹配项。 It may also be worth converting these values from a string to an integer, if your database server will end up storing it more efficiently. 如果您的数据库服务器最终将更有效地存储这些值,那么也可能需要将这些值从字符串转换为整数。 结论 (Conclusion) I hope I’ve adequately demonstrated that it is not only possible to build a system that uses secure encryption while allowing fast queries (with minimal information leakage against very privileged attackers), but that it’s possible to build such a system simply, out of the components provided by modern cryptography libraries with very little glue. 我希望我已经充分证明了,不仅可以构建一个使用安全加密同时允许快速查询的系统(对特权较高的攻击者的信息泄漏最少),而且还可以简单地构建一个这样的系统,现代密码学库提供的几乎不需要胶水的组件。 If you’re interested in implementing encrypted database storage into your software, we’d love to provide you and your company with our consulting services. if you’re interested.
  7. 前言 我们在进行网络通信时,需要数据包在不同网络设备之间传输。这个过程就需要数据包进行封装与解封装。 一、数据封装与解封装过程 1.1、数据封装过程 应用层传输过程: 在应用层,数据“翻译”为网络世界使用的语音——二进制编码数据。 传输层传输过程: 在传输层,上层数据被分割成小的数据段,并为每个分段后的数据封装TCP报文头部。在TCP头部有一个关键的字段信息——端口号,他用于标识上层的协议或应用程序,确保上层应用数据的正常通信。 网络层传输过程: 在网络层,上层数据被封装上新的报文头部——IP头部。(这里所说的上层数据包括TCP头部。) 数据链路层传输过程: 在数据链路层,上层数据被封装一个MAC头部,其内部有一个关键的字段信息——MAC地址。 物理层传输过程: 无论是之前每一层封装的头部还是上层数据信息都是由二进制组成的,物理层将这些二进制数字组成的比特流转换成电信号在网络中传输。 封装过程图示: 1. 2、数据解封装过程 数据被封装完毕通过网络传输到接收方后,将进入的数据解封装,这将是封装过程的一个逆过程。 如图示: 1.3、相关数据传输的一些基本概念 1.3.1 PDU图示 PDU——协议数据单元 PDU是指同层之间传递的数据单位。 应用层:消息/报文(上层数据)。 传输层:数据段(TCP头部、上层数据)。 网络层:数据包(IP头部、TCP头部、上层数据)。 数据链路层:数据帧(MAC头部、IP头部、TCP头部、上层数据) 物理层:比特流 PDU图示: 1. 3.2 常见硬件设备与五层模型的对应关系层名称 应用层 传输层 网络层 数据链路层 物理层 典型设备 计算机 防火墙 路由器 交换机 网卡 二、数据封装与解封装过程 首先要明确一个问题,发送方与接收方各层必须采用相同的协议才能建立连接,实现正常的通信。 如图示: 总结 综上所述,数据封装与解封装在网络通信中占据非常重要的地位。
  8. NLP学习路线 开始记录学习nlp,学习路线参考博主的建议,后续把这部分的内容进行整理。 前言要学好NLP,下面3个是缺一不可的: 1. 机器学习基础 人工智能很多技术和模块是搭建在机器学习基础上的,无论是CV,NLP,语音识别。可以直接去学习一个方向,也能学到东西。 但是可能不能很好的理解技术和模型背后的细节。 2. 数据结构与算法 在工程上写一个算法,如果不懂数据结构和算法,写出来的程序可能效率不高,达不到上线的要求。所以要懂数据结构和算法,才能写出最优化,性能高的程序。 3. 良好的编程基础 有良好的编程基础才能写出好的程序,不只是会讲讲理论,还能够实现出来,达到落地的地步。 在有了上面的基础后,学完自然语言的基础知识。然后需要在NLP里选择一个技术路线或者应用领域。比如预训练模型BERT,图神经网络。或者选择一个领域,智能对话系统,自然语言生成等,在某一个领域深入下去,把领域内的方方面面知识点都搞明白能够串起来。我们要使自己成为一个T字型的人才,有一个的知识的宽度,同时一定要在某方面有深度。 同时我们要养成读论文的习惯,比如在工作中突然来了一个新的需求,这时候就需要去读读论文,看看别人的思路,做一个baseline出来,然后再此基础上进行改进。 1、自然语言处理 自然语言处理 = Natural Language Processing = NLP 自然语言理解 = Natural Language Understanding = NLU = 理解文本中的意思 自然语言生成 = Natural Language Generation = NLG = 根据意思生成文本 例1) 一个人在看百度贴吧看帖子的时候, 首先是看帖子,这是一个理解文本内容(NLU)的过程, 然后回答帖子,这是一个生成文本(NLG)的过程。 例2) 人类在语言交流的时候 1) 听到对方的声音讯号, 根据从小学习的语文, 转换成一串文字。 (语音识别) 2) 对这段文字进行理解。 (NLU) 3) 回复对方。 (NLG) 1.1 为什么自然语言处理难? 图片:所见即所得。 文字:看到的是文字,要理解背后的含义。 1) CV的图像,一眼看过去,图片内容很直观明了。比如图片中一只狗在追一只猫,看图片就知道内容,很少有要揣摩图片意思的应用场景, 基本都是图片分类,目标检测等。 2) 自然语言的理解,想想我们从小学习的古诗还有阅读理解,要进行前后文内容的结合,才能回答问题; 还有一词多义, 一句多义等。 还有一个场景,有人突然说了一句话,听的多个人听完后可能理解的意思是不一样的。 1.2 自然语言处理技术的三个维度 自然语言理解是从上到下的一个过程:单词->句子结构->句子含义 Morphology(单词) :构成语言的最小单位,单词本身含义,词性 Syntax(句子结构):句子剖析,主语+谓语+宾语,语法树 Semantic(语义):这句话的含义, 最终的目的地 1.3 NLP基础任务 nlp基础任务主要分为以下几点: 1、分词(Word Segmentation):单词是句子最小的单位,要把句子切分完后做特征工程,中文比英文要难些,英文天生空格或其他符号就能切分,中文要借助一些算法才能分出一个比较好的结果。分词是NLP任务的第一步,是已经解决的问题。 2. 词性分析(Part-of-Speech Tagging):对后续单词理解是有帮助的,词性也可以作为后续任务的特征。非常基础的工作,是已经解决的比较好的问题。 3. 语义理解(Semantic Understanding):理解一句话的含义,NLP领域的核心。例如Bert本身也是为了很好的理解一个单词,以达到更好的理解一句话。 4. 命名实体识别(Named Entity Recognition):比较基础的任务,现实生活中实际存在的一个物体,比如人,地名,公司名,组织名,时间。 医疗领域:科室,药名。 实体是在一个领域里比较有含义的单词,通常是给一个文本,任务是把实体标记出来。 像聊天机器人,意图识别,知识图谱等场景中,命名实体识别对后续的任务有非常大的帮助。 5. 依存文法分析(Dependecy Parsing):语法分析领域的重要技术,单词之间的依存关系。 6. 句法分析(Parsing):对一句话的结构,主谓宾来进行剖析,语法树。实际应用场景比较少,即使有也对系统提升比较小。 依存文法分析通常价值比句法分析大。 7. 自然语言处理技术概览 1.4 算法复杂度 对于复杂度的理解是至关重要的。写完任何一个程序,我们都需要仔细思考程序的效率如何。这个效率可以从两个方面来考虑,一方面是时间复杂度,另外一方面是空间复杂度。 算法复杂度衡量的是一个算法的效率,比如一个算法运行下来需要多长时间?需要消耗多少资源?根据算法复杂度,我们可以评估一个算法的优劣。在算法复杂度的衡量上,我们经常使用Big O表示法 复杂度的理解是必修课。在从事AI工作中经常会碰到各种各样程序效率低的问题,一个模型训练起来可能需要几天甚至几个月。这时候最直接的解决方式就是加机器,但也是最笨的方法。作为一名AI工程师,我们首先需要想到如何从根本上优化算法,比如检查是否使用了合理的数据结构? 如果一个程序需要经常做数据的查询,那这时候你要考虑用像哈希等合理的数据结构了。相反,如果你用的是列表(list),查询速度就会变得很慢。 再比如,假设我们需要寻找一堆数据中的最大的几个数,很多人可能会选择先把所有的数做排序,之后在提取最大的前几个。但有没有比这个更高效的做法呢? 实际上,在这个场景,我们可以使用一个优先队列(priority queue)来更快速地做查询。 所以,你可以看到每一个小的细节决定了整个程序的效率。这也是为什么一定要重视算法复杂度的原因。 算法复杂度不是衡量程序跑了几秒,而是分析算法效率的级别,线性与问题的大小,平方与问题大小,三次方与问题大小。 复杂度从下面两个角度去衡量1)时间复杂度:用了多少时间; 2)空间复杂度:用了多少内存空间 1) 时间复杂度 随着n的增加,时间增长的趋势 // O(1)的时间复杂度 int x = 0; int y = 1; // O(n)时间复杂度 for (int i = 1; i < =n;i++){ x++; } // O(n^2)时间复杂度 for (int i = 1; i < =n;i++){ for (int j= 1; j< =n;j++){ x++; } } // // O(n+n^2) = O(n^2)时间复杂度 for (int i = 1; i < =n;i++){ x++; } for (int i = 1; i < =n;i++){ for (int j= 1; j< =n;j++){ x++; } } //O(LogN)的算法复杂度 int i = 1; while (i<n) i = i * 2; //O(NLogN)的算法复杂度 for (int i = 1; i < =n;i++){ int i = 1; while (i<n) i = i * 2; } 空间复杂度 随着n的增加,空间增长的趋势 // O(1)的空间复杂度 int x = 0; int y = 1; // O(n)的空间复杂度 int[] nums = new int[n]; for(int i = 0; i< n;i++){ nums[i]=i; } //O(n^2)的空间复杂度 matrix,矩阵分配空间,下面为一个n*n的方阵的内存分配 void malloc2D_1(int **&a, int n) { a = new int*[n]; for(int i=0;i<n;i++) a[i] = new int[n]; } 3) 斐波那契数列的时间复杂度 O(2^n) :计算加法所执行的次数 F[n]=F[n-1]+F 实现: def fb(n): if n==0: return 0 if n==1: return 1 return fb(n-1)+fb(n-2) if __name__ == "__main__": s=fb(9) print(s) 4) 斐波那契数列的空间复杂度 O(n) : 计算时最多入栈的数据的数量,递归调用函数时,会进行上下文切换,对当前函数中的状态进行入栈操作,当调用函数返回时,进行出栈操作。 1.5 动态规划算法 动态规划的核心思想:把计算结果存入内存, 需要的时候从内存里取出来。 为了解决一个大的问题,我们从小问题开始解决。 但一旦解决了小问题,我们就把这些问题的答案存放在内存空间为后续提供使用。所以对于动态规划算法有几个关键点: 1、子问题:思考如何把一个问题拆解成更小的子问题? 并把大问题以子问题的形式表示出来? 2、结果存放:如何存放过程结果? 实际例子:最大递增子串 import numpy as np import sys def max_subseq_sum(arr): max_so_far = -sys.maxsize #取系统的最大值 max_current = 0 #当前最长子序列的和 for i in range(0, len(arr)): #1)当前位置的最长子序列的和有两种可能,分别是下面的if和else if max_current + arr[i] >= arr[i]: #第一种可能:到i-1位置和>=0,到i位置的和就是i-1加上当前位置 max_current = max_current + arr[i] else: #第二种可能:i-1位置是负数,i位置就是自己的值 max_current = arr[i] #2) 如果本轮循环加上i位置的值比上一轮要大,则更新 #否则不更新(例如本轮加了一个负值,就会比上一轮小,就不要更新) if max_so_far < max_current: max_so_far = max_current return max_so_far print (max_subseq_sum(np.array([-2, -3, 4, -1, -2, 1, 5, -3]))) print (max_subseq_sum(np.array([-1,1,2,3,4,-5,2,4]))) 上面代码思路说明: 1)分解子问题: 当前位置最长子序列 = Max(当前位置的值,前一个位置的最长子序列和+当前位置的值) 2)存放子问题结果:存放在max_current中 3)本轮结束时会读取子问题的结果max_current,并和上一轮的结果max_so_far比较,选取较大值更新到max_so_far中 import sys # m是硬币的种类,coins代表具体的面值,V是想换取的纸钞面值。 def minCoins(coins, m, C): # coins: 硬币的面值 # m : 硬币的个数 = len(coins) # C: 需要换的纸币面值 # table[i] 存储换取面值为i的纸币,需要用到的最少量的硬币数 table = [0 for i in range(C + 1)] # Base case table[0] = 0 # 初始化 for i in range(1, C + 1): table[i] = sys.maxsize # 对于每一种价值i来计算,最少用多少硬币可以换取? for i in range(1, C + 1): # Go through all coins smaller than i for j in range(m): if (coins[j] <= i): sub_res = table[i - coins[j]] if (sub_res != sys.maxsize and #在所有coin[j]中找最好的 sub_res + 1 < table[i]): table[i] = sub_res + 1 #上图中m(j)的值+1 return table[C] arr = [1, 2, 3] m = len(arr) n = 6 print(minCoins(arr, m, n)) 2、吃瓜教程——西瓜书+南瓜书 机器学习中监督学习的基本任务 分类任务 回归任务 监督学习 非监督学习 半监督学习 一部分数据有“标记”或者“答案”,另一部分数据没有 更常见:各种原因产生的标记缺失。 增强学习 知道这些概念后,现在开始步入机器学习的第一步。 2.1 线性回归 2.2 逻辑回归 2.2.1 逻辑回归有什么用 逻辑回归,虽然名字叫“回归”,但是它并不是用来回归的。什么是回归?我们之前有介绍过,回归问题解决的是因变量(即Y)是连续值的情况。 而逻辑回归是解决Y是离散变量的问题,即分类。 通常而言,逻辑回归主要解决的是二分类的问题,即分类的结果只有两个类别。比如【男,女】、【有钱,没钱】、【感染病毒,没感染病毒】、【垃圾邮件,不是垃圾邮件】……等等。 从上面的例子中,我们其实可以想象出,其实逻辑回归的应用场景是比较多的。比如基于邮件的特征,去判断一封邮件是否是垃圾邮件;基于用户行为,判断用户的性别等。 2.2.2 逻辑回归的本质 逻辑回归,虽然是一种分类算法,但确实和“回归”有一些关联。如果用一个公式表达: 逻辑回归=线性回归+sigmoid函数 对,这里的关键,就是sigmoid函数。这个函数就是我们之前讲回归和分类时候的激活函数。激活函数是为了将线性回归的连续性结果映射到离散值上,这样就是分类问题了。 在网上看到一张图展示逻辑回归的原理: 2.2.3 算法逻辑 (1)sigmoid函数 我们先看一看下面的函数(单位越阶函数)作为激活函数: 这个是不是可以将连续的z(z=wx+b)映射到离散的y了?是的。 但是,如果将这个函数如果作为激活函数,将会导致函数是不连续不可导的。 因此,我们需要找到一个可以替代这个函数的函数,使其单调可微。什么函数呢?对,这就是sigmoid函数的一种:对数几率函数。 这个函数是连续的,极限取值是0-1,且可以按照0.5的阈值进行二分类。 用了这个函数以后,y和x的函数关系变为 其中: 2.2.4 损失函数 将输入的值映射到0,1之间,0,1之间就可以看成概率值。 反向传播要求导,求导的结果就是g(z)*(1-g(z)),比较好计算。 红色虚线是求导后函数的图形,当z=0时取最大值0.25;当z取值比较大(两端),梯度接近为0,这就是神经网络中sigmoid作为激活函数梯度消失的原因。 ok,既然有了上述的预测函数,下一步,我们要定义具体的损失函数。这里,我们通常用对数似然损失来作为损失函数: 这个公式比较好理解,就不展开了。 这个代价函数呢,叫做交叉熵,其中y(i)指的是预测的结果,而hθ(xi)指的是xi这个点原本的值。 那么它具体是什么意思呢,为什么叫做交叉熵?我们举两个极端的例子看看就明白了: 1、xi原始值hθ=1,预测结果,yi=1的情况 这个时候,代价函数的加号右边会被消掉,因为右边(1-y(i))是0,左边部分呢,因为hθ(xi)=1,故而 log(1)=0。 y(i)log(hθ(xi)) = 1 * log(0) = 0 也就是说,若xi原始值是1,当预测值y=1的时候,代价函数是0的。这个也比较好理解,代价函数为0就是说预测结果和原始结果完全一致的,没有半点出差错。 2、计算结果,yi=0,原始值hθ=0 因为1-hθ(xi),最终结果还是等于0。 也就是说,这个损失函数,只要原始值与预测结果越相符,损失函数就越大,反之,损失函数就会越小。 以上说的只是一个点的情况,实际的代价函数,是要计算所有点的损失函数的均值,如下所示: 2.2.5 损失函数推导 由于: 假设逻辑回归的cost函数如下,我们如何理解这个公式呢? 将逻辑回归的cost函数简化,即得出: 所以就有: 我们可以利用梯度下降算法来求得J(θ)的值最小,根据梯度下降法可得θ的更新过程。j=0 时,代表更新j向量的第0分量,j=1 时,代表更新j向量的第1分量,以此类推,为了方便理解,可以把j看成数组vector_j,j=0,就是更新vector_j[0]。α为学习步长。 经过一些数学推导的最终形式如下(推导过程为对θ求偏导数)。 针对求导过程: ps:xj为x向量的第j分量,还可以理解为x数组的第j项,其实下图是对θ数组的第j项进行更新的算式,然而真正代码角度是对整个θ数组进行更新,也就是下下图的样子。 当我们把上式向量化处理就得到了代码可以处理的形式。 2.2.6 逻辑回归案例 学习了原理之后,看看这个到底怎么使用。 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets iris = datasets.load_iris() X = iris.data y = iris.target plt.scatter(X[y==0,0], X[y==0,1], color="red") plt.scatter(X[y==1,0], X[y==1,1], color="blue") plt.show() 首先对数据进行切分: import numpy as np from sklearn import datasets def train_test_split(X, y, test_ratio=0.2, seed=None): """将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test""" assert X.shape[0] == y.shape[0], "the size of X must be equal to the size of y" assert 0.0 <= test_ratio <= 1.0, "test_ration must be valid" if seed: np.random.seed(seed) shuffled_indexes = np.random.permutation(len(X)) test_size = int(len(X) * test_ratio) test_indexes = shuffled_indexes[:test_size] train_indexes = shuffled_indexes[test_size:] X_train = X[train_indexes] y_train = y[train_indexes] X_test = X[test_indexes] y_test = y[test_indexes] return X_train, X_test, y_train, y_test if __name__=="__main__": iris = datasets.load_iris() X = iris.data y = iris.target X_train, X_test, y_train, y_test = train_test_split(X, y, seed=666) print(X_train.shape) #(120, 4) 接下来编写逻辑回归类: import numpy as np class LogisticRegression: def __init__(self): """初始化Logistic Regression模型""" self.coef_ = None self.intercept_ = None self._theta = None def _sigmoid(self, t): return 1. / (1. + np.exp(-t)) def fit(self, X_train, y_train, eta=0.01, n_iters=1e4): """根据训练数据集X_train, y_train, 使用梯度下降法训练Logistic Regression模型""" assert X_train.shape[0] == y_train.shape[0], "the size of X_train must be equal to the size of y_train" def J(theta, X_b, y): y_hat = self._sigmoid(X_b.dot(theta)) try: return - np.sum(y * np.log(y_hat) + (1 - y) * np.log(1 - y_hat)) / len(y) except: return float(inf) def dJ(theta, X_b, y): return X_b.T.dot(self._sigmoid(X_b.dot(theta)) - y) / len(y) def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8): theta = initial_theta cur_iter = 0 while cur_iter < n_iters: gradient = dJ(theta, X_b, y) last_theta = theta theta = theta - eta * gradient if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon): break cur_iter += 1 return theta X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) initial_theta = np.zeros(X_b.shape[1]) self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters) self.intercept_ = self._theta[0] self.coef_ = self._theta[1:] return self def predict_proba(self, X_predict): """给定待预测数据集X_predict,返回表示X_predict的结果概率向量""" assert self.intercept_ is not None and self.coef_ is not None, "must fit before predict!" assert X_predict.shape[1] == len(self.coef_), "the feature number of X_predict must be equal to X_train" X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict]) return self._sigmoid(X_b.dot(self._theta)) def predict(self, X_predict): """给定待预测数据集X_predict,返回表示X_predict的结果向量""" assert self.intercept_ is not None and self.coef_ is not None, "must fit before predict!" assert X_predict.shape[1] == len(self.coef_), "the feature number of X_predict must be equal to X_train" proba = self.predict_proba(X_predict) return np.array(proba >= 0.5, dtype=int) def score(self, X_test, y_test): """根据测试数据集 X_test 和 y_test 确定当前模型的准确度""" y_predict = self.predict(X_test) return self.accuracy_score(y_test, y_predict) def __repr__(self): return "LogisticRegression()" # 准确率计算 def accuracy_score(y_true, y_predict): """计算y_true和y_predict之间的准确率""" assert len(y_true) == len(y_predict), "the size of y_true must be equal to the size of y_predict" return np.sum(y_true == y_predict) / len(y_true) 通过调用进行预测: import numpy as np from sklearn import datasets import LogisticRegression def train_test_split(X, y, test_ratio=0.2, seed=None): """将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test""" assert X.shape[0] == y.shape[0], "the size of X must be equal to the size of y" assert 0.0 <= test_ratio <= 1.0, "test_ration must be valid" if seed: np.random.seed(seed) shuffled_indexes = np.random.permutation(len(X)) test_size = int(len(X) * test_ratio) test_indexes = shuffled_indexes[:test_size] train_indexes = shuffled_indexes[test_size:] X_train = X[train_indexes] y_train = y[train_indexes] X_test = X[test_indexes] y_test = y[test_indexes] return X_train, X_test, y_train, y_test if __name__=="__main__": iris = datasets.load_iris() X = iris.data y = iris.target X_train, X_test, y_train, y_test = train_test_split(X, y, seed=666) log_reg = LogisticRegression() log_reg.fit(X_train, y_train) log_reg.score(X_test, y_test) log_reg.predict_proba(X_test) print(y_test) 在jupter上展示: 3 Pytorch 深度学习 3.1 numpy 1 保存数组 import numpy as np nd9 =np.random.random([5, 5]) np.savetxt(X=nd9, fname=./test1.txt) nd10 = np.loadtxt(./test1.txt) print(nd10) 2 numpy数组运算 3 修改数组的形状 4 展平 5 合并数组 6 批量处理 3.2 pytorch基础 1 测试 CUDA import torch print("Support CUDA ?: ", torch.cuda.is_available()) x = torch.tensor([10.0]) x = x.cuda() print(x) 2 add 3 torch.view与torch.reshpae的异同 4 矩阵计算 7 对照表 8 求导 9 使用Numpy实现机器学习 10 使用Tensor及antograd实现机器学习 11 使用TensorFlow架构 # -*- coding: utf-8 -*- import tensorflow as tf import numpy as np #生成训练数据 np.random.seed(100) x = np.linspace(-1, 1, 100).reshape(100,1) y = 3*np.power(x, 2) +2+ 0.2*np.random.rand(x.size).reshape(100,1) # 创建两个占位符,分别用来存放输入数据x和目标值y #运行计算图时,导入数据. x1 = tf.placeholder(tf.float32, shape=(None, 1)) y1 = tf.placeholder(tf.float32, shape=(None, 1)) # 创建权重变量w和b,并用随机值初始化. # TensorFlow 的变量在整个计算图保存其值. w = tf.Variable(tf.random_uniform([1], 0, 1.0)) b = tf.Variable(tf.zeros([1])) # 前向传播,计算预测值. y_pred = np.power(x,2)*w + b # 计算损失值 loss=tf.reduce_mean(tf.square(y-y_pred)) # 计算有关参数w、b关于损失函数的梯度. grad_w, grad_b = tf.gradients(loss, [w, b]) #用梯度下降法更新参数. # 执行计算图时给 new_w1 和new_w2 赋值 # 对TensorFlow 来说,更新参数是计算图的一部分内容 # 而PyTorch,这部分是属于计算图之外. learning_rate = 0.01 new_w = w.assign(w - learning_rate * grad_w) new_b = b.assign(b - learning_rate * grad_b) # 已构建计算图, 接下来创建TensorFlow session,准备执行计算图. with tf.Session() as sess: # 执行之前需要初始化变量w、b sess.run(tf.global_variables_initializer()) for step in range(2000): # 循环执行计算图. 每次需要把x1,y1赋给x和y. # 每次执行计算图时,需要计算关于new_w和new_b的损失值, # 返回numpy多维数组 loss_value, v_w, v_b = sess.run([loss, new_w, new_b], feed_dict={ x1: x, y1: y}) if step%200==0: #每200次打印一次训练结果 print("损失值、权重、偏移量分别为{:.4f},{},{}".format(loss_value,v_w,v_b)) # 可视化结果 plt.figure() plt.scatter(x,y) plt.plot (x, v_b + v_w*x**2)
  9. 前言平时自己比较赖,论坛和博客平时都需要维护。比如数据库备份,那么在平时的工作中怎么高效的完成数据库备份任务呢? 废话不在多说,上源码。 源码#! /bin/ sj=`date +%Y%m%d%H%M%S` read -p "要备份的数据库名:" sql mysqldump -u root -p $sql >/root/bf/数据库$sql备份`date +%Y%m%d%H%M%S`.sql echo "备份时间:$sj" >> /root/bf/log.txt。 echo "恭喜!数据库以备份"使用说明先在root目录下新建个bf文件夹将文件保存为sql.sh给脚本给与权限chmod -R 777 sql.sh终端命令./sql.sh输入要备份的数据库名称即可开始备份log.txt用来记录备份的日志。 版权属于:逍遥子大表哥 本文链接:https://blog.bbskali.cn/256.html 按照知识共享署名-非商业性使用 4.0 国际协议进行许可,转载引用文章应遵循相同协议。
  10. 前言平时自己比较赖,论坛和博客平时都需要维护。比如数据库备份,那么在平时的工作中怎么高效的完成数据库备份任务呢? 废话不在多说,上源码。 源码#! /bin/ sj=`date +%Y%m%d%H%M%S` read -p "要备份的数据库名:" sql mysqldump -u root -p $sql >/root/bf/数据库$sql备份`date +%Y%m%d%H%M%S`.sql echo "备份时间:$sj" >> /root/bf/log.txt。 echo "恭喜!数据库以备份"使用说明先在root目录下新建个bf文件夹将文件保存为sql.sh给脚本给与权限chmod -R 777 sql.sh终端命令./sql.sh输入要备份的数据库名称即可开始备份log.txt用来记录备份的日志。 版权属于:逍遥子大表哥 本文链接:https://blog.bbskali.cn/256.html 按照知识共享署名-非商业性使用 4.0 国际协议进行许可,转载引用文章应遵循相同协议。
  11. 由于自学python3,需要在服务器上调试python程序。在centos中,自带有python2,因此需要经常安装python3。但是这里有一个坑,就是centos的yum是用python2写的,如果正常编译安装python3,那么yum就会直接挂了。为了方便以后编译安装python3,不用天天去网上找教程,准备写下这篇文章,供日后参考。首先连上服务器,看下python版本:python -V如图我们可以看到centos下,默认带有python2.7.5: 接下来我们开始安装python3。1 安装python3所需要的组件 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel 2 备份现有的python2 cd /usr/bin mv python python.bak mv pip pip.bak3 下载并编译安装python3这篇文章我们选择最新的稳定版本3.6.5,如有更新可以自行去官网(https://www.python.org/downloads/source/)查找下载地址。 cd ~ && wget https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tar.xz tar -xvJf Python-3.6.5.tar.xz cd Python-3.6.5 指定安装路径 ./configure prefix=/usr/local/python3 编译并安装 make && make install编译安装完成后如图: 接下来做一条软连接,将python3指向python,顺便把pip也重新指向: ln -s /usr/local/python3/bin/python3 /usr/bin/python ln -s /usr/local/python3/bin/pip3 /usr/bin/pip这时候我们执行一下python,看看版本回显信息: python -V python2 -V如图可以看到,python命令对应了python3.6.5,python2命令对应了python2.7.5。 4 修改yum配置装完了python3之后,我们要修一下yum了,不然以后都没法装软件和环境了。 vim /usr/bin/yum如图,按insert,把头部的 #! /usr/bin/python 修改为 #! /usr/bin/python2 修改完成后按esc,然后输入 :wq 保存退出 同样修改一下 urlgrabber-ext-down 文件,把头部的 #! /usr/bin/python 修改为 #! /usr/bin/python2: vim /usr/libexec/urlgrabber-ext-down 改完之后再试一下yum,已经恢复正常: 版权属于:逍遥子大表哥 本文链接:https://blog.bbskali.cn/296.html 按照知识共享署名-非商业性使用 4.0 国际协议进行许可,转载引用文章应遵循相同协议。
  12. 由于自学python3,需要在服务器上调试python程序。在centos中,自带有python2,因此需要经常安装python3。但是这里有一个坑,就是centos的yum是用python2写的,如果正常编译安装python3,那么yum就会直接挂了。为了方便以后编译安装python3,不用天天去网上找教程,准备写下这篇文章,供日后参考。首先连上服务器,看下python版本:python -V如图我们可以看到centos下,默认带有python2.7.5: 接下来我们开始安装python3。1 安装python3所需要的组件 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel 2 备份现有的python2 cd /usr/bin mv python python.bak mv pip pip.bak3 下载并编译安装python3这篇文章我们选择最新的稳定版本3.6.5,如有更新可以自行去官网(https://www.python.org/downloads/source/)查找下载地址。 cd ~ && wget https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tar.xz tar -xvJf Python-3.6.5.tar.xz cd Python-3.6.5 指定安装路径 ./configure prefix=/usr/local/python3 编译并安装 make && make install编译安装完成后如图: 接下来做一条软连接,将python3指向python,顺便把pip也重新指向: ln -s /usr/local/python3/bin/python3 /usr/bin/python ln -s /usr/local/python3/bin/pip3 /usr/bin/pip这时候我们执行一下python,看看版本回显信息: python -V python2 -V如图可以看到,python命令对应了python3.6.5,python2命令对应了python2.7.5。 4 修改yum配置装完了python3之后,我们要修一下yum了,不然以后都没法装软件和环境了。 vim /usr/bin/yum如图,按insert,把头部的 #! /usr/bin/python 修改为 #! /usr/bin/python2 修改完成后按esc,然后输入 :wq 保存退出 同样修改一下 urlgrabber-ext-down 文件,把头部的 #! /usr/bin/python 修改为 #! /usr/bin/python2: vim /usr/libexec/urlgrabber-ext-down 改完之后再试一下yum,已经恢复正常: 版权属于:逍遥子大表哥 本文链接:https://blog.bbskali.cn/296.html 按照知识共享署名-非商业性使用 4.0 国际协议进行许可,转载引用文章应遵循相同协议。
  13. 如何利用Python处理学生的成绩表呢?在实际问题中,我们常用excel来完成此工作。如计算平均分、总分、及格人数等。如何利用Python来完成此工作呢? 前期准备Python3.9所需模块pandas openpyxl成绩表.xlsx win10安装pyton环境Python 安装包下载地址:https://www.python.org/downloads/ 打开该链接,点击下图中的版本号或者Download按钮进入对应版本的下载页面,滚动到最后即可看到各个平台的 Python 安装包。 对前缀的说明: 以Windows installer (64-bit)开头的是 64 位的 Python 安装程序; 以Windows installer (32-bit)开头的是 32 位的 Python 安装程序。 对后缀的说明: embeddable zip file表示.zip格式的绿色免安装版本,可以直接嵌入(集成)到其它的应用程序中; executable installer表示.exe格式的可执行程序,这是完整的离线安装包,一般选择这个即可; web-based installer表示通过网络安装的,也就是说下载到的是一个空壳,安装过程中还需要联网下载真正的 Python 安装包。 *注意勾选Add Python 3.9 to PATH,这样可以将 Python 命令工具所在目录添加到系统 Path 环境变量中,以后开发程序或者运行 Python 命令会非常方便。 继续点击下一步,这样便很快完成python的安装。 验证 在cmd中输入python可以看到回显,说明安装成功。 牛刀小试 print ("kali's blog https://blog.bbskali.cn") 这样便安装完成Python Python处理excel安装相应的模块,因为对excel的操作离不开python相应的库。这里我们用到了pandas openpyxl这两个库。 在cmd中执行下面命令安装即可! python pip install pandas python pip install openpyxl需要注意的是,在pip安装过程中,速度相对比较慢。我们可以改变Python的源来提高下载速度。详情请参考下面这篇文章。 更换Pip下载源,让下载速度飞起来 Python的学习过程中,往往会学习到很多库,而安装各类库的时候,往往不尽人意,下载速度从几KB到十几KB。甚至下... 利用Python打开Excelimport pandas as pd import openpyxl df=pd.read_excel('H:\chengji.xlsx', sheet_name='Sheet1') #读取指定表 print(df)sheet_name为我们读取Excel中的表 求学生总分和平均分所用到的函数 sum:求和 mean:平均分 需要注意的是 axis 0为列,1为行 import pandas as pd import openpyxl df=pd.read_excel('H:\chengji.xlsx', sheet_name='Sheet1') #读取指定表 temp = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]] df["总分"] = temp.sum(axis=1) #axis 0为列,1为行 df["平均分"] = temp.mean(axis=1)求每科目的平均分和最高分import pandas as pd import openpyxl df=pd.read_excel('H:\chengji.xlsx', sheet_name='Sheet1') #读取指定表 temp = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]] Total = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]].mean() Tota2 = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]].max()判断成绩数组中及格人数df1 = df[df[['语文','数学','英语']] >= 90] print('及格人数:',df1[['语文','数学','英语']].count())判断参加考试的人数df2 = df[['语文','数学','英语']] print('考试人数:',df2[['语文','数学','英语']].count())对数据进行保存writer = pd.ExcelWriter('H:\ 2.xlsx') writer.save()#文件保存 writer.close()#文件关闭处理完成的效果 完整代码# -*- coding: UTF-8 -*- import pandas as pd import openpyxl df=pd.read_excel('H:\chengji.xlsx', sheet_name='date1') #读取指定表 temp = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]] df["总分"] = temp.sum(axis=1)#axis 0为列,1为行 df["平均分"] = temp.mean(axis=1) Total = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]].mean() Tota2 = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]].max() writer = pd.ExcelWriter('H:\ 2.xlsx') df.to_excel(writer,sheet_name='Sheet1') Total.to_excel(writer,sheet_name='Sheet2') Tota2.to_excel(writer,sheet_name='Sheet3') # 判断成绩数组中及格人数 df1 = df[df[['语文','数学','英语']] >= 90] print('及格人数:',df1[['语文','数学','英语']].count()) df2 = df[['语文','数学','英语']] print('考试人数:',df2[['语文','数学','英语']].count()) writer.save()#文件保存 writer.close()#文件关闭 templ= r"H:\ 2.xlsx" wb = openpyxl.load_workbook(templ) #指定单元格保存 ws = wb['Sheet1'] ws['c189'].value = '平均成绩' ws['d189'].value = Total['语文'] ws['e189'].value = Total['数学'] ws['f189'].value = Total['英语'] ws['g189'].value = Total['物理'] ws['h189'].value = Total['化学'] ws['i189'].value = Total['道德与法治'] ws['j189'].value = Total['历史'] ws['k189'].value = Total['生地'] ws['c190'].value = '及格人数' ws['d190'].value = df1['语文'].count() ws['e190'].value = df1['数学'].count() ws['f190'].value = df1['英语'].count() #及格率 ws['d190'].value = df1['语文'].count() / df2['语文'].count() wb.save(r"H:\ 2.xlsx") 上诉代码可根据自己的实际情况进行修改,如及格人数中,我是按>=90分计算的。 版权属于:逍遥子大表哥 本文链接:https://blog.bbskali.cn/2505.html 按照知识共享署名-非商业性使用 4.0 国际协议进行许可,转载引用文章应遵循相同协议。
  14. 如何利用Python处理学生的成绩表呢?在实际问题中,我们常用excel来完成此工作。如计算平均分、总分、及格人数等。如何利用Python来完成此工作呢? 前期准备Python3.9所需模块pandas openpyxl成绩表.xlsx win10安装pyton环境Python 安装包下载地址:https://www.python.org/downloads/ 打开该链接,点击下图中的版本号或者Download按钮进入对应版本的下载页面,滚动到最后即可看到各个平台的 Python 安装包。 对前缀的说明: 以Windows installer (64-bit)开头的是 64 位的 Python 安装程序; 以Windows installer (32-bit)开头的是 32 位的 Python 安装程序。 对后缀的说明: embeddable zip file表示.zip格式的绿色免安装版本,可以直接嵌入(集成)到其它的应用程序中; executable installer表示.exe格式的可执行程序,这是完整的离线安装包,一般选择这个即可; web-based installer表示通过网络安装的,也就是说下载到的是一个空壳,安装过程中还需要联网下载真正的 Python 安装包。 *注意勾选Add Python 3.9 to PATH,这样可以将 Python 命令工具所在目录添加到系统 Path 环境变量中,以后开发程序或者运行 Python 命令会非常方便。 继续点击下一步,这样便很快完成python的安装。 验证 在cmd中输入python可以看到回显,说明安装成功。 牛刀小试 print ("kali's blog https://blog.bbskali.cn") 这样便安装完成Python Python处理excel安装相应的模块,因为对excel的操作离不开python相应的库。这里我们用到了pandas openpyxl这两个库。 在cmd中执行下面命令安装即可! python pip install pandas python pip install openpyxl需要注意的是,在pip安装过程中,速度相对比较慢。我们可以改变Python的源来提高下载速度。详情请参考下面这篇文章。 更换Pip下载源,让下载速度飞起来 Python的学习过程中,往往会学习到很多库,而安装各类库的时候,往往不尽人意,下载速度从几KB到十几KB。甚至下... 利用Python打开Excelimport pandas as pd import openpyxl df=pd.read_excel('H:\chengji.xlsx', sheet_name='Sheet1') #读取指定表 print(df)sheet_name为我们读取Excel中的表 求学生总分和平均分所用到的函数 sum:求和 mean:平均分 需要注意的是 axis 0为列,1为行 import pandas as pd import openpyxl df=pd.read_excel('H:\chengji.xlsx', sheet_name='Sheet1') #读取指定表 temp = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]] df["总分"] = temp.sum(axis=1) #axis 0为列,1为行 df["平均分"] = temp.mean(axis=1)求每科目的平均分和最高分import pandas as pd import openpyxl df=pd.read_excel('H:\chengji.xlsx', sheet_name='Sheet1') #读取指定表 temp = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]] Total = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]].mean() Tota2 = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]].max()判断成绩数组中及格人数df1 = df[df[['语文','数学','英语']] >= 90] print('及格人数:',df1[['语文','数学','英语']].count())判断参加考试的人数df2 = df[['语文','数学','英语']] print('考试人数:',df2[['语文','数学','英语']].count())对数据进行保存writer = pd.ExcelWriter('H:\ 2.xlsx') writer.save()#文件保存 writer.close()#文件关闭处理完成的效果 完整代码# -*- coding: UTF-8 -*- import pandas as pd import openpyxl df=pd.read_excel('H:\chengji.xlsx', sheet_name='date1') #读取指定表 temp = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]] df["总分"] = temp.sum(axis=1)#axis 0为列,1为行 df["平均分"] = temp.mean(axis=1) Total = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]].mean() Tota2 = df[["语文","数学","英语","物理","化学","道德与法治","历史","生地"]].max() writer = pd.ExcelWriter('H:\ 2.xlsx') df.to_excel(writer,sheet_name='Sheet1') Total.to_excel(writer,sheet_name='Sheet2') Tota2.to_excel(writer,sheet_name='Sheet3') # 判断成绩数组中及格人数 df1 = df[df[['语文','数学','英语']] >= 90] print('及格人数:',df1[['语文','数学','英语']].count()) df2 = df[['语文','数学','英语']] print('考试人数:',df2[['语文','数学','英语']].count()) writer.save()#文件保存 writer.close()#文件关闭 templ= r"H:\ 2.xlsx" wb = openpyxl.load_workbook(templ) #指定单元格保存 ws = wb['Sheet1'] ws['c189'].value = '平均成绩' ws['d189'].value = Total['语文'] ws['e189'].value = Total['数学'] ws['f189'].value = Total['英语'] ws['g189'].value = Total['物理'] ws['h189'].value = Total['化学'] ws['i189'].value = Total['道德与法治'] ws['j189'].value = Total['历史'] ws['k189'].value = Total['生地'] ws['c190'].value = '及格人数' ws['d190'].value = df1['语文'].count() ws['e190'].value = df1['数学'].count() ws['f190'].value = df1['英语'].count() #及格率 ws['d190'].value = df1['语文'].count() / df2['语文'].count() wb.save(r"H:\ 2.xlsx") 上诉代码可根据自己的实际情况进行修改,如及格人数中,我是按>=90分计算的。 版权属于:逍遥子大表哥 本文链接:https://blog.bbskali.cn/2505.html 按照知识共享署名-非商业性使用 4.0 国际协议进行许可,转载引用文章应遵循相同协议。

黑客攻防讨论组

黑客攻防讨论组

    You don't have permission to chat.
    ×
    ×
    • 创建新的...