快乐学习
前程无忧、中华英才非你莫属!

python-mitmproxy-交互式 HTTPS 代理-1

zhangtongle阅读(2600)

简介

最近要实现接口自动化测试的,流量录制和回放。

mitmproxy最为合适,基于服务器的,基于Python的,可编程的。可互动的。so,已经抛弃了什么Fiddler 、charles ,因为它才是最好的。

他的背景是,适用于渗透测试人员和软件开发人员的必备利器,拿过来做接口自动化测试的流量录制和回放,可能也就不到3行代码就能实现。so ,我选择它来做我们的工具组件之一。

安装

安装包下载地址:
https://mitmproxy.org/downloads/#5.3.0/

你什么系统就下什么安装包,windows 版本,直接点下一步下一步,点击击默认安装就好。

千万别下最新版本,因为它跟python版本强依赖。最新版本8.x 需要python3.10x版本,我的py是3.8 只能安装5.x版本。

其他版本的安装你不会,可以看这个文档
https://docs.mitmproxy.org/archive/v5/overview-installation/

启动

windows版本安装完成会自动启动

如果没有启动可以手动启动,或者下次启动可以按照我说的:

如果你的mitmproxy安装在默认路径下。可以打开cmd 命令窗口
切换到图片中所在的路径执行:mitmdump 并回车,就可以开启。

监听端口8080,配置谷歌浏览器代理。

在谷歌浏览器上,安转一个插件:SwitchyOmega_Chromium.zip

可以找博客主要,或者自己百度下载,然后顺手百度一下,谷歌浏览器如何安装插件即可。

安装好之后,配置mitmproxy服务器的监听端口号为8080

然后在配置好的代理环境下访问 https://www.ztloo.com

可以看到访问https://www.ztloo.com 可以成功,显示200,其他链接

Cannot establish TLS with client (sni: beacons.gvt2.com): TlsException("SSL) 会出现这样的错误,是因为需要安装证书,它跟fiddler、charles 一样也是需要安装证书的,要不然抓不了HTTS的数据包。

安装证书

http://mitm.it/ 在谷歌浏览器代理环境下,访问这个链接,会提示你安装对应的证书引导提示

点击对应的get绿色区域,会自动下载证书文件,然后安装即可。

比如windows 上安装双击下列文件(跟着提示,安装到根证书即可)
不需要设置密码

mitmproxy-ca-cert.p12

然后就能抓取https 的数据包了,例如百度。

手机上安装

访问http://mitm.it/ 下载对应手机的证书,发送到对应手机,
如果手机不识别,就去安卓手机的安全、从SD卡下安装证书。

手机端iphone上下载安装mitmproxy证书:

  • 手机和PC在同一个局域网中,设置wifi代理为PC端的ip,端口为mitmproxy的端口(默认8080)

  • 手机浏览器访问mitm.it,下载安装mitmproxy描述文件,完成验证

  • 经过上面两步,个别APP就可以访问并被mitmproxy在PC端截获,但有时发现很多APP无法上网,这时还需要添加证书的信任

“设置”——关于本机——证书信任设置——开启mitmproxy完全信任

安卓端android(华为为例)安卓端android(华为为例)

  • 1 设置

  • 2 安全与隐私

  • 3 更多安全设置

  • 4 从存储设备安装

  • 5 选中证书文件,点击安装

  • 6 输入锁屏密码

  • 7 给安装文件命名mitmproxy


更详细的说明可以参考:https://mitmproxy.org/,后续会更新更为实战,更为好玩的数据抓取功能。一定要持续关注哦~

Python排序指南-(社区文档)

zhangtongle阅读(2508)

前言

Python 列表有一个内置的 list.sort() 方法可以直接修改列表。
还有一个 sorted() 内置函数,它会从一个可迭代对象构建一个新的排序列表。

在本文档中,我们将探索使用Python对数据进行排序的各种技术。

基本排序

简单的升序排序非常简单:只需调用 sorted() 函数。它返回一个新的排序后列表:

sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]

你也可以使用 list.sort() 方法,它会直接修改原列表(并返回 None 以避免混淆),通常来说它不如 sorted() 方便 但如果你不需要原列表,它会更有效率。

a = [5, 2, 3, 1, 4]
a.sort()
a
[1, 2, 3, 4, 5]

另外一个区别是, list.sort() 方法只是为列表定义的,而 sorted() 函数可以接受任何可迭代对象。

sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
[1, 2, 3, 4, 5]

关键函数

list.sort() 和 sorted() 都有一个 key 形参用来指定在进行比较前要在每个列表元素上调用的函数(或其他可调用对象)。
例如,下面是一个不区分大小写的字符串比较:

sorted("This is a test string from Andrew".split(), key=str.lower)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']

key 形参的值应该是个函数(或其他可调用对象),它接受一个参数并返回一个用于排序的键。 这种机制速度很快,因为对于每个输入记录只会调用一次键函数。

一种常见的模式是使用对象的一些索引作为键对复杂对象进行排序。例如:

student_tuples = [
    ('john', 'A', 15),
    ('jane', 'B', 12),
    ('dave', 'B', 10),
]
sorted(student_tuples, key=lambda student: student[2])   # sort by age
('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

同样的技术也适用于具有命名属性的对象。例如:

class Student:
    def __init__(self, name, grade, age):
        self.name = name
        self.grade = grade
        self.age = age
    def __repr__(self):
        return repr((self.name, self.grade, self.age))

student_objects = [
    Student('john', 'A', 15),
    Student('jane', 'B', 12),
    Student('dave', 'B', 10),
]
sorted(student_objects, key=lambda student: student.age)   # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

Operator 模块函数

上面显示的键函数模式非常常见,因此 Python 提供了便利功能,使访问器功能更容易,更快捷。 operator 模块有 itemgetter() 、 attrgetter() 和 methodcaller() 函数。

使用这些函数,上述示例变得更简单,更快捷:

from operator import itemgetter, attrgetter

sorted(student_tuples, key=itemgetter(2))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

sorted(student_objects, key=attrgetter('age'))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

Operator 模块功能允许多级排序。 例如,按 grade 排序,然后按 age 排序:

sorted(student_tuples, key=itemgetter(1,2))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

sorted(student_objects, key=attrgetter('grade', 'age'))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

升序和降序

list.sort() 和 sorted() 接受布尔值的 reverse 参数。这用于标记降序排序。
例如,要以反向 age 顺序获取学生数据:


sorted(student_tuples, key=itemgetter(2), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)

sorted(student_objects, key=attrgetter('age'), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

排序稳定性和排序复杂度

排序保证是 稳定 的。 这意味着当多个记录具有相同的键值时,将保留其原始顺序。

data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
sorted(data, key=itemgetter(0))
[('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]

注意 blue 的两个记录如何保留它们的原始顺序,以便 ('blue', 1) 保证在 ('blue', 2) 之前。

这个美妙的属性允许你在一系列排序步骤中构建复杂的排序。
例如,要按 grade 降序然后 age 升序对学生数据进行排序,请先 age 排序,然后再使用 grade 排序:

s = sorted(student_objects, key=attrgetter('age'))     # sort on secondary key
sorted(s, key=attrgetter('grade'), reverse=True)       # now sort on primary key, descending
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

这可以被抽象为一个包装函数,该函数能接受一个列表以及字段和顺序的元组,以对它们进行多重排序。

def multisort(xs, specs):
    for key, reverse in reversed(specs):
        xs.sort(key=attrgetter(key), reverse=reverse)
    return xs

multisort(list(student_objects), (('grade', True), ('age', False)))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

Python 中使用的 Timsort 算法可以有效地进行多种排序,因为它可以利用数据集中已存在的任何排序。


使用装饰-排序-去装饰的旧方法

这个三个步骤被称为 Decorate-Sort-Undecorate :

首先,初始列表使用控制排序顺序的新值进行修饰。

然后,装饰列表已排序。

最后,删除装饰,创建一个仅包含新排序中初始值的列表。

例如,要使用DSU方法按 grade 对学生数据进行排序:

decorated = [(student.grade, i, student) for i, student in enumerate(student_objects)]
decorated.sort()
[student for grade, i, student in decorated]               # undecorate
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

这方法语有效是因为元组按字典顺序进行比较,先比较第一项;如果它们相同则比较第二个项目,依此类推。

不一定在所有情况下都要在装饰列表中包含索引 i ,但包含它有两个好处:

排序是稳定的——如果两个项具有相同的键,它们的顺序将保留在排序列表中。

原始项目不必具有可比性,因为装饰元组的排序最多由前两项决定。 因此,例如原始列表可能包含无法直接排序的复数。

这个方法的另一个名字是 Randal L. Schwartz 在 Perl 程序员中推广的 Schwartzian transform。

既然 Python 排序提供了键函数,那么通常不需要这种技术。


使用 cmp 参数的旧方法

本 HOWTO 中给出的许多结构都假定为 Python 2.4 或更高版本。在此之前,没有内置 sorted() , list.sort() 也没有关键字参数。相反,所有 Py2.x 版本都支持 cmp 参数来处理用户指定的比较函数。

在 Py3.0 中, cmp 参数被完全删除(作为简化和统一语言努力的一部分,消除了丰富的比较与 cmp() 魔术方法之间的冲突)。

在 Py2.x 中, sort 允许一个可选函数,可以调用它来进行比较。
该函数应该采用两个参数进行比较,然后返回负值为小于,如果它们相等则返回零,或者返回大于的正值。
例如,我们可以这样做:

def numeric_compare(x, y):
    return x - y  # 返回负值为小于,小的值放在前面
sorted([5, 2, 4, 1, 3], cmp=numeric_compare) 
[1, 2, 3, 4, 5]

或者你可反转比较的顺序:


def reverse_numeric(x, y):
    return y - x # 返回正值,大的值放在前面
sorted([5, 2, 4, 1, 3], cmp=reverse_numeric) 
[5, 4, 3, 2, 1]

在将代码从 Python 2.x 移植到 3.x 时,如果让用户提供比较函数并且需要将其转换为键函数则会出现这种情况。 以下包装器使得做到这点变得很容易。

def cmp_to_key(mycmp):
    'Convert a cmp= function into a key= function'
    class K:
        def __init__(self, obj, *args):
            self.obj = obj
        def __lt__(self, other):
            return mycmp(self.obj, other.obj) < 0
        def __gt__(self, other):
            return mycmp(self.obj, other.obj) > 0
        def __eq__(self, other):
            return mycmp(self.obj, other.obj) == 0
        def __le__(self, other):
            return mycmp(self.obj, other.obj) <= 0
        def __ge__(self, other):
            return mycmp(self.obj, other.obj) >= 0
        def __ne__(self, other):
            return mycmp(self.obj, other.obj) != 0
    return K

要转换为键函数,只需包装旧的比较函数:

sorted([5, 2, 4, 1, 3], key=cmp_to_key(reverse_numeric))

在 Python 3.2 中, functools.cmp_to_key() 函数被添加到标准库中的 functools 模块中

原创-Pandas心法之数据字符串与正则处理-8

zhangtongle阅读(2391)

"""
字符串操作
"""
import pandas as pd

monte = pd.Series(['Graham Chapman', 'John Cleese', 'Terry Gilliam',
                   'Eric Idle', 'Terry Jones', 'Michael Palin'])
print(monte)
print(monte.str.lower())
print(monte.str.len())
print(monte.str.startswith('T'))
print(monte.str.split())

'''
字符串函数
len() lower() translate() islower()
ljust() upper() startswith() isupper()
rjust() find() endswith() isnumeric()
center() rfind() isalnum() isdecimal()
zfill() index() isalpha() split()
strip() rindex() isdigit() rsplit()
rstrip() capitalize() isspace() partition()
lstrip() swapcase() istitle() rpartition()

'''

'''
使用正则表达式
'''
'''

Method Description
match() Call re.match() on each element, returning a boolean.
extract() Call re.match() on each element, returning matched groups as strings.
findall() Call re.findall() on each element
replace() Replace occurrences of pattern with some other string
contains() Call re.search() on each element, returning a boolean
count() Count occurrences of pattern
split() Equivalent to str.split(), but accepts regexps
rsplit() Equivalent to str.rsplit(), but accepts regexps

'''

# 通过在每个元素的开头要求一组连续的字符来从每个名字中提取名字:
# print(monte.str.extract('([A-Za-z]+)', expand=False))

'''
例如查找所有以辅音开头和结尾的名称,
并使用字符串开头(^)和字符串结尾($)正则表达式字符
'''
print(monte.str.findall(r'^[^AEIOU].*[^aeiou]$'))
print(monte.str[0:3])

'''
字符串还有一些有用的方法

get() 索引每个元素
slice() 切片每个元素
slice_replace() 用传递的值替换每个元素中的切片
cat() 连接字符串
repeat() 重复值
normalize() 返回字符串的Unicode形式
pad() 在字符串的左侧,右侧或两侧添加空格
wrap() 将长字符串拆分成长度小于给定宽度的行
join() 使用传递的分隔符将字符串连接到系列的每个元素中
get_dummies() 提取虚拟变量作为数据框

'''
print(monte.str.split().str.get(-1))

# 通过分隔符来查询
full_monte = pd.DataFrame({'name': monte,
                           'info': ['B|C|D', 'B|D', 'A|C',
                                    'B|D', 'B|C', 'B|C|D']})
print(full_monte)

# 该get_dummies()例程可让您快速将这些指标变量拆分为DataFrame:
print(full_monte['info'].str.get_dummies('|'))

原创-Pandas心法之数据透视表-7

zhangtongle阅读(2453)

###############透视表##########################
import pandas as pd
import seaborn as sns

# 科学上网就好了。
# 其中包含有关该不幸航程的每位乘客的大量信息,
# 包括性别,年龄,舱位,已付车费等。
titanic = sns.load_dataset('titanic')
# print(titanic.head())

# 让我们按性别查看存活率:
# print(titanic.groupby('sex')[['survived']].mean())

'''
这立即为我们提供了一些见识:
总体而言,船上每四位女性中就有三位得以幸存,而只有五分之一的男性得以幸存!
'''

'''
这很有用,但我们可能想更进一步,按照性别和阶级来考察生存率
'''

# print(titanic.head())
# print('--------------------------')

life = titanic.groupby(['sex', 'class'])['survived'].aggregate('mean').unstack()
print(life)

print('--------------------------')

'''
透视表

透视表默认处理函数是均值
'''
tsb= titanic.pivot_table('survived', index='sex', columns='class')
print(tsb)
'''
这显然比该groupby方法更具可读性,并且产生相同的结果。
您可能会期望20世纪初的跨大西洋航行,
生存梯度对女性和更高阶层的人都有利。
一流的妇女几乎可以确定地生存(嗨,罗斯!),而十分之三的男性中只有一个幸存了(抱歉,杰克!)。

'''

# 多级透视表
'''
例如,我们可能有兴趣将年龄视为第三维。
我们将使用以下pd.cut功能对年龄进行分类:
'''
age = pd.cut(titanic['age'], [0, 18, 80])

tsc = titanic.pivot_table('survived', ['sex', age], 'class')
# print(tsc)

'''
在处理列时,我们也可以应用相同的策略。
让我们添加pd.qcut用于自动计算分位数的票价信息:
'''
fare = pd.qcut(titanic['fare'], 2)
dfs = titanic.pivot_table('survived', ['sex', age], [fare, 'class'])
# print(dfs)

'''
额外的数据透视表选项
'''

# survived 统计它sum, fare 统计它均值,以class 分组。索引是性别
tps = titanic.pivot_table(index='sex', columns='class',
                          aggfunc={'survived': sum, 'fare': 'mean'})
# print(tps)

'''
有时,计算每个分组的总数很有用。这可以通过margins关键字完成:
'''
tcm = titanic.pivot_table('survived', index='sex', columns='class', margins=True)

# print(tcm)
'''
在这里,这自动为我们提供了有关按性别分类不可知生存率,
按类别分类不可知性别生存率以及总生存率38%的信息。
可以使用margins_name关键字指定边距标签,默认为"All"。
'''

'''
例如:生育水平数据
'''
births = pd.read_csv('births.csv')
# print(births.head())

'''
通过使用数据透视表,我们可以开始更多地了解此数据。
让我们添加一个十年专栏,看看男女出生与十年的关系:
'''
births['decade'] = 10 * (births['year'] // 10)
bgs = births.pivot_table('births', index='decade', columns='gender', aggfunc='sum')
# print(bgs)

原创-Pandas心法之数据汇总与分组-6

zhangtongle阅读(2310)

###############汇总与分组##########################
import seaborn as sns
import numpy as np
import pandas as pd

planets = sns.load_dataset('planets')
planets.shape

# print(planets.head())

rng = np.random.RandomState(42)
ser = pd.Series(rng.rand(5))
ser.sum()
ser.mean()

df = pd.DataFrame(
    {'A': rng.rand(5), 'B': rng.rand(5)}
)

print(df.mean())
print(df.mean(axis='columns'))

print(planets.dropna().describe())

'''
Aggregation Description
count() Total number of items
first(), last() First and last item
mean(), median() Mean and median
min(), max() Minimum and maximum
std(), var() Standard deviation and variance
mad() Mean absolute deviation
prod() Product of all items
sum() Sum of all items
These are all methods of DataFrame and Series objects.
'''

# GroupBy: Split, Apply, Combine

df = pd.DataFrame({'key': ['A', 'B', 'C', 'A', 'B', 'C'],
                   'data': range(6)}, columns=['key', 'data'])

print(df)
print(df.groupby('key').sum())

group_op = planets.groupby('method')['orbital_period']
print(group_op.median())

# 可以直接迭代每个组
for (method, group) in planets.groupby('method'):
    print("{0:30s} shape={1}".format(method, group.shape))

gdu = planets.groupby('method')['year'].describe().unstack()
print(gdu)
print(df)

'''
aggregate()方法允许更大的灵活性。
它可以采用字符串,函数或其列表,然后一次计算所有聚合
'''
dfk = df.groupby('key').aggregate(['min', np.median, max])
print(dfk)

rng = np.random.RandomState(0)
df = pd.DataFrame(
    {'key': ['A', 'B', 'C', 'A', 'B', 'C'],
     'data1': range(6),
     'data2': rng.randint(0, 10, 6)},
    columns=['key', 'data1', 'data2'])

dfagg = df.groupby('key').aggregate({'data1': 'min',
                                     'data2': 'max'})
print(dfagg)

# 过滤
def filter_func(x):
    return x['data2'].std() > 4

print(df)

print('-----------------------------')
print(df.groupby('key').std())
print('-----------------------------')
print(df.groupby('key').filter(filter_func))

print('-----------------------------')
dfr = df.groupby('key').transform(lambda x: x - x.mean())
print(dfr)

# apply() 方法的应用

'''
该apply()方法使您可以将任意函数应用于分组结果。
该函数应采用DataFrame,并返回Pandas对象(
例如DataFrame,Series)或标量;合并操作将根据返回的输出类型进行调整。
'''

def norm_by_data2(x):
    # x is a DataFrame of group values
    x['data1'] /= x['data2'].sum()
    return x

df_norm = df.groupby('key').apply(norm_by_data2)
print(df_norm)

# 指定分离键
L = [0, 1, 0, 1, 2, 0]
print(df.groupby(L).sum())

# 字典或series 映射索引到组
df2 = df.set_index('key')
print(df2)

mapping = {'A': 'vowel', 'B': 'consonant', 'C': 'consonant'}
print('------------------------------')
print(df2.groupby(mapping).sum())

# 与映射类似,您可以传递将输入索引值并输出组的任何Python函数
print(df2.groupby(str.lower).mean())
print(df2.groupby([str.lower, mapping]).mean())

# 分组案例
decade = 10 * (planets['year'] // 10)
decade = decade.astype(str) + 's'
decade.name = 'decade'
print(planets.groupby(['method', decade])['number'].sum().unstack().fillna(0))

原创-Pandas心法之数据连接&合并-5

zhangtongle阅读(2375)

前言

Pandas 下半部分内容,来了。这些示例整合了一下,直接贴上,没怎么分类,因为比较懒

但是内容,肯定是很精华,并配上了中文的注释,并且每行代码,都经过小编的运行和验证。含金量还是非常之高。

示例代码的主要内容有、数据的合并concat、merge 这两个函数,如果你有大量的Excel, 数据库表的复杂链接查询的时候,发现SQL 很慢的时候,可以试试merge函数。

还有分组和汇总,当我们的数据有很多突出的特征,我们就可以进行分类统计和描述。
分类统计和描述,就用到了分组函数 gruopby,结合aggregate和聚合函数max,min等就可以了。

还有更为简洁高级点的分组统计功能,那就是透视表pivot_table

还有字符串处理函数,以及时间字段的处理


import numpy as np
import pandas as pd

# 将Series 和DataFrame与pd.concat函数连接在一起
from datetime import datetime

def make_df(cols, ind):
    """Quickly make a DataFrame"""
    data = {c: [str(c) + str(i) for i in ind]
            for c in cols}

    return pd.DataFrame(data, ind)

# example DataFrame
md = make_df('ABC', range(3))
# print(md)

# numpy数组的串联
x = [1, 2, 3]
y = [4, 5, 6]
z = [7, 8, 9]
xyz = np.concatenate([x, y, z])
# print(xyz)

# 设置轴来设定串联的方向
x = [[1, 2],
     [3, 4]]
xx = np.concatenate([x, x], axis=1)  # 1 是x轴方向
# print(xx)

# pd.concat()可以用于Series或DataFrame对象的简单串联
ser1 = pd.Series(['A', 'B', 'C'], index=[1, 2, 3])
ser2 = pd.Series(['D', 'E', 'F'], index=[4, 5, 6])
ser = pd.concat([ser1, ser2])
# print(ser)

df1 = make_df('AB', [1, 2])
df2 = make_df('AB', [3, 4])

df = pd.concat([df1, df2])
# print('这是concat的df',df)

df3 = make_df('AB', [0, 1])
df4 = make_df('CD', [0, 1])

dfs = pd.concat([df3, df4], axis=1)
# print(dfs)

# 重复索引
x = make_df('AB', [0, 1])
y = make_df('AB', [2, 3])
y.index = x.index  # make duplicate indices!

xys = pd.concat([x, y])
# print(xys)

# 给两个DF数据分别在左侧X轴,添加多层索引
xyk = pd.concat([x, y], keys=['x', 'y'])
# print(xyk)

# 串联部分索引不同,出现NaN
df5 = make_df('ABC', [1, 2])
df6 = make_df('BCD', [3, 4])
# 解决办法,使用join 函数内连接,把索引相同部分进行关联
# 其他不关联的索引A,D舍去。可以理解为sql 的内连接
dfn = pd.concat([df5, df6], join='inner')
# print(dfn)

# 可以理解为sql 的左链接,以df5 为基准。
dfc = pd.concat([df5, df6], join_axes=[df5.columns])
# print(dfc)

# 通过append 函数 来合并数据.效果一样
# print('这是append的df', df1.append(df2))

# 通过append方法不会修改原始对象,
# 而是会使用合并的数据创建一个新对象
# 还是使用concat 比较高效。、

# 1、 高性能合并Merge 合并多个数据源
df_emp = pd.DataFrame({'employee': ['Bob', 'Jake', 'Lisa', 'Sue', 'ztloo'],
                       'group': ['Accounting', 'Engineering', 'Engineering', 'HR', 'code']})
df_date = pd.DataFrame({'employee': ['Lisa', 'Bob', 'Jake', 'Sue', 'pys'],
                        'hire_date': [2004, 2008, 2012, 2014, 2020]})

# print(df_emp)
# print(df_date)

# 按照第一个参数df_emp 的索引顺序排列的
# merge 只合并两个数据源相同的列,不同的列会舍弃
df3 = pd.merge(df_emp, df_date)
# print(df3)

df4 = pd.DataFrame({'group': ['Accounting', 'Engineering', 'HR'],
                    'supervisor': ['Carly', 'Guido', 'Steve']})

# 两个df 在去合并一个df,通过group,新增一个关系列。
df34 = pd.merge(df3, df4)
# print(df34)

# 合并的df 数据中有重复索引
df5 = pd.DataFrame({'group': ['Accounting', 'Accounting',
                              'Engineering', 'Engineering', 'HR', 'HR'],
                    'skills': ['math', 'spreadsheets', 'coding', 'linux',
                               'spreadsheets', 'organization']})
print(df_emp)

# 根据df_emp 中的grop角色进行关联合并。
df15 = pd.merge(df_emp, df5)
print(df15)

# 通过关键字来合并,显示指定两个df 中都有的字段,用来作为关联。
dfe12 = pd.merge(df_emp, df_date, on='employee')
print(dfe12)

df3 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue', 'dssf'],
                    'salary': [70000, 80000, 120000, 90000, 1009009]})

# 两个df 中,关联两个索引名称不同的方法。
# 通过left_on和right_on 来指定左右关联的索引名称
df13_lr = pd.merge(df_emp, df3, left_on="employee", right_on="name")
print(df13_lr)

# 去掉重复的列,删掉name 列。
print(df13_lr.drop('name', axis=1))

df1a = df_emp.set_index('employee')
df2a = df_date.set_index('employee')
print(df1a)
print(df2a)

dfaa = pd.merge(df1a, df2a, left_index=True, right_index=True)
print(dfaa)

print(df1a.join(df2a))
print(df1a)

# 因为df1a 的索引set_index 被设置成了employee,so 直接关联name.
dfa3 = pd.merge(df1a, df3, left_index=True, right_on='name')
print(dfa3)

# 严重的问题
# 两个df 中有不同的列,使用merge 只会合并都存在的列
df6 = pd.DataFrame({'name': ['Peter', 'Paul', 'Mary'],
                    'food': ['fish', 'beans', 'bread']},
                   columns=['name', 'food'])

df7 = pd.DataFrame({'name': ['Mary', 'Joseph'],
                    'drink': ['wine', 'beer']},
                   columns=['name', 'drink'])

# 为了解决多个df 中不同的列,使用how=outer,
df67 = pd.merge(df6, df7,how='outer')
print(df67)

# 如果只显示第一个df数据中的所有列,left ,也可以使用right.
df67 = pd.merge(df6, df7, how='left')
print(df67)

# 合并两个df ,df 中有相同的列名
df8 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue'],
                    'rank': [1, 2, 3, 4]})
df9 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue'],
                    'rank': [3, 1, 4, 2]})

'''
由于输出将有两个冲突的列名,
因此合并功能会自动附加后缀_x或_y使输出列唯一。
如果这些默认值不合适,则可以使用suffixes关键字指定自定义后缀:
'''

df89 = pd.merge(df8, df9, on="name")
print(df89)

df89 = pd.merge(df8, df9, on="name", suffixes=["_L", "_R"])
print(df89)

##################################################################

pop = pd.read_csv('state-population.csv')
areas = pd.read_csv('state-areas.csv')
abbrevs = pd.read_csv('state-abbrevs.csv')

print('-----------pop------------')
print(pop.head())
#
print('-----------areas------------')
print(areas.head())

print('-----------abbrevs------------')
print(abbrevs.head())

# 让state/region和 abbreviation 字段相关联
merged = pd.merge(pop, abbrevs, how='outer',
                  left_on='state/region', right_on='abbreviation')

# drop duplicate info

# 删掉abbreviation 列
merged = merged.drop('abbreviation', axis=1)  # drop duplicate info
# print(merged.head())
#

# 检查数据是否有不匹配有空行
print(merged.isnull().any())

# 一些population信息为空;让我们找出:
pop_null = merged[merged['population'].isnull()].head()
# print(pop_null)

state_unique = merged.loc[merged['state'].isnull(), 'state/region'].unique()
# unique.返回Series对象的唯一值。
print(state_unique)

# 把合并好的数据中的state/region
# 等于pr的数据中的state 字段的值修改成Puerto Rico。
merged.loc[merged['state/region'] == 'PR', 'state'] = 'Puerto Rico'

# 把合并好的数据中的state/region 等于USA的数据中的state 字段的值修改成Puerto Rico

merged.loc[merged['state/region'] == 'USA', 'state'] = 'United States'

# any()一个True,则返回True,非空为False
print(merged.isnull().any())
print(merged.head())

# 将结果与面积数据合并。
# 检查我们的结果,我们将希望同时加入state这两个列:
final = pd.merge(merged, areas, on='state', how='left')
print(final.head())

print(final.isnull().any())

# area列中为空;我们可以看一下此处忽略了哪些区域:
fun = final['state'][final['area (sq. mi)'].isnull()].unique()
print(fun)

'''
我们看到,我们areas DataFrame不包括整个美国地区。
我们可以插入适当的值(例如,使用所有州面积的总和),
但是在这种情况下,我们将删除空值,因为整个美国的人口密度与我们当前的讨论无关:
'''
final.dropna(inplace=True)
# print(final.head())

data2010 = final.query("year == 2010 & ages == 'total'")
# print(data2010.head())

data2010.set_index('state', inplace=True)
density = data2010['population'] / data2010['area (sq. mi)']
density.sort_values(ascending=False, inplace=True)
print(density.head())
print(density.tail())

原创-Pandas心法之分层索引-4

zhangtongle阅读(2446)

"""
# 7、分层索引、
"""

import pandas as pd
import numpy as np

index = [('California', 2000), ('California', 2010),
         ('New York', 2000), ('New York', 2010),
         ('Texas', 2000), ('Texas', 2010)]
populations = [33871648, 37253956,
               18976457, 19378102,
               20851820, 25145561]

pop = pd.Series(populations, index=index)
print(pop)

# 切片
print(pop[('California', 2010):('Texas', 2000)])

# 例如,如果您需要从2010年中选择所有值
# 通过列表生成式,来生成2010对应的索引数据
print(pop[[i for i in pop.index if i[1] == 2010]])

# 上面的列表生成式的索引方式,代码看起来还是有些小复杂
# 下面我们用MultiIndex分层索引
'''
请注意,其中MultiIndex包含多个索引级别-在这种情况下,包括状态名称和年份,以及为每个数据点编码这些级别的多个标签。
'''
index = pd.MultiIndex.from_tuples(index)
print(index)

# 重置索引
pop = pop.reindex(index)
print(pop)

# 再次查询2010年的所有数据
print(pop[:, 2010])

# 取消堆叠
pop_df = pop.unstack()
print(pop_df)

# 堆叠
print(pop_df.stack())

# 添加一列
pop_df = pd.DataFrame({'total': pop,
                       'under18': [9267089, 9284094,
                                   4687374, 4318033,
                                   5906301, 6879014]})

print(pop_df)

# 根据上述数据,我们在此按年份计算了18岁以下的人口比例
f_u18 = pop_df['under18'] / pop_df['total']
print(f_u18.unstack())

# 创建多个索引的df
df = pd.DataFrame(np.random.rand(4, 2),
                  index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
                  columns=['data1', 'data2'])

print(df)

data = {('California', 2000): 33871648,
        ('California', 2010): 37253956,
        ('Texas', 2000): 20851820,
        ('Texas', 2010): 25145561,
        ('New York', 2000): 18976457,
        ('New York', 2010): 19378102}

print(pd.Series(data))

# 通过多个一维数组创建多维索引
index1 = pd.MultiIndex.from_arrays([['a', 'a', 'b', 'b'], [1, 2, 1, 2]])
print(index1)

# 通过多个元组创建多维索引
index2 = pd.MultiIndex.from_tuples([('a', 1), ('a', 2), ('b', 1), ('b', 2)])
print(index2)

# 通过单个索引的笛卡尔积构造它
index3 = pd.MultiIndex.from_product([['a', 'b'], [1, 2]])
print(index3)

# 通过传递levels(包含每个级别的可用索引值labels的列表的列表)和(引用这些标签的列表的列表)直接使用其内部编码来构造:
index4 = pd.MultiIndex(levels=[['a', 'b'], [1, 2]],
                       codes=[[0, 0, 1, 1], [0, 1, 0, 1]])
print(index4)

print(pop.index)

# 给多层索引的Series 索引起名
pop.index.names = ['state', 'year']
print(pop)

# 层次索引和列
index = pd.MultiIndex.from_product([[2013, 2014], [1, 2]], names=['year', 'visit'])

columns = pd.MultiIndex.from_product([['Bob', 'Guido', 'Sue'], ['HR', 'Temp']], names=['subject', 'type'])

# mock 一些数据
data = np.round(np.random.randn(4, 6), 1)
data[:, ::2] *= 10
data += 37

# create the DataFrame
health_data = pd.DataFrame(data, index=index, columns=columns)

'''DataFrames乘法索引'''
print(health_data)

# 通过人名来访问
print(health_data['Guido'])

# 索引和切片一个多指标
print(pop)

# 通过部分索引取值
print(pop['California'])

# 通过完整索引取值
print(pop['California', 2000])

# 通过部分索引,切片取值
print(pop.loc['California':'New York'])

# 使用部分索引取值.
print(pop.loc[:, 2000])

# 使用布尔索引
print(pop[pop > 22000000])

# 使用花式索引
print(pop[['California', 'Texas']])
print(health_data)
print(health_data['Guido', 'HR'])
print(health_data.iloc[:2, :2])  # 2行,2列
print(health_data.loc[:, ('Bob', 'HR')])

# 元组中创建切片将导致语法错误:
# print(health_data.loc[(:,1), (:, 'HR')])

# 上述解决方案
idx = pd.IndexSlice
print(health_data.loc[idx[:, 1], idx[:, 'HR']])

'''
警告 如果索引未排序,许多MultiIndex切片操作将失败。
'''

index = pd.MultiIndex.from_product([['a', 'c', 'b'], [1, 2]])
data = pd.Series(np.random.rand(6), index=index)
data.index.names = ['char', 'int']
print(data)

# 出错的原因就是,未对MultiIndex进行排序的结果。
# 熊猫提供了许多方便的例程来执行这种排序
# sort_index()和sortlevel()方法
try:
    data['a':'b']
except KeyError as e:
    print(type(e))
    print(e)

data = data.sort_index()
print(data)

print(data['a':'b'])

'''
Stacking and unstacking indices¶

说明:
如前所述,可以将数据集从堆叠的多索引转换为简单的二维表示形式,可以选择指定要使用的级别:
'''
print(pop)
print('---------------------')

print(pop.unstack(level=0))

print('---------------------')

print(pop.unstack(level=1))

print('---------------------')
# 与unstack()相反stack(),在这里可用于恢复原始系列:
print(pop.unstack().stack()) # 还原

'''指标设置和重置'''

# 重新排列层次结构数据的另一种方法是将索引标签转换为列
# 这可以通过该reset_index方法来完成

pop_flat = pop.reset_index(name='population')
print(pop_flat)
print(pop_flat.set_index(['state', 'year']))

'''多指标上的数据聚合'''

# 每年两次访问中的测量结果进行平均。
data_mean = health_data.mean(level='year')
print(data_mean)

# 使用axis关键字,我们还可以在列的各个级别之间取均值
print(data_mean.mean(axis=1, level='type'))

原创-Pandas心法之处理丢失数据-3

zhangtongle阅读(2489)

"""
# 6、处理丢失数据
"""
# 现实世界中的数据很少是干净且同质的。特别是,许多有趣的数据集将丢失一些数据

import numpy as np
import pandas as pd

# 第一种:缺少的数据为None
vals1 = np.array([1, None, 3, 4])
print(vals1)

# 因为数组里面有None控制,so,聚合函数报错
print(vals1.sum()) # 报错

# 第二种:另一个缺少的数据表示形式NaN
vals2 = np.array([1, np.nan, 3, 4])
print(vals2)
print(vals2.dtype)

# 这种缺失的数据,在计算和聚合的时候不会错误
print(1 + np.nan)
print(0 * np.nan)

# 使用nan式聚合函数
print(np.sum(vals2)) # 错误
print(np.nansum(vals2))
print(np.nanmin(vals2))

# NaN and None in Pandas¶
# 在pandas 里面None 和nan d都统一处理NaN
print(pd.Series([1, np.nan, 2, None]))
x = pd.Series(range(2), dtype=int)
print(x)
x[0] = None
print(x)

# 对空值进行处理
'''
isnull():生成一个布尔值掩码,指示缺少的值
notnull(): 的反面 isnull()
dropna():返回过滤后的数据版本
fillna():返回填充或估算缺失值的数据副本

'''

# 检查空值
data = pd.Series([1, np.nan, 'hello', None])

# 为空的布尔数组
print(data.isnull())

# 为空的数据
print(data[data.isnull()])

# 不为空的数据
print(data[data.notnull()])

# 删除空值
print(data.dropna())

# DataFrame 的空值处理
df = pd.DataFrame([[1, np.nan, 2],
                   [2, 3, 5],
                   [np.nan, 4, 6]])
print(df)

print('----------------')
print(df.dropna()) # 暴力的只要行中包括na就全行删除。

print(df.dropna(axis='columns')) # 只要列中包括na,就删除整列

# 增加一列全是nan的
df[3] = np.nan
print(df)
print('----------------')

# 删除某一列中全是nan 的数据
print(df.dropna(axis='columns', how='all'))

# 删除每行少于3个非空值的数据 ,thresh 为控制参数
print(df.dropna(axis='rows', thresh=3))
# 此处的第一行和最后一行已删除,因为它们仅包含两个非空值

# 填充空值,一味的删除也不是个办法
# 有时,您宁可使用有效值替换它们,也不要丢弃NA值
data = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))
print(data)
# 把空值都填充为零
print(data.fillna(0))

# 把空值填充为上一行不为空的值,叫向前填充
print(data.fillna(method='ffill'))

# 把空值填充为下一行不为空的值,叫向后填充
print(data.fillna(method='bfill'))

print(df)
print('-------')
print(df.fillna(method='ffill', axis=1)) # 沿X轴方向向前填充

# 请注意,如果在向前填充过程中先前值不可用,则NA值将保留。

原创-Pandas心法之初级数据操作与索引对齐-2

zhangtongle阅读(2543)

1、数据操作

"""
# 4、对熊猫中的数据进行操作
由于Pandas设计为可与NumPy配合使用,
因此任何NumPy ufunc均可在PandasSeries和DataFrame对象上使用
"""

import pandas as pd
import numpy as np

rng = np.random.RandomState(42)
ser = pd.Series(rng.randint(0, 10, 4))
print(ser)

df = pd.DataFrame(rng.randint(0, 10, (3, 4)),
                  columns=['A', 'B', 'C', 'D'])
print(df)
print(np.max(ser))  # 求Series 中最大的值

# 复杂一点的计算
print(np.sin(df * np.pi / 4))

2、索引对齐

'''
# 5、索引对齐
对于两个Series或两个DataFrame对象的二进制操作,Pandas将在执行操作的过程中对齐索引。在处理不完整的数据时,这非常方便
'''

# 两个Series 中有不同的index 索引
area = pd.Series({'Alaska': 1723337, 'Texas': 695662,
                  'California': 423967}, name='area')
population = pd.Series({'California': 38332521, 'Texas': 26448193,
                        'New York': 19651127}, name='population')

print(population / area)

# 找出两个Series 中所有行索引
print(area.index | population.index)
print(area.index & population.index)

# 处理索引不对齐的情况、
A = pd.Series([2, 4, 6], index=[0, 1, 2])
B = pd.Series([1, 3, 5], index=[1, 2, 3])
print(A + B)

# 使用NaN不是理想的行为.
# 处理方式,在索引不对齐的情况,把不存在的索引值填充为零。
print(A.add(B, fill_value=0))

df1 = pd.DataFrame(rng.randint(0, 20, (2, 2)),
                   columns=list('AB'))

print(df1)
print('------------------')

df2 = pd.DataFrame(rng.randint(0, 10, (3, 3)),
                   columns=list('BAC'))

print(df2)
print('------------------')
print(df1+df2)

'''
请注意,无论两个对象中的索引顺序如何,
索引都正确对齐,并且对结果中的索引进行排序
'''

# 更好的处理NaN处理方式
print(df1.stack()) # 堆叠,把列索引变行索引,相当于行的二级索引。
fill = df1.stack().mean()
print(fill)
df1.add(df2, fill_value=fill) # 把NaN 填充为均值。

'''
基础的运算符可以直接应用与DataFrame

+ add()
- sub(), subtract()
* mul(), multiply()
/ truediv(),div(),divide()
// floordiv()
% mod()
** pow()

'''

# numpy 二维数组处理 减法
A = rng.randint(10, size=(3, 4))
# print(A)
# print(A - A[0])

# DataFrame数据 处理方式
df = pd.DataFrame(A, columns=list('QRST'), index=['a', 'b', 'c'])
print(df)

print('--------------------')

# 取出列索引为Q 行索引名为a 的数据:3
print(df['Q']['a'])

# 。你的目的虽然是取出行索引全部的数据。但是语法方式行不通。
print(df['a'])  # 错误

# 通过堆叠,你可以取出行索引为a 的全部数据。
print(df.stack()['a'])  # 正确

print(df - df.iloc[0])  # 默认沿着行 axis =1 计算。

print(df['Q']) # 列索引
print(df.iloc[0]) # 行索引

# 如果要改为按列操作,
# 则可以在指定axis关键字的同时使用前面提到的对象方法:
print(df.subtract(df['R'], axis=0))

# 行数据索引为0,列索引步长为2.
halfrow = df.iloc[0, ::2]
print(halfrow)
print(df - halfrow)

特别的技术,给特别的你!

联系QQ:1071235258QQ群:710045715
error: Sorry,暂时内容不可复制!