<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>DataShare Blog</title><description>数据人阿多</description><link>https://datashare-duo.github.io/</link><language>zh_CN</language><item><title>Python与Rust类型参数对比：从TypeVar到泛型T</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/20260410-Python%E4%B8%8ERust%E7%B1%BB%E5%9E%8B%E5%8F%82%E6%95%B0%E5%AF%B9%E6%AF%94%EF%BC%9A%E4%BB%8ETypeVar%E5%88%B0%E6%B3%9B%E5%9E%8BT/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/20260410-Python%E4%B8%8ERust%E7%B1%BB%E5%9E%8B%E5%8F%82%E6%95%B0%E5%AF%B9%E6%AF%94%EF%BC%9A%E4%BB%8ETypeVar%E5%88%B0%E6%B3%9B%E5%9E%8BT/</guid><description>Python与Rust类型参数对比</description><pubDate>Fri, 10 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;一、相同的目标：占位符与泛化&lt;/h1&gt;
&lt;p&gt;无论是 Python 的 &lt;code&gt;TypeVar&lt;/code&gt; 还是 Rust 的 &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt;，它们的核心使命完全一致：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;定义一个“尚不确定具体类型”的占位符，让同一套代码逻辑安全地适用于多种不同类型&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;# Python: 定义一个泛型函数
from typing import TypeVar

T = TypeVar(&apos;T&apos;)

def first(items: list[T]) -&amp;gt; T:
    return items[0]
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// Rust: 定义一个泛型函数
fn first&amp;lt;T&amp;gt;(items: &amp;amp;[T]) -&amp;gt; &amp;amp;T {
    &amp;amp;items[0]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在两种语言中，类型检查器（Python 的 &lt;code&gt;mypy&lt;/code&gt; ， Rust 的 &lt;code&gt;rustc&lt;/code&gt;）都能根据调用上下文自动推导出 &lt;code&gt;T&lt;/code&gt; 的具体类型，并保证返回类型与输入元素类型一致&lt;/p&gt;
&lt;h1&gt;二、语法演进：殊途同归&lt;/h1&gt;
&lt;p&gt;Python 的类型标注语法一直在向更简洁、更内聚的方向演化，而 Rust 从一开始就采用了现在这种高效的形式&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;对比维度&lt;/th&gt;
&lt;th&gt;Python (&lt;code&gt;TypeVar&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Rust 泛型参数&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;传统声明&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;T = TypeVar(&apos;T&apos;)&lt;/code&gt;&amp;lt;br&amp;gt;&lt;code&gt;class Stack(Generic[T]):&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;struct Stack&amp;lt;T&amp;gt; { ... }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;现代声明（3.12+）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;class Stack[T]:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;struct Stack&amp;lt;T&amp;gt; { ... }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;函数定义&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;def func[T](arg: T) -&amp;gt; T:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fn func&amp;lt;T&amp;gt;(arg: T) -&amp;gt; T { ... }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;可以看到，Python 3.12 引入的 PEP 695 语法已经让 Python 的泛型写法与 Rust 高度趋同——类型变量直接写在类名或函数名后的方括号内&lt;/p&gt;
&lt;h1&gt;三、类型约束：继承（Inheritance） vs. 特征（Trait）&lt;/h1&gt;
&lt;p&gt;这是两种语言泛型系统最核心的差异所在&lt;/p&gt;
&lt;h2&gt;Python：基于&lt;strong&gt;继承&lt;/strong&gt;或&lt;strong&gt;协议&lt;/strong&gt;的上界约束&lt;/h2&gt;
&lt;p&gt;Python 通过 &lt;code&gt;bound&lt;/code&gt; 参数限定类型变量必须满足某个父类或协议（&lt;code&gt;Protocol&lt;/code&gt;）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from typing import TypeVar, Protocol

class SupportsClose(Protocol):
    def close(self) -&amp;gt; None: ...

T = TypeVar(&apos;T&apos;, bound=SupportsClose)

def safe_close(obj: T) -&amp;gt; T:
    obj.close()
    return obj
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;约束依据：&lt;strong&gt;是不是某个类的子类&lt;/strong&gt;，或者&lt;strong&gt;是否实现了特定的方法集&lt;/strong&gt;（鸭子类型）&lt;/li&gt;
&lt;li&gt;运行时行为：&lt;code&gt;isinstance&lt;/code&gt; 可以检查继承关系，但 &lt;code&gt;TypeVar&lt;/code&gt; 本身不参与运行时类型强制&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Rust：基于 &lt;strong&gt;Trait&lt;/strong&gt; 的行为约束&lt;/h2&gt;
&lt;p&gt;Rust 没有传统意义上的继承，类型能否用作泛型参数完全取决于它是否&lt;strong&gt;实现了指定的 Trait&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use std::io::Write;

fn write_twice&amp;lt;T: Write&amp;gt;(mut writer: T) -&amp;gt; std::io::Result&amp;lt;()&amp;gt; {
    writer.write_all(b&quot;hello&quot;)?;
    writer.write_all(b&quot;world&quot;)?;
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;约束依据：&lt;strong&gt;实现了哪些 Trait&lt;/strong&gt;，Trait 是显式的“行为契约”，不是隐式的继承关系&lt;/li&gt;
&lt;li&gt;编译时强制：如果传入的类型没有实现 &lt;code&gt;Write&lt;/code&gt;，编译&lt;strong&gt;直接失败&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;学习提示&lt;/strong&gt;：Python 的 &lt;code&gt;bound=SomeProtocol&lt;/code&gt; 在思想上最接近 Rust 的 &lt;code&gt;T: SomeTrait&lt;/code&gt;。可以把 Rust 的 Trait 理解为必须显式声明并实现的、编译期强制的 Python &lt;code&gt;Protocol&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;四、型变（Variance）：显式声明 vs. 自动推导&lt;/h1&gt;
&lt;p&gt;型变（&lt;strong&gt;协变&lt;/strong&gt;、&lt;strong&gt;逆变&lt;/strong&gt;、&lt;strong&gt;不变&lt;/strong&gt;）是理解容器类型间替换关系的关键，Python 与 Rust 对型变的处理方式差异巨大&lt;/p&gt;
&lt;h2&gt;Python：定义 &lt;code&gt;TypeVar&lt;/code&gt; 时&lt;strong&gt;显式声明&lt;/strong&gt;型变&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;from typing import TypeVar, Generic

T_co = TypeVar(&apos;T_co&apos;, covariant=True)      # 协变：只产出数据
T_contra = TypeVar(&apos;T_contra&apos;, contravariant=True)  # 逆变：只消费数据
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;如果希望 &lt;code&gt;Reader[Dog]&lt;/code&gt; 可以赋值给 &lt;code&gt;Reader[Animal]&lt;/code&gt;，必须将 &lt;code&gt;T&lt;/code&gt; 标记为 &lt;code&gt;covariant=True&lt;/code&gt;，为可协变的&lt;/li&gt;
&lt;li&gt;默认行为是&lt;strong&gt;不变&lt;/strong&gt;（既不协变也不逆变），这是最安全的默认值&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Rust：编译器&lt;strong&gt;自动推导&lt;/strong&gt;型变&lt;/h2&gt;
&lt;p&gt;Rust 的类型系统会分析泛型参数在结构体或枚举中的&lt;strong&gt;使用方式&lt;/strong&gt;，自动决定其型变&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;struct Producer&amp;lt;T&amp;gt; {
    value: T,           // 只产出 T，编译器自动推导为协变
}

struct Consumer&amp;lt;T&amp;gt; {
    _marker: std::marker::PhantomData&amp;lt;fn(T)&amp;gt;, // 只消费 T，编译器自动推导为逆变
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Rust 不需要（也不能）用关键字显式声明协变/逆变，这减少了心智负担&lt;/li&gt;
&lt;li&gt;型变信息主要用于&lt;strong&gt;生命周期&lt;/strong&gt;的协变/逆变，对普通类型参数影响较小&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;核心口诀对比&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt;：你需要自己声明型变（&lt;code&gt;covariant&lt;/code&gt;/&lt;code&gt;contravariant&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rust&lt;/strong&gt;：编译器帮你搞定，你只需关注类型是否被&lt;strong&gt;读&lt;/strong&gt;（产出→协变）或被&lt;strong&gt;写&lt;/strong&gt;（消费→逆变）&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h1&gt;五、运行时存在性：类型擦除 vs. 单态化&lt;/h1&gt;
&lt;p&gt;这一点是两者运行时行为的根本区别，直接影响你对“泛型性能”的认知&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;Python (&lt;code&gt;TypeVar&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Rust 泛型&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;何时检查&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;静态类型检查器（mypy、pyright）&lt;/td&gt;
&lt;td&gt;编译器（rustc）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;运行时类型信息&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;完全擦除&lt;/strong&gt;。&lt;code&gt;list[int]&lt;/code&gt; 和 &lt;code&gt;list[str]&lt;/code&gt; 在运行时都是 &lt;code&gt;list&lt;/code&gt;。&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;单态化（Monomorphization）&lt;/strong&gt;。为每个具体类型生成独立代码。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;性能影响&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;零运行时开销（因为标注只是注释），但对运行速度无提升。&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;零成本抽象&lt;/strong&gt;。运行时性能等同于手写的具体类型代码，无动态分发开销。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;可否用 &lt;code&gt;isinstance&lt;/code&gt; 检查&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ 不可。&lt;code&gt;isinstance(obj, list[T])&lt;/code&gt; 是无效的。&lt;/td&gt;
&lt;td&gt;❌ 不可，但编译时静态分发已保证类型正确。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关键理解&lt;/strong&gt;：
Python 的泛型是&lt;strong&gt;给工具看的&lt;/strong&gt;，运行时 Python 解释器根本不知道 &lt;code&gt;T&lt;/code&gt; 是什么
Rust 的泛型是&lt;strong&gt;给编译器看的&lt;/strong&gt;，编译后 &lt;code&gt;Option&amp;lt;i32&amp;gt;&lt;/code&gt; 和 &lt;code&gt;Option&amp;lt;String&amp;gt;&lt;/code&gt; 是完全不同的两套机器码&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;六、高级特性对照表&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;Python&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;多个类型参数&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;class Pair[K, V]:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;struct Pair&amp;lt;K, V&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;常量泛型&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ 不支持&lt;/td&gt;
&lt;td&gt;&lt;code&gt;struct Array&amp;lt;T, const N: usize&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;可变长度类型参数&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TypeVarTuple&lt;/code&gt;（用于 &lt;code&gt;*args&lt;/code&gt; 类型）&lt;/td&gt;
&lt;td&gt;通过元组或宏实现，无直接语法糖&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;高阶类型（泛型上的泛型）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ParamSpec&lt;/code&gt;（用于装饰器参数签名捕获）&lt;/td&gt;
&lt;td&gt;通过关联类型（Associated Types）和泛型 trait 部分实现&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;幽灵类型标记&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;不需要（类型已擦除）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PhantomData&amp;lt;T&amp;gt;&lt;/code&gt; 用于标记未直接使用的类型参数&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;七、从 Python 到 Rust：学习路径建议&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先理解 Python &lt;code&gt;TypeVar&lt;/code&gt; 的作用域与约束&lt;/strong&gt;：熟悉 &lt;code&gt;bound&lt;/code&gt; 和 &lt;code&gt;Protocol&lt;/code&gt;，它们是 Rust &lt;code&gt;Trait&lt;/code&gt; 约束的心理映射&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;接受“编译时单态化”的概念&lt;/strong&gt;：Python 里你写 &lt;code&gt;def func[T](x: T)&lt;/code&gt; 只有一个函数对象；Rust 里会为每个 &lt;code&gt;T&lt;/code&gt; 生成一份独立的机器码。这是 Rust 高性能的来源，也是二进制体积可能增大的原因&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;忘记 Python 的型变显式声明&lt;/strong&gt;：在 Rust 中，你几乎不需要手动操心协变/逆变，编译器会帮你处理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;掌握 Rust Trait 系统&lt;/strong&gt;：如果说 Python 的 &lt;code&gt;TypeVar&lt;/code&gt; 是“占位符”，那么 Rust 的 &lt;code&gt;Trait&lt;/code&gt; 就是“准入证”。学好 Trait 是写好 Rust 泛型代码的关键&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;八、总结对比表&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;Python (&lt;code&gt;TypeVar&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Rust 泛型&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;定义方式&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;T = TypeVar(&apos;T&apos;)&lt;/code&gt; 或 &lt;code&gt;class C[T]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;struct S&amp;lt;T&amp;gt;&lt;/code&gt; 或 &lt;code&gt;fn f&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;类型约束&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bound=BaseClass&lt;/code&gt; 或 &lt;code&gt;bound=Protocol&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;T: Trait&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;型变控制&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;显式声明 &lt;code&gt;covariant&lt;/code&gt; / &lt;code&gt;contravariant&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;编译器自动推导&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;运行时行为&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;类型擦除，仅用于静态检查&lt;/td&gt;
&lt;td&gt;单态化，零成本抽象&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;学习重心&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;理解继承、协议与型变规则&lt;/td&gt;
&lt;td&gt;理解 Trait、所有权与单态化&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;掌握了 Python 的 &lt;code&gt;TypeVar&lt;/code&gt; 和泛型思维，你已经拥有了理解 Rust 泛型系统的核心“元认知”。接下来只需要将“继承约束”切换为“Trait 约束”，将“运行时擦除”切换为“编译时单态化”，就能顺利迈入 Rust 的类型世界，可以利用已有的 Python 类型知识平滑过渡到 Rust 的泛型思维&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Rust-%E6%98%AF%E5%90%A6%E4%BC%9A%E9%87%8D%E5%86%99-Python-%E8%A7%A3%E9%87%8A%E5%99%A8%E4%B8%8E%E6%9C%89%E5%85%B3%E7%9A%84%E5%BA%93%EF%BC%8C%E6%9B%BF%E4%BB%A3-C-%E8%AF%AD%E8%A8%80%E5%9C%B0%E4%BD%8D%EF%BC%9F.md&quot;&gt;Rust-是否会重写-Python-解释器与有关的库，替代-C-语言地位？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%96%B0%E6%99%8B%E5%8C%85%E9%A1%B9%E7%9B%AE%E5%B7%A5%E5%85%B7uv%E7%9A%84%E7%AE%80%E5%8D%95%E5%B0%9D%E8%AF%95.md&quot;&gt;Python-新晋包项目工具uv的简单尝试&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E6%96%B0%E6%80%9D%E8%B7%AF%EF%BC%9A%E7%94%A8-uv-Workspace-%E5%85%B1%E4%BA%AB%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%EF%BC%8C%E7%9C%81%E6%97%B6%E7%9C%81%E7%A9%BA%E9%97%B4%EF%BC%81.md&quot;&gt;Python-项目管理新思路：用-uv-Workspace-共享虚拟环境，省时省空间！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%88%A9%E7%94%A8-uv-%E2%80%9C%E4%B8%80%E9%94%AE%E2%80%9D-%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E6%9C%8D%E5%8A%A1.md&quot;&gt;Python-利用-uv-“一键”-快速部署服务&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 装饰器的灵活实现：带参数与不带参数</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/20260204-Python-%E8%A3%85%E9%A5%B0%E5%99%A8%E7%9A%84%E7%81%B5%E6%B4%BB%E5%AE%9E%E7%8E%B0%EF%BC%9A%E5%B8%A6%E5%8F%82%E6%95%B0%E4%B8%8E%E4%B8%8D%E5%B8%A6%E5%8F%82%E6%95%B0/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/20260204-Python-%E8%A3%85%E9%A5%B0%E5%99%A8%E7%9A%84%E7%81%B5%E6%B4%BB%E5%AE%9E%E7%8E%B0%EF%BC%9A%E5%B8%A6%E5%8F%82%E6%95%B0%E4%B8%8E%E4%B8%8D%E5%B8%A6%E5%8F%82%E6%95%B0/</guid><description>Python 装饰器</description><pubDate>Wed, 04 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;装饰器是Python中一种强大的语法糖，它允许我们在不修改原函数代码的情况下，为函数添加额外的功能。装饰器本质上是一个可调用对象，它接受一个函数作为输入，并返回一个新的函数。装饰器的使用方式非常灵活，既可以不带参数使用，也可以带参数使用&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;函数装饰器实现&lt;/h1&gt;
&lt;p&gt;我们先来看一个简单的函数装饰器实现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import time

def delayed_start(func=None, *, duration=1):
    def decorator(_func):
        def wrapper(*args, **kwargs):
            print(f&quot;Wait for {duration} seconds before starting...&quot;)
            time.sleep(duration)
            return _func(*args, **kwargs)
        return wrapper

    if func is None:
        return decorator
    else:
        return decorator(func)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个装饰器可以以两种方式使用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不带参数使用&lt;/strong&gt;：当装饰器不带参数使用时，Python会直接将装饰的函数作为参数传递给 &lt;code&gt;delayed_start&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;@delayed_start
def hello_no_arg(name=&quot;datashare&quot;):
    print(&quot;from hello_no_arg, param name =&quot;, name)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等价于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hello_no_arg = delayed_start(hello_no_arg)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;带参数使用&lt;/strong&gt;：当装饰器带参数使用时，Python会先调用装饰器函数，返回一个真正的装饰器，然后再用这个装饰器装饰函数&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;@delayed_start(duration=2)
def hello_with_arg(name=&quot;datashare&quot;):
    print(&quot;from hello_with_arg, param name =&quot;, name)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等价于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hello_with_arg = delayed_start(duration=2)(hello_with_arg)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;实现原理&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;delayed_start&lt;/code&gt;函数的巧妙之处在于它通过检查 &lt;code&gt;func&lt;/code&gt;参数是否为 &lt;code&gt;None&lt;/code&gt;来判断装饰器的使用方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果 &lt;code&gt;func&lt;/code&gt;不是 &lt;code&gt;None&lt;/code&gt;，说明是不带参数使用，直接返回 &lt;code&gt;decorator(func)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;func&lt;/code&gt;是 &lt;code&gt;None&lt;/code&gt;，说明是带参数使用，返回 &lt;code&gt;decorator&lt;/code&gt;函数等待接收真正的函数参数&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;类装饰器实现&lt;/h1&gt;
&lt;p&gt;类装饰器通过实现 &lt;code&gt;__call__&lt;/code&gt;方法来实现装饰器的功能。下面是带参数和不带参数的类装饰器实现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from functools import wraps
import time

class Timer:
    def __init__(self, func=None, *, print_args=False):
        self.func = func
        self.print_args = print_args

    def __call__(self, *args, **kwargs):
        # 情况 1：@Timer(print_args=True)
        # 第一次 __call__，args[0] 是函数
        if self.func is None:
            func = args[0]
            return self._decorate(func)

        # 情况 2：@Timer
        # 或者已经绑定好函数，真正执行
        return self._decorate(self.func)(*args, **kwargs)

    def _decorate(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            st = time.perf_counter()
            ret = func(*args, **kwargs)

            if self.print_args:
                print(f&apos;&quot;{func.__name__}&quot;, args: {args}, kwargs: {kwargs}&apos;)

            print(f&quot;time cost: {time.perf_counter() - st:.4f} seconds&quot;)
            return ret

        return wrapper
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不带参数使用&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;@Timer
def compute(x):
    time.sleep(1)
    return x * 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当类装饰器不带参数使用时，Python会创建 &lt;code&gt;Timer&lt;/code&gt;类的实例，并将 &lt;code&gt;compute&lt;/code&gt;函数传递给 &lt;code&gt;__init__&lt;/code&gt;方法。此时 &lt;code&gt;self.func&lt;/code&gt;就是 &lt;code&gt;compute&lt;/code&gt;函数。当我们调用 &lt;code&gt;compute(10)&lt;/code&gt;时，实际上是调用 &lt;code&gt;Timer&lt;/code&gt;实例的 &lt;code&gt;__call__&lt;/code&gt;方法&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;带参数使用&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;@Timer(print_args=True)
def compute2(x):
    time.sleep(1)
    return x * 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当类装饰器带参数使用时，Python会先调用 &lt;code&gt;Timer(print_args=True)&lt;/code&gt;创建实例，此时 &lt;code&gt;self.func&lt;/code&gt;为 &lt;code&gt;None&lt;/code&gt;。然后用这个实例去装饰 &lt;code&gt;compute2&lt;/code&gt;函数，这相当于调用 &lt;code&gt;Timer&lt;/code&gt;实例的 &lt;code&gt;__call__&lt;/code&gt;方法，并将 &lt;code&gt;compute2&lt;/code&gt;作为参数传入&lt;/p&gt;
&lt;h1&gt;两种实现方式的比较&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;函数装饰器&lt;/th&gt;
&lt;th&gt;类装饰器&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;代码简洁性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;更简洁，适合简单的装饰逻辑&lt;/td&gt;
&lt;td&gt;更复杂，但结构更清晰&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;状态管理&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;需要使用闭包或nonlocal变量&lt;/td&gt;
&lt;td&gt;可以使用实例属性，更直观&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;可扩展性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;适合简单的装饰功能&lt;/td&gt;
&lt;td&gt;适合需要维护状态的复杂装饰器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;可读性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;对于简单场景更易读&lt;/td&gt;
&lt;td&gt;对于复杂场景更易维护&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;实际应用场景&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;性能监控&lt;/strong&gt;：如 &lt;code&gt;Timer&lt;/code&gt;装饰器，用于测量函数执行时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;权限验证&lt;/strong&gt;：检查用户是否有权限执行某个函数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日志记录&lt;/strong&gt;：自动记录函数的调用和参数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓存&lt;/strong&gt;：实现函数结果的缓存，提高性能&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重试机制&lt;/strong&gt;：当函数执行失败时自动重试&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;最佳实践&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;使用 &lt;code&gt;functools.wraps&lt;/code&gt;装饰器来保留原函数的元数据（如函数名、文档字符串等）&lt;/li&gt;
&lt;li&gt;对于简单的装饰器，优先使用函数装饰器&lt;/li&gt;
&lt;li&gt;对于需要维护状态的装饰器，考虑使用类装饰器&lt;/li&gt;
&lt;li&gt;在设计带参数的装饰器时，确保同时支持带参数和不带参数的使用方式&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;总结&lt;/h1&gt;
&lt;p&gt;Python装饰器是一个强大而灵活的特性，它允许我们以非侵入式的方式增强函数的功能。通过掌握函数装饰器和类装饰器的实现方式，以及如何实现带参数和不带参数的装饰器，我们可以编写出更加通用和可重用的代码。无论是简单的函数增强还是复杂的状态管理，装饰器都能提供优雅的解决方案&lt;/p&gt;
&lt;p&gt;理解装饰器的工作原理不仅有助于我们编写更好的装饰器，还能加深我们对Python函数式编程和元编程的理解，是成为高级Python开发者的重要一步&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-2%E4%B8%AA%E5%A5%BD%E7%94%A8%E7%9A%84%E8%A3%85%E9%A5%B0%E5%99%A8%E5%87%BD%E6%95%B0.md&quot;&gt;Python-2个好用的装饰器函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B%E4%B8%8E%E4%BD%BF%E7%94%A8%E8%A7%84%E5%88%99%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python-函数参数类型与使用规则详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%88%A9%E7%94%A8partial%E5%81%8F%E5%87%BD%E6%95%B0%EF%BC%8C%E7%94%9F%E6%88%90%E4%B8%8D%E5%90%8C%E7%9A%84%E8%81%9A%E5%90%88%E5%87%BD%E6%95%B0.md&quot;&gt;Python利用partial偏函数，生成不同的聚合函数&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-11-用户自定义函数</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-11-%E7%94%A8%E6%88%B7%E8%87%AA%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-11-%E7%94%A8%E6%88%B7%E8%87%AA%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0/</guid><description>Polars python 自定义函数如何与 polars 结合使用</description><pubDate>Mon, 26 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;polars学习系列文章，第11篇 用户自定义函数，python 自定义函数如何与 polars 结合使用&lt;/p&gt;
&lt;p&gt;该库目前已更新到 &lt;code&gt;1.37.1&lt;/code&gt; 版本，近一年版本更新迭代的速度非常快，之前分享的前10篇文章的版本是 &lt;code&gt;1.2.1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;该系列文章会分享到github，大家可以去下载jupyter文件，进行参考学习
仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;小编运行环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;, sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11 

import polars as pl

print(&quot;polars 版本：&quot;, pl.__version__)
#polars 版本： 1.37.1
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;提供的 api 函数/接口/方法&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;map_elements&lt;/code&gt; ：对列中的每个值，传入函数，类似pandas中的map&lt;/li&gt;
&lt;li&gt;&lt;code&gt;map_batches&lt;/code&gt; ：整个列全部传入函数，类似pandas中的apply&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;示例数据&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;df = pl.DataFrame(
    {
        &quot;keys&quot;: [&quot;a&quot;, &quot;a&quot;, &quot;b&quot;, &quot;b&quot;],
        &quot;values&quot;: [10, 7, 1, 23],
    }
)
print(df)
shape: (4, 2)
┌──────┬────────┐
│ keys ┆ values │
│ ---  ┆ ---    │
│ str  ┆ i64    │
╞══════╪════════╡
│ a    ┆ 10     │
│ a    ┆ 7      │
│ b    ┆ 1      │
│ b    ┆ 23     │
└──────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;map_elements 用法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;import math 

def my_log(value):
    return math.log(value)  # math.log 应用与每个值

out = df.select(pl.col(&quot;values&quot;).map_elements(my_log, return_dtype=pl.Float64))
print(out)
shape: (4, 1)
┌──────────┐
│ values   │
│ ---      │
│ f64      │
╞══════════╡
│ 2.302585 │
│ 1.94591  │
│ 0.0      │
│ 3.135494 │
└──────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;存在问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;限于单个项&lt;/strong&gt;：只用应用在单个值上面，而不能一次应用到整个列&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能开销&lt;/strong&gt;：为每个单独的项调用函数也很慢，所有这些额外的函数调用会增加大量的开销&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;map_batches 用法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;def diff_from_mean(series):
    total = 0
    for value in series:
        total += value
    mean = total / len(series)
    return pl.Series([value - mean for value in series])

out = df.select(pl.col(&quot;values&quot;).map_batches(diff_from_mean, return_dtype=pl.Float64))
print(&quot;== select() with UDF ==&quot;)
print(out)
== select() with UDF ==
shape: (4, 1)
┌────────┐
│ values │
│ ---    │
│ f64    │
╞════════╡
│ -0.25  │
│ -3.25  │
│ -9.25  │
│ 12.75  │
└────────┘

print(&quot;== group_by() with UDF ==&quot;)
out = df.group_by(&quot;keys&quot;).agg(
    pl.col(&quot;values&quot;).map_batches(diff_from_mean, return_dtype=pl.Float64)
)
print(out)
== group_by() with UDF ==
shape: (2, 2)
┌──────┬───────────────┐
│ keys ┆ values        │
│ ---  ┆ ---           │
│ str  ┆ list[f64]     │
╞══════╪═══════════════╡
│ a    ┆ [1.5, -1.5]   │
│ b    ┆ [-11.0, 11.0] │
└──────┴───────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;提升用户自定义函数性能&lt;/h1&gt;
&lt;h2&gt;numpy 通用函数&lt;/h2&gt;
&lt;p&gt;纯python实现的自定义函数一般速度都比较慢，要尽量减少代用python实现的方法，可以调用 numpy 中的实现的通用函数/算子，来加速，实际是通过调用C语言的轮子来加速&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import numpy as np

out = df.select(pl.col(&quot;values&quot;).map_batches(np.log, return_dtype=pl.Float64))
print(out)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;通过 Numba 提升自定义函数性能&lt;/h2&gt;
&lt;p&gt;如果 numpy 中没有可用的函数，那么自定义函数可以通过 Numba 来提速，即时编译&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from numba import guvectorize, int64, float64

@guvectorize([(int64[:], float64[:])], &quot;(n)-&amp;gt;(n)&quot;)
def diff_from_mean_numba(arr, result):
    total = 0
    for value in arr:
        total += value
    mean = total / len(arr)
    for i, value in enumerate(arr):
        result[i] = value - mean


out = df.select(
    pl.col(&quot;values&quot;).map_batches(diff_from_mean_numba, return_dtype=pl.Float64)
)
print(&quot;== select() with UDF ==&quot;)
print(out)

out = df.group_by(&quot;keys&quot;).agg(
    pl.col(&quot;values&quot;).map_batches(diff_from_mean_numba, return_dtype=pl.Float64)
)
print(&quot;== group_by() with UDF ==&quot;)
print(out)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;注意事项&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;加速时，数据缺失是不行的&lt;/strong&gt;，在利用numba装饰器&lt;code&gt;@guvectorize&lt;/code&gt;加速时，要么填充缺失值，要么删除缺失值，否则polars会报错&lt;/p&gt;
&lt;h1&gt;组合多列&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;@guvectorize([(int64[:], int64[:], float64[:])], &quot;(n),(n)-&amp;gt;(n)&quot;)
def add(arr, arr2, result):
    for i in range(len(arr)):
        result[i] = arr[i] + arr2[i]


df3 = pl.DataFrame({&quot;values_1&quot;: [1, 2, 3], &quot;values_2&quot;: [10, 20, 30]})

out = df3.select(
    pl.struct([&quot;values_1&quot;, &quot;values_2&quot;])
    .map_batches(
        lambda combined: add(
            combined.struct.field(&quot;values_1&quot;), combined.struct.field(&quot;values_2&quot;)
        ),
        return_dtype=pl.Float64,
    )
    .alias(&quot;add_columns&quot;)
)
print(out)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;流式计算&lt;/h1&gt;
&lt;p&gt;可以使用 &lt;code&gt;map_batches&lt;/code&gt; 的 &lt;code&gt;is_elementwise=True&lt;/code&gt; 参数将结果流式传输到函数中&lt;/p&gt;
&lt;p&gt;设置流式计算，需要确保是针对每个值进行计算，更节省内存&lt;/p&gt;
&lt;h1&gt;返回数据类型&lt;/h1&gt;
&lt;p&gt;返回数据类型是自动推断的，第一个非空值类型，作为结果类型&lt;/p&gt;
&lt;p&gt;python 与 polars 数据类型映射：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;int -&amp;gt; Int64&lt;/li&gt;
&lt;li&gt;float -&amp;gt; Float64&lt;/li&gt;
&lt;li&gt;bool -&amp;gt; Boolean&lt;/li&gt;
&lt;li&gt;str -&amp;gt; String&lt;/li&gt;
&lt;li&gt;list[tp] -&amp;gt; List[tp]&lt;/li&gt;
&lt;li&gt;dict[str, [tp]] -&amp;gt; struct&lt;/li&gt;
&lt;li&gt;any -&amp;gt; object  尽量禁止这种情况&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以将 &lt;code&gt;return_dtype&lt;/code&gt; 参数传递给 &lt;code&gt;map_batches&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6.md&quot;&gt;Python polars学习-01 读取与写入文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F.md&quot;&gt;Python polars学习-02 上下文与表达式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-03_%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2.md&quot;&gt;Python polars学习-03 数据类型转换&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-04_%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python polars学习-04 字符串数据处理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-05_%E5%8C%85%E5%90%AB%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.md&quot;&gt;Python polars学习-05 包含的数据结构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-06_Lazy-Eager-API.md&quot;&gt;Python polars学习-06 Lazy / Eager API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-07_%E7%BC%BA%E5%A4%B1%E5%80%BC.md&quot;&gt;Python polars学习-07 缺失值&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-08_%E5%88%86%E7%B1%BB%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python polars学习-08 分类数据处理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-09_%E6%95%B0%E6%8D%AE%E6%A1%86%E5%85%B3%E8%81%94%E4%B8%8E%E6%8B%BC%E6%8E%A5.md&quot;&gt;Python polars学习-09 数据框关联与拼接&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-polars%E5%AD%A6%E4%B9%A0-10-%E6%97%B6%E9%97%B4%E5%BA%8F%E5%88%97%E7%B1%BB%E5%9E%8B.md&quot;&gt;Python-polars学习-10-时间序列类型&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 利用 uv “一键” 快速部署服务</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%88%A9%E7%94%A8-uv-%E2%80%9C%E4%B8%80%E9%94%AE%E2%80%9D-%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E6%9C%8D%E5%8A%A1/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%88%A9%E7%94%A8-uv-%E2%80%9C%E4%B8%80%E9%94%AE%E2%80%9D-%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E6%9C%8D%E5%8A%A1/</guid><description>Python uv部署服务</description><pubDate>Wed, 14 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;随着Python在Web开发、数据科学等领域的广泛应用，项目依赖管理与环境部署的效率直接影响着开发体验。传统的Python项目往往需要结合 virtualenv、pip 乃至 pipenv/poetry 等多种工具进行环境隔离、依赖安装与版本管理，步骤繁琐且容易因环境不一致导致运行问题&lt;/p&gt;
&lt;p&gt;最近以来，一个名为 &lt;strong&gt;uv&lt;/strong&gt; 的现代化、高性能 Python 包管理工具由 Astral 团队推出，它集成了虚拟环境管理、依赖解析与安装、项目初始化等核心功能，并以其极快的速度和简洁的命令受到开发者关注。uv 旨在简化 Python 项目的搭建与协作流程，通过一行命令即可完成从零开始的环境构建与依赖同步，大大提升了项目初始化与部署的效率&lt;/p&gt;
&lt;p&gt;本文将基于一个实际的 FastAPI 项目案例，演示如何利用 uv 快速拉取现有项目、一键部署完整运行环境&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;拉取项目&lt;/h1&gt;
&lt;p&gt;这里以小编创建好的一个测试项目为案例进行操作，页面比较简单
github地址：https://github.com/DataShare-duo/uv_project&lt;/p&gt;
&lt;p&gt;在本地终端或者git bash上执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone git@github.com:DataShare-duo/uv_project.git
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;uv 部署环境&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;前提：github上拉取的项目，必须是基于 &lt;code&gt;uv&lt;/code&gt; 构建的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;部署服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ./uv_project
uv sync 
uv run main.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在浏览器打开 http://0.0.0.0:8000 即可访问后端的服务，是不是很简单，可见 &lt;code&gt;uv&lt;/code&gt; 工具是多么强大，通过一个命令 &lt;code&gt;uv sync&lt;/code&gt; 构建好了项目的运行虚拟环境，即可启动服务，以往构建环境是多么的痛苦
&lt;img src=&quot;./images/6641583-ffe5093e993b0edd.png&quot; alt=&quot;前端页面&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;本地基于 uv 项目构建&lt;/h1&gt;
&lt;p&gt;以上的测试项目在本地通过 &lt;code&gt;uv&lt;/code&gt; 构建的过程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uv init uv_project --python 3.11
cd uv_project 
uv add fastapi
uv add uvicorn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该项目的前、后端代码，均是利用 DeepSeek 生成，并调试运行成功&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E6%96%B0%E6%80%9D%E8%B7%AF%EF%BC%9A%E7%94%A8-uv-Workspace-%E5%85%B1%E4%BA%AB%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%EF%BC%8C%E7%9C%81%E6%97%B6%E7%9C%81%E7%A9%BA%E9%97%B4%EF%BC%81.md&quot;&gt;Python-项目管理新思路：用-uv-Workspace-共享虚拟环境，省时省空间！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%96%B0%E6%99%8B%E5%8C%85%E9%A1%B9%E7%9B%AE%E5%B7%A5%E5%85%B7uv%E7%9A%84%E7%AE%80%E5%8D%95%E5%B0%9D%E8%AF%95.md&quot;&gt;Python-新晋包项目工具uv的简单尝试&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>《Python-编程从新手到高手》知识点</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/%E3%80%8APython-%E7%BC%96%E7%A8%8B%E4%BB%8E%E6%96%B0%E6%89%8B%E5%88%B0%E9%AB%98%E6%89%8B%E3%80%8B%E7%9F%A5%E8%AF%86%E7%82%B9/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/%E3%80%8APython-%E7%BC%96%E7%A8%8B%E4%BB%8E%E6%96%B0%E6%89%8B%E5%88%B0%E9%AB%98%E6%89%8B%E3%80%8B%E7%9F%A5%E8%AF%86%E7%82%B9/</guid><description>Python 编程从新手到高手知识点</description><pubDate>Tue, 23 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;最近小编利用业余时间充电，细读了《Python 编程从新手到高手》这本书的部分章节，作者：【美】贾森·C. 麦克唐纳，其中确实藏了不少干货！一些之前未曾涉猎的知识点，这次也被一一解锁。整理出来部分内容，分享给大家一起学习交流，共同进步呀～ 📚✨&lt;/p&gt;
&lt;p&gt;&lt;em&gt;该书中文版的翻译还是差点意思，读起来不是很通顺&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Python中的变量：名称和值&lt;/h1&gt;
&lt;p&gt;原文中关于 &lt;strong&gt;变量&lt;/strong&gt; 的描述：Python 用name（名称）和 value（值）来代替variable（变量）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个name指向一个value或object（对象），就像你的名字指向你一样。可能有多个name指向同一个value，就像你可能有一个名字和一个昵称&lt;/li&gt;
&lt;li&gt;一个value是内存中一个特定的数据实例&lt;/li&gt;
&lt;li&gt;“变量”这个术语指代这两者的组合：一个name指向一个value&lt;/li&gt;
&lt;li&gt;名称有作用域，它们随着函数的出现而出现，随着函数的消失而消失，但是它们没有类型&lt;/li&gt;
&lt;li&gt;值有类型，但是没有作用域&lt;/li&gt;
&lt;li&gt;名称被绑定到值，而这些值存在于内存中，且有一些引用指向它们。你可以把一个名称绑定到任何你想要的值上，但是你只能对特定的值执行一些有限的操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;作者强调：虽然Python是一种动态类型的语言，但是Python仍然是一种强类型的语言。名称可以随意绑定到不同类型的值上面，但是任何值都是有类型的&lt;/p&gt;
&lt;h1&gt;类属性与类方法&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;类属性属于类本身，而不属于某个实例。实际上，这意味着所有相关的类实例“共享”类属性。即使没有任何实例，类属性也依然存在&lt;/li&gt;
&lt;li&gt;类方法属于类，而不属于类的某个实例&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;@classmethod
def inform(cls, codeword):
    cls._codeword = codeword
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码在类方法上使用了@classmethod装饰器。类方法将类作为其第一个参数接收，因此第一个参数被命名为cls。该inform()类方法既可以直接在SecretAgent类上调用，也可以在任何SecretAgent实例（如fox）上调用。inform()对类属性_codeword所做的更改会出现在类本身及其所有实例上&lt;/p&gt;
&lt;h1&gt;流&lt;/h1&gt;
&lt;p&gt;要想处理任何数据文件，你需要获得一个流（又称文件对象或类文件对象），其提供读取和写入内存中的特定文件的方法。一般存在两种流：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;二进制流是所有流的基础，用来处理二进制数据（0和1）&lt;/li&gt;
&lt;li&gt;文本流则处理二进制文本的编码和解码&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;print 刷新&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;指定参数：&lt;code&gt;print(&apos;.&apos;, end=&apos;&apos;, flush=True)&lt;/code&gt;，大家一般使用的方法&lt;/li&gt;
&lt;li&gt;全局的方法：如果需要所有的print()调用默认每次都刷新，可以在非缓冲模式下运行Python，只需要在调用程序时将-u选项传递给Python解释器即可，如&lt;code&gt;python3 -u test.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;并发与并行&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;并发（concurrency）是编程中的多任务处理：在多个任务之间快速分配程序的注意力&lt;/li&gt;
&lt;li&gt;并行（parallelism），并行是指多个任务同时发生&lt;/li&gt;
&lt;li&gt;有两种方法可以在Python中实现并发：线程、异步&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;重点是记住这2个英文单词，比如在hive sql中，任务在集群中运行，可以启动并行，&lt;code&gt;set hive.exec.parallel=true;&lt;/code&gt;，中文翻译有时会忽略两者差异&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B%E4%B8%8E%E4%BD%BF%E7%94%A8%E8%A7%84%E5%88%99%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python-函数参数类型与使用规则详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-3-14-%E6%97%A0GIL%E8%A7%A3%E9%87%8A%E5%99%A8%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%EF%BC%9A%E9%87%8A%E6%94%BE%E5%A4%9A%E6%A0%B8CPU%E7%9A%84%E5%B9%B6%E8%A1%8C%E6%BD%9C%E5%8A%9B.md&quot;&gt;Python-3-14-无GIL解释器性能测试：释放多核CPU的并行潜力&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C.md&quot;&gt;Python-标准库之pathlib（二），路径操作&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 函数参数类型与使用规则详解</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B%E4%B8%8E%E4%BD%BF%E7%94%A8%E8%A7%84%E5%88%99%E8%AF%A6%E8%A7%A3/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B%E4%B8%8E%E4%BD%BF%E7%94%A8%E8%A7%84%E5%88%99%E8%AF%A6%E8%A7%A3/</guid><description>Python 函数参数类型</description><pubDate>Wed, 03 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;Python以其灵活性著称，这种特性在函数参数设计中尤为明显。本文将依据语言规范，系统阐述Python函数所支持的全部参数类型及其应用&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;完整函数参数示例1&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;def func(pos_only=None, /, pos_kw=None, *, kw_only=None):
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;仅位置参数 (Positional-only)&lt;/strong&gt; ： &lt;code&gt;/&lt;/code&gt; 前面的参数
&lt;strong&gt;标识&lt;/strong&gt;：使用 &lt;code&gt;/&lt;/code&gt; 符号分隔
&lt;strong&gt;特点&lt;/strong&gt;：只能通过位置传递，不能使用参数名&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def func(a, b, /, c):
    # a, b 是仅位置参数
    pass

# 正确调用
func(1, 2, 3)      # a=1, b=2, c=3
func(1, 2, c=3)    # a=1, b=2, c=3

# 错误调用
func(a=1, b=2, c=3)  # TypeError: 不能使用关键字传递a, b
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;位置或关键字参数 (Positional-or-keyword)&lt;/strong&gt;：&lt;code&gt; /&lt;/code&gt; 和 &lt;code&gt;*&lt;/code&gt; 之间的参数
&lt;strong&gt;位置&lt;/strong&gt;：在 &lt;code&gt;/&lt;/code&gt; 之后，&lt;code&gt;*&lt;/code&gt; 之前（如果没有 &lt;code&gt;/&lt;/code&gt; 或 &lt;code&gt;*&lt;/code&gt;，则在所有参数中）
&lt;strong&gt;特点&lt;/strong&gt;：既可以通过位置传递，也可以通过关键字传递&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def func(a, b, c):
    # 传统写法，所有参数都是位置或关键字参数
    pass

# 两种方式都可以
func(1, 2, 3)       # 位置传递
func(a=1, b=2, c=3) # 关键字传递
func(1, b=2, c=3)   # 混合传递
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;仅关键字参数 (Keyword-only)&lt;/strong&gt;：&lt;code&gt;*&lt;/code&gt; 后面的参数
&lt;strong&gt;标识&lt;/strong&gt;：使用 &lt;code&gt;*&lt;/code&gt; 符号分隔，或者单个 &lt;code&gt;*&lt;/code&gt;
&lt;strong&gt;特点&lt;/strong&gt;：必须使用关键字传递&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def func(*, a, b):
    # a, b 是仅关键字参数
    pass

# 正确调用
func(a=1, b=2)

# 错误调用
func(1, 2)  # TypeError: 必须使用关键字参数
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;完整函数参数示例2&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;def comprehensive(
    pos_only_1,          # 仅位置参数
    pos_only_2=10,       # 带默认值的仅位置参数
    /,                   # 分隔符
    pos_kw_1,            # 位置或关键字参数
    pos_kw_2=20,         # 带默认值的位置或关键字参数
    *args,               # 可变位置参数
    kw_only_1,           # 仅关键字参数
    kw_only_2=30,        # 带默认值的仅关键字参数
    **kwargs             # 可变关键字参数
):
    pass

# 调用示例
comprehensive(
    1,              # pos_only_1
    2,              # pos_only_2
    3,              # pos_kw_1
    pos_kw_2=4,     # pos_kw_2
    5, 6,           # 进入args
    kw_only_1=7,    # kw_only_1
    kw_only_2=8,    # kw_only_2
    extra1=9,       # 进入kwargs
    extra2=10       # 进入kwargs
)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;可变位置参数&lt;/strong&gt;：&lt;strong&gt;&lt;code&gt;*args&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def func(a, *args, b=10):
    # args收集所有额外的位置参数
    pass

func(1, 2, 3, 4)  # a=1, args=(2,3,4), b=10
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;可变关键字参数&lt;/strong&gt;： &lt;strong&gt;&lt;code&gt;**kwargs&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;def func(a, **kwargs):
    # kwargs收集所有额外的关键字参数
    pass

func(1, x=2, y=3)  # a=1, kwargs={&apos;x&apos;:2, &apos;y&apos;:3}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%EF%BC%9A%E5%88%97%E8%A1%A8%E4%BD%9C%E4%B8%BA%E9%BB%98%E8%AE%A4%E5%80%BC%EF%BC%8C%E4%B8%80%E4%B8%AA%E9%9A%90%E8%97%8F%E7%9A%84%E9%99%B7%E9%98%B1%EF%BC%81.md&quot;&gt;Python函数参数：列表作为默认值，一个隐藏的陷阱！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-3-14-%E6%97%A0GIL%E8%A7%A3%E9%87%8A%E5%99%A8%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%EF%BC%9A%E9%87%8A%E6%94%BE%E5%A4%9A%E6%A0%B8CPU%E7%9A%84%E5%B9%B6%E8%A1%8C%E6%BD%9C%E5%8A%9B.md&quot;&gt;Python-3-14-无GIL解释器性能测试：释放多核CPU的并行潜力&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-2%E4%B8%AA%E5%A5%BD%E7%94%A8%E7%9A%84%E8%A3%85%E9%A5%B0%E5%99%A8%E5%87%BD%E6%95%B0.md&quot;&gt;Python-2个好用的装饰器函数&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 3.14 无GIL解释器性能测试：释放多核CPU的并行潜力</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-3-14-%E6%97%A0GIL%E8%A7%A3%E9%87%8A%E5%99%A8%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%EF%BC%9A%E9%87%8A%E6%94%BE%E5%A4%9A%E6%A0%B8CPU%E7%9A%84%E5%B9%B6%E8%A1%8C%E6%BD%9C%E5%8A%9B/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-3-14-%E6%97%A0GIL%E8%A7%A3%E9%87%8A%E5%99%A8%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%EF%BC%9A%E9%87%8A%E6%94%BE%E5%A4%9A%E6%A0%B8CPU%E7%9A%84%E5%B9%B6%E8%A1%8C%E6%BD%9C%E5%8A%9B/</guid><description>Python 无GIL解释器性能测试</description><pubDate>Tue, 28 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;Python 3.14 自2025年10月7日发布以来，已在技术社区中积累了丰富的实践与评测资料。目前国内的相关文章大多译自国外大神的博客文章，内容都很“高大上”，但在普遍适用性方面尚缺乏贴近实际的基础案例。为此，本文旨在提供一个通用的实践示例，作为后续深入研究和学习的baseline&lt;/p&gt;
&lt;h1&gt;名词解释&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;自由线程&lt;/strong&gt;、&lt;strong&gt;无GIL&lt;/strong&gt;与英文术语 &lt;strong&gt;Free-threaded&lt;/strong&gt; 同义，均指代同一项核心语言特性，即代码在执行时不再受全局解释器锁（GIL）的约束&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#Win10 系统  安装uv 
pip install uv 

uv -V  
#uv 0.9.0 (39b688653 2025-10-07)

python -VV
#Python 3.14.0 free-threading build (main, Oct  7 2025, 15:34:02) [MSC v.1944 64 bit (AMD64)]
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;测试结果图&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-7709a355023e3e37.png&quot; alt=&quot;CPU负荷&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-3a86e1dd41062dd0.png&quot; alt=&quot;运行时长&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;安装python3.14无GIL解释器&lt;/h1&gt;
&lt;p&gt;目前，Python官方的标准构建版本仍默认包含全局解释器锁（GIL）。若需使用无GIL的解释器，开发者需从源代码自行构建，或选用由社区提供的预编译版本。值得注意的是，工具 &lt;code&gt;uv&lt;/code&gt; 现已提供预编译的无GIL解释器，支持用户直接安装使用。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir 314t &amp;amp;&amp;amp; cd 314t  #创建目录

uv init  #初始化项目
uv python list #查看所有可用的python版本
uv python install cpython-3.14.0+freethreaded-windows-x86_64-none  #安装无GIL版本
uv python pin 3.14t #切换项目解释器
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;测试代码&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#test.py
import time
import threading
import queue

N = 3_0000_0000  #模拟任务量


def cpu_bound_task(n, thread_id, q):
   count = 0
   for i in range(n):
       count += i * i
   q.put(count)


def run_with_threads(num_threads):
   threads = []
   start = time.time()
   q = queue.Queue()
   for i in range(num_threads):
       t = threading.Thread(
           target=cpu_bound_task,
           args=(N // num_threads, i, q)  #每个线程计算 1/n
       )

       threads.append(t)
       t.start()
       
   for t in threads:
       t.join()
   end = time.time()
   print(f&quot;Total time taken with {num_threads} threads: {end - start:.2f} seconds&quot;)
   
   
if __name__ == &quot;__main__&quot;:
   for num in [1, 2, 4, 8, 16, 32]:
       run_with_threads(num)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;运行测试代码：&lt;/strong&gt;
小编电脑是物理4核，启动4个线程时，CPU利用率达到100%&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uv run test.py
#Total time taken with 1 threads: 27.00 seconds
#Total time taken with 2 threads: 15.08 seconds
#Total time taken with 4 threads: 9.39 seconds
#Total time taken with 8 threads: 8.72 seconds
#Total time taken with 16 threads: 9.74 seconds
#Total time taken with 32 threads: 9.55 seconds
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C.md&quot;&gt;Python-标准库之pathlib（二），路径操作&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E6%96%B0%E6%80%9D%E8%B7%AF%EF%BC%9A%E7%94%A8-uv-Workspace-%E5%85%B1%E4%BA%AB%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%EF%BC%8C%E7%9C%81%E6%97%B6%E7%9C%81%E7%A9%BA%E9%97%B4%EF%BC%81.md&quot;&gt;Python-项目管理新思路：用-uv-Workspace-共享虚拟环境，省时省空间！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%96%B0%E6%99%8B%E5%8C%85%E9%A1%B9%E7%9B%AE%E5%B7%A5%E5%85%B7uv%E7%9A%84%E7%AE%80%E5%8D%95%E5%B0%9D%E8%AF%95.md&quot;&gt;Python-新晋包项目工具uv的简单尝试&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 标准库之pathlib（二），路径操作</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C/</guid><description>Python pathlib基础库</description><pubDate>Wed, 15 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;小编之前写过一篇介绍 &lt;code&gt;pathlib&lt;/code&gt; 标准库的文章，最近在做项目时，又发现其有一个更好用的功能，分享给大家，供大家参考学习&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;创建目录方法：Path.mkdir()&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;pathlib.Path.mkdir()&lt;/code&gt; 方法是 Python 中创建目录的核心方法，提供了灵活且安全的目录创建功能&lt;/p&gt;
&lt;h3&gt;方法签名：&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Path.mkdir(mode=0o777, parents=False, exist_ok=False)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;参数详解：&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;mode&lt;/code&gt; (可选)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用:&lt;/strong&gt; 设置目录权限（Unix/Linux/Mac 系统有效）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;默认值:&lt;/strong&gt; 0o777 (八进制，表示最大权限)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注意:&lt;/strong&gt; 在 Windows 上此参数被忽略&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;常用权限值:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from pathlib import Path

# 创建用户可读/写/执行，组和其他用户只读/执行的目录
Path(&quot;my_dir&quot;).mkdir(mode=0o755)  # drwxr-xr-x

# 创建只有用户可读/写/执行的目录  
Path(&quot;private_dir&quot;).mkdir(mode=0o700)  # drwx------
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;parents&lt;/code&gt; (可选)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用:&lt;/strong&gt; 是否自动创建父目录&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;默认值:&lt;/strong&gt; &lt;code&gt;False&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;当 &lt;code&gt;False&lt;/code&gt; 时:&lt;/strong&gt; 父目录必须存在，否则抛出 &lt;code&gt;FileNotFoundError&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;当 &lt;code&gt;True&lt;/code&gt; 时:&lt;/strong&gt; 自动创建所有不存在的父目录&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. &lt;code&gt;exist_ok&lt;/code&gt; (可选)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作用:&lt;/strong&gt; 目录已存在时的处理方式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;默认值:&lt;/strong&gt; &lt;code&gt;False&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;当 &lt;code&gt;False&lt;/code&gt; 时:&lt;/strong&gt; 目录已存在会抛出 &lt;code&gt;FileExistsError&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;当 &lt;code&gt;True&lt;/code&gt; 时:&lt;/strong&gt; 目录已存在不会报错&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;基础用法示例&lt;/h1&gt;
&lt;h3&gt;示例 1: 创建单级目录&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;from pathlib import Path

# 在当前目录下创建新文件夹
Path(&quot;new_folder&quot;).mkdir()

# 创建指定路径的目录
Path(&quot;/tmp/example&quot;).mkdir()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;示例 2: 创建多级目录（使用 &lt;code&gt;parents=True&lt;/code&gt;）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;from pathlib import Path

# 传统方式 - 需要逐级检查创建
# 这里演示只判断父目录是否存在
path = Path(&quot;a/b/c/d/e&quot;)
if not path.parent.exists():
    path.parent.mkdir()
path.mkdir()

# 简化方式 - 一次性创建所有层级
Path(&quot;a/b/c/d/e&quot;).mkdir(parents=True)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;示例 3: 安全创建目录（使用 &lt;code&gt;exist_ok=True&lt;/code&gt;）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;from pathlib import Path

# 安全创建 - 目录存在也不报错
Path(&quot;my_project&quot;).mkdir(exist_ok=True)

# 等同于检查是否存在再创建
path = Path(&quot;my_project&quot;)
if not path.exists():
    path.mkdir()
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C.md&quot;&gt;Python-标准库之pathlib，路径操作&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-collections%E8%AF%A6%E8%A7%A3%EF%BC%9A%E8%A7%A3%E9%94%81%E9%AB%98%E6%95%88%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.md&quot;&gt;Python-collections详解：解锁高效数据结构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%88%A9%E7%94%A8partial%E5%81%8F%E5%87%BD%E6%95%B0%EF%BC%8C%E7%94%9F%E6%88%90%E4%B8%8D%E5%90%8C%E7%9A%84%E8%81%9A%E5%90%88%E5%87%BD%E6%95%B0.md&quot;&gt;Python利用partial偏函数，生成不同的聚合函数&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 单实例模式详解</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%8D%95%E5%AE%9E%E4%BE%8B%E6%A8%A1%E5%BC%8F%E8%AF%A6%E8%A7%A3/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%8D%95%E5%AE%9E%E4%BE%8B%E6%A8%A1%E5%BC%8F%E8%AF%A6%E8%A7%A3/</guid><description>Python 单实例模式</description><pubDate>Fri, 22 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;你是否听说过 Python 中的 &lt;strong&gt;单实例模式（Singleton Pattern）&lt;/strong&gt;？ ，小编之前在阅读别人代码的时候曾经遇到过，一直不知道那段代码什么含义，后来在搜索资料时，才知道那段代码的含义是创建单实例，也正是从那之后，才知道这个名词 &lt;strong&gt;“单实例”&lt;/strong&gt;，是 Python 中的一种设计模式，用大白话说就是类的实例对象在内存中只有一个&lt;/p&gt;
&lt;h1&gt;单实例模式代码&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;class Singleton:
    _instance = None
    
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;借助大模型进行详细解释&lt;/h1&gt;
&lt;p&gt;首次创建实例对象时，类的属性 &lt;code&gt;_instance = None&lt;/code&gt;，然后程序会进入 if 条件进行执行，重点语句：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
# cls._instance = super().__new__(cls, *args, **kwargs)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;super(Singleton, cls)&lt;/code&gt; 的作用&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;super函数：用于获取父类（基类）的方法，继承父类，进行父类初始化的用法&lt;/li&gt;
&lt;li&gt;参数含义：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Singleton&lt;/code&gt;：当前类&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cls&lt;/code&gt;：当前类的引用（在类方法中，cls代表类本身）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种写法明确指定了从&lt;code&gt;Singleton&lt;/code&gt;类开始，在MRO(Method Resolution Order)中查找父类。在Python 3中可以简化为&lt;code&gt;super()&lt;/code&gt;，但这种写法更清晰地展示了继承关系&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;.__new__(cls, *args, **kwargs)&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;调用父类的&lt;code&gt;__new__&lt;/code&gt;方法：这是实际创建对象实例的关键步骤&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;super(Singleton, cls).__new__(cls) → 实际调用object.__new__(Singleton)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 CPython（Python 的官方实现）中，&lt;code&gt;object.__new__&lt;/code&gt; 是用 C 语言实现的底层函数。它的核心工作是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;内存分配：为新对象分配适当的内存空间&lt;/li&gt;
&lt;li&gt;对象初始化：设置对象的基本结构&lt;/li&gt;
&lt;li&gt;返回原始对象：返回一个&quot;空&quot;的、未初始化的对象实例&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;object.__new__&lt;/code&gt; 是底层实现，它不会触发 Python 层面的 &lt;code&gt;__new__&lt;/code&gt; 方法调用&lt;/strong&gt;
当 &lt;code&gt;object.__new__&lt;/code&gt; 执行时：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;它直接操作内存分配，不经过 Python 的方法查找机制&lt;/li&gt;
&lt;li&gt;它是解释器内置的 C 函数，不是 Python 函数&lt;/li&gt;
&lt;li&gt;它的工作就是创建原始对象，不会检查或调用任何 &lt;code&gt;__new__&lt;/code&gt; 方法&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;object.__new__(Singleton) &lt;/code&gt;的工作原理：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;内存分配：为 Singleton 实例分配适当大小的内存&lt;/li&gt;
&lt;li&gt;对象初始化：设置基本对象头（类型指针、引用计数等）&lt;/li&gt;
&lt;li&gt;返回原始对象：返回一个&quot;空&quot;的、未初始化的对象实例&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;3. 返回赋值 &lt;code&gt;cls._instance=&lt;/code&gt;&lt;/strong&gt;
经过第2步之后，会将原始对象赋值给 &lt;code&gt;cls._instance&lt;/code&gt;，其实是类在内存中的地址/指针，这样类的属性不再为&lt;code&gt;None&lt;/code&gt;，后续如果再次创建实例时，直接返回第一次创建好的实例对象&lt;/p&gt;
&lt;h1&gt;单例模式的核心优点&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;节省内存资源：在内存中只有一个对象，避免了重复创建实例带来的内存浪费&lt;/li&gt;
&lt;li&gt;减少系统开销：单例可长驻内存，避免频繁的创建和销毁对象，减少系统开销&lt;/li&gt;
&lt;li&gt;全局访问点：提供一个全局访问点，允许在应用程序中轻松访问该唯一实例&lt;/li&gt;
&lt;li&gt;数据同步控制：全局只有一个接入点，可以更好地进行数据同步控制，避免多重占用&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;单例模式的实际应用场景&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;日志记录器：应用程序通常只需要一个日志记录器实例，避免多个日志文件冲突&lt;/li&gt;
&lt;li&gt;数据库连接池：数据库连接是稀缺资源，使用单例模式可以统一管理连接，避免资源浪费&lt;/li&gt;
&lt;li&gt;配置管理：应用程序的全局配置通常只需要一个实例，保证配置的一致性，比如大模型在内存/GPU中只初始化一次，来处理所有的用户请求&lt;/li&gt;
&lt;li&gt;缓存系统：全局缓存需要统一管理，避免多个缓存实例导致数据不一致&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-collections%E8%AF%A6%E8%A7%A3%EF%BC%9A%E8%A7%A3%E9%94%81%E9%AB%98%E6%95%88%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.md&quot;&gt;Python-collections详解：解锁高效数据结构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B%E4%B8%8E%E4%BD%BF%E7%94%A8%E8%A7%84%E5%88%99%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python-函数参数类型与使用规则详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-2%E4%B8%AA%E5%A5%BD%E7%94%A8%E7%9A%84%E8%A3%85%E9%A5%B0%E5%99%A8%E5%87%BD%E6%95%B0.md&quot;&gt;Python-2个好用的装饰器函数&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python collections详解：解锁高效数据结构</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-collections%E8%AF%A6%E8%A7%A3%EF%BC%9A%E8%A7%A3%E9%94%81%E9%AB%98%E6%95%88%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-collections%E8%AF%A6%E8%A7%A3%EF%BC%9A%E8%A7%A3%E9%94%81%E9%AB%98%E6%95%88%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</guid><description>Python collections基础库</description><pubDate>Tue, 12 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;虽然  Python 中已提供了 &lt;strong&gt;列表&lt;/strong&gt;、&lt;strong&gt;字典&lt;/strong&gt; 等非常灵活的数据结构，但是 &lt;strong&gt;&lt;code&gt;collections&lt;/code&gt;&lt;/strong&gt; 模块提供了高性能的容器数据类型，能大幅优化代码效率和可读性，本文将深入解析该模块中的六大核心工具，助你写出更优雅的Python代码，避免你重复造轮子&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;namedtuple：命名元组&lt;/h1&gt;
&lt;p&gt;传统元组通过索引访问元素，代码可读性差：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;point = (2, 5)
print(f&quot;X: {point[0]}, Y: {point[1]}&quot;)  # 可读性低
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;namedtuple&lt;/strong&gt; 赋予元组字段名&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from collections import namedtuple

# 创建具名元组类型
Point = namedtuple(&apos;Point&apos;, [&apos;x&apos;, &apos;y&apos;])
p = Point(2, 5)

print(p.x, p.y)  # 直观访问
print(p._asdict()) # 转为字典：{&apos;x&apos;: 2, &apos;y&apos;: 5}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ 适用场景：数据库查询结果、坐标点等轻量级数据结构&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;deque：高效双端队列&lt;/h1&gt;
&lt;p&gt;列表(list)在头部插入/删除效率为 &lt;code&gt;O(n)&lt;/code&gt;，deque 在两端操作均为 &lt;code&gt;O(1)&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from collections import deque

d = deque([1, 2, 3])
d.appendleft(0)  # 左侧添加 → deque([0, 1, 2, 3])
d.extend([4, 5]) # 右侧扩展 → [0,1,2,3,4,5]
d.rotate(2)      # 向右旋转 → [4,5,0,1,2,3]
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;🔥 性能对比：千万元素头部插入&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;list.insert(0, x)&lt;/strong&gt;：耗时2.1秒&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;deque.appendleft(x)&lt;/strong&gt;：耗时0.02秒&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Counter：元素统计利器&lt;/h1&gt;
&lt;p&gt;快速统计可迭代对象中元素频率&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from collections import Counter

text = &quot;python collections is powerful&quot;
word_count = Counter(text.split())

print(word_count.most_common(2))
# 输出：[(&apos;python&apos;, 1), (&apos;collections&apos;, 1)]

# 数学运算
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)
print(c1 + c2)  # Counter({&apos;a&apos;: 4, &apos;b&apos;: 3})
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 进阶技巧：elements()方法生成迭代器，subtract()实现减法操作&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;defaultdict：智能字典&lt;/h1&gt;
&lt;p&gt;避免KeyError异常，自动初始化默认值&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from collections import defaultdict

# 值为列表的字典
dd = defaultdict(list)
dd[&apos;fruits&apos;].append(&apos;apple&apos;)  # 无需初始化
print(dd[&apos;animal&apos;])  # 访问不存在的key，返回空列表 []

# 值为计数的字典
count_dict = defaultdict(int)
for char in &quot;abracadabra&quot;:
    count_dict[char] += 1
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;支持任意可调用对象：&lt;strong&gt;defaultdict(lambda: &apos;N/A&apos;)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;ChainMap：字典聚合器&lt;/h1&gt;
&lt;p&gt;合并多个字典而不创建新对象&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from collections import ChainMap

dict1 = {&apos;a&apos;: 1, &apos;b&apos;: 2}
dict2 = {&apos;b&apos;: 3, &apos;c&apos;: 4}

chain = ChainMap(dict1, dict2)
print(chain[&apos;b&apos;])  # 输出2（dict1优先）
print(chain[&apos;c&apos;])  # 输出4

# 动态添加字典
chain = chain.new_child({&apos;d&apos;: 5}) 
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;🌟 特点：查找顺序可定制，原始字典修改实时同步&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;OrderedDict：有序字典&lt;/h1&gt;
&lt;p&gt;虽然Python3.7+的dict已有序，但OrderedDict提供额外功能&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from collections import OrderedDict

od = OrderedDict()
od[&apos;z&apos;] = 1
od[&apos;a&apos;] = 2
print(list(od.keys()))  # 保持插入顺序：[&apos;z&apos;, &apos;a&apos;]

# 特殊方法
od.move_to_end(&apos;z&apos;)  # 移动键到末尾 ，OrderedDict([(&apos;a&apos;, 2), (&apos;z&apos;, 1)])
od.popitem(last=False)  # FIFO删除，删除 (&apos;a&apos;, 2)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%AD%97%E5%85%B8%E5%B7%B2%E7%BB%8F%E6%98%AF%E6%9C%89%E5%BA%8F%E7%9A%84%EF%BC%8C%E4%BD%A0%E7%9F%A5%E9%81%93%E5%90%97%EF%BC%9F.md&quot;&gt;Python-字典已经是有序的，你知道吗？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E4%B8%AD%E7%9A%84Lambda%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0.md&quot;&gt;Python中的Lambda匿名函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%88%A9%E7%94%A8partial%E5%81%8F%E5%87%BD%E6%95%B0%EF%BC%8C%E7%94%9F%E6%88%90%E4%B8%8D%E5%90%8C%E7%9A%84%E8%81%9A%E5%90%88%E5%87%BD%E6%95%B0.md&quot;&gt;Python利用partial偏函数，生成不同的聚合函数&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 函数参数：列表作为默认值，一个隐藏的陷阱！</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%EF%BC%9A%E5%88%97%E8%A1%A8%E4%BD%9C%E4%B8%BA%E9%BB%98%E8%AE%A4%E5%80%BC%EF%BC%8C%E4%B8%80%E4%B8%AA%E9%9A%90%E8%97%8F%E7%9A%84%E9%99%B7%E9%98%B1%EF%BC%81/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%EF%BC%9A%E5%88%97%E8%A1%A8%E4%BD%9C%E4%B8%BA%E9%BB%98%E8%AE%A4%E5%80%BC%EF%BC%8C%E4%B8%80%E4%B8%AA%E9%9A%90%E8%97%8F%E7%9A%84%E9%99%B7%E9%98%B1%EF%BC%81/</guid><description>Python 函数参数</description><pubDate>Tue, 05 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;在Python编程中，函数参数的设计直接影响代码的健壮性和可预测性。**一个需要警惕的实践是：避免将可变对象（尤其是列表）作为函数参数的默认值。**这样做可能导致极其隐蔽且令人困惑的bug&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;现象：一个诡异的“记忆”功能&lt;/h1&gt;
&lt;p&gt;想象你设计了一个函数，用来记录新添加的学生姓名到某个班级列表。如果列表为空，则创建一个新列表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def add_student(name, student_list=[]):
    student_list.append(name)
    return student_list

# 第一次调用：添加Alice
class1 = add_student(&quot;Alice&quot;)
print(class1)  # 输出: [&apos;Alice&apos;] 

# 第二次调用：添加Bob
class2 = add_student(&quot;Bob&quot;)
print(class2)  # 输出: [&apos;Alice&apos;, &apos;Bob&apos;] 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;问题来了：&lt;/strong&gt; 第二次调用&lt;strong&gt;add_student(&quot;Bob&quot;)&lt;strong&gt;时，并没有传递&lt;/strong&gt;student_list&lt;/strong&gt;参数，期望的是生成一个只包含**&quot;Bob&quot;&lt;strong&gt;的新列表。但结果却包含了第一次添加的&lt;/strong&gt;&quot;Alice&quot;**！这个函数似乎“记住了”之前的调用&lt;/p&gt;
&lt;h1&gt;原因揭秘：列表是引用类型&lt;/h1&gt;
&lt;p&gt;要理解这个问题的本质，必须明白Python中变量的工作方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;列表是引用类型&lt;/strong&gt;
在Python中，变量存储的是对象的引用（内存地址），而不是对象本身。当你将一个列表赋值给变量时，实际上是在创建一个指向列表对象的引用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;默认参数的创建时机&lt;/strong&gt;
当Python解释器遇到函数定义时，它会立即创建默认参数对象。对于列表这样的可变对象，这意味着只有一个列表对象被创建，并且这个对象会持续存在于整个程序的生命周期中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;函数调用时的陷阱&lt;/strong&gt;
当你多次调用函数而不提供参数时，Python不会创建新的列表，而是重复使用同一个默认列表对象。因为列表是可变的，每次对它的修改都会永久改变这个共享对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;引用传递的后果&lt;/strong&gt;
由于函数操作的是指向同一个列表对象的引用，所有使用默认参数的调用实际上都在操作同一个物理列表。这就是为什么数据会&quot;神奇地&quot;在函数调用之间保留下来&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;解决方案：使用不可变默认参数&lt;/h1&gt;
&lt;p&gt;正确的做法是使用 &lt;strong&gt;None&lt;/strong&gt; 作为哨兵值&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def add_item(item, items=None):
    if items is None:
        items = []  # 每次调用都创建新列表
    items.append(item)
    return items
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-2%E4%B8%AA%E5%A5%BD%E7%94%A8%E7%9A%84%E8%A3%85%E9%A5%B0%E5%99%A8%E5%87%BD%E6%95%B0.md&quot;&gt;Python-2个好用的装饰器函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E8%BF%88%E5%90%91%E5%BC%BA%E7%B1%BB%E5%9E%8B%E5%8C%96%E7%9A%84%E4%BC%98%E9%9B%85%E8%BD%AC%E5%8F%98.md&quot;&gt;Python-迈向强类型化的优雅转变&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%AD%97%E5%85%B8%E5%B7%B2%E7%BB%8F%E6%98%AF%E6%9C%89%E5%BA%8F%E7%9A%84%EF%BC%8C%E4%BD%A0%E7%9F%A5%E9%81%93%E5%90%97%EF%BC%9F.md&quot;&gt;Python-字典已经是有序的，你知道吗？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 项目管理新思路：用 uv Workspace 共享虚拟环境，省时省空间！</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E6%96%B0%E6%80%9D%E8%B7%AF%EF%BC%9A%E7%94%A8-uv-Workspace-%E5%85%B1%E4%BA%AB%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%EF%BC%8C%E7%9C%81%E6%97%B6%E7%9C%81%E7%A9%BA%E9%97%B4%EF%BC%81/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E6%96%B0%E6%80%9D%E8%B7%AF%EF%BC%9A%E7%94%A8-uv-Workspace-%E5%85%B1%E4%BA%AB%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%EF%BC%8C%E7%9C%81%E6%97%B6%E7%9C%81%E7%A9%BA%E9%97%B4%EF%BC%81/</guid><description>Python uv项目管理</description><pubDate>Tue, 29 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;上手 &lt;strong&gt;&lt;code&gt;uv&lt;/code&gt;&lt;/strong&gt; 一段时间后，真心觉得这款工具让 Python 项目管理变得省心不少！它不仅操作便捷，安装第三方包的速度更是快得飞起。&lt;/p&gt;
&lt;p&gt;不过，在使用过程中也发现了一个小痛点：&lt;strong&gt;&lt;code&gt;uv&lt;/code&gt;&lt;/strong&gt; 默认会为每个项目创建独立的虚拟环境。这意味着，如果你同时开发多个项目，即使它们依赖相同的第三方包（比如常用的 &lt;strong&gt;&lt;code&gt;requests&lt;/code&gt;&lt;/strong&gt;、&lt;strong&gt;&lt;code&gt;pandas&lt;/code&gt;&lt;/strong&gt;），这些包也需要在每个项目的虚拟环境中&lt;strong&gt;重复安装&lt;/strong&gt;。久而久之，宝贵的磁盘空间就这样被悄悄占用了不少。&lt;/p&gt;
&lt;p&gt;难道只能忍受这种“甜蜜的负担”吗？当然不是！仔细翻阅 &lt;strong&gt;&lt;code&gt;uv&lt;/code&gt;&lt;/strong&gt; 的文档后发现，它其实贴心地提供了&lt;strong&gt;工作空间（Workspace）&lt;strong&gt;功能！通过工作空间，你可以让&lt;/strong&gt;多个项目共享同一个虚拟环境&lt;/strong&gt;。这样一来，公共依赖包只需安装一次，所有关联项目都能顺畅使用，&lt;strong&gt;大幅减少了重复安装带来的空间浪费&lt;/strong&gt;，管理效率再上一个台阶！&lt;/p&gt;
&lt;p&gt;在尝试获取 &lt;strong&gt;&lt;code&gt;uv&lt;/code&gt; 工作空间（Workspace）&lt;/strong&gt; 功能的相关信息时，小编注意到 DeepSeek 模型提供的回答有时存在&lt;strong&gt;不准确或偏离主题&lt;/strong&gt;的情况。&lt;/p&gt;
&lt;p&gt;这表明，&lt;strong&gt;&lt;code&gt;uv&lt;/code&gt;&lt;/strong&gt; 这一相对较新的功能细节，&lt;strong&gt;可能尚未被充分纳入 DeepSeek 当前模型版本的训练数据&lt;/strong&gt;。这一现象也提醒我们，即使是强大的 AI 模型，&lt;strong&gt;其知识覆盖和能力也存在一定的边界与时效性局限&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;uv self version
# uv 0.8.2 (21fadbcc1 2025-07-22)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;工作空间示例&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;创建根项目，并添加一个三方包 &lt;code&gt;pandas&lt;/code&gt;
在根项目的文件夹里面生成一个虚拟环境 &lt;code&gt;.venv&lt;/code&gt; ，&lt;code&gt;pandas&lt;/code&gt;被安装在该文件夹内&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;uv init workspace_project  -p 3.11
cd workspace_project
uv add pandas
uv tree
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;workspace-project v0.1.0
└── pandas v2.3.1
    ├── numpy v2.3.1
    ├── python-dateutil v2.9.0.post0
    │   └── six v1.17.0
    ├── pytz v2025.2
    └── tzdata v2025.2
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;创建子项目1，并添加一个三方包 &lt;code&gt;fastapi&lt;/code&gt;
在子项目中添加的包，会被安装到根项目的虚拟环境&lt;code&gt;.venv&lt;/code&gt;中&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;pwd  # D:\桌面\Python\uv\workspace_project
uv init sub_project1  # 创建子项目1
cd sub_project1  
uv add fastapi
uv tree
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;workspace-project v0.1.0
└── pandas v2.3.1
    ├── numpy v2.3.1
    ├── python-dateutil v2.9.0.post0
    │   └── six v1.17.0
    ├── pytz v2025.2
    └── tzdata v2025.2
sub-project1 v0.1.0
└── fastapi v0.116.1
    ├── pydantic v2.11.7
    │   ├── annotated-types v0.7.0
    │   ├── pydantic-core v2.33.2
    │   │   └── typing-extensions v4.14.1
    │   ├── typing-extensions v4.14.1
    │   └── typing-inspection v0.4.1
    │       └── typing-extensions v4.14.1
    ├── starlette v0.47.2
    │   ├── anyio v4.9.0
    │   │   ├── idna v3.10
    │   │   ├── sniffio v1.3.1
    │   │   └── typing-extensions v4.14.1
    │   └── typing-extensions v4.14.1
    └── typing-extensions v4.14.1
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;创建子项目2，并添加一个三方包 &lt;code&gt;requests&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;pwd  # D:\桌面\Python\uv\workspace_project
uv init sub_project2  # 创建子项目1
cd sub_project2  
uv add requests
uv tree
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;workspace-project v0.1.0
└── pandas v2.3.1
    ├── numpy v2.3.1
    ├── python-dateutil v2.9.0.post0
    │   └── six v1.17.0
    ├── pytz v2025.2
    └── tzdata v2025.2
sub-project2 v0.1.0
└── requests v2.32.4
    ├── certifi v2025.7.14
    ├── charset-normalizer v3.4.2
    ├── idna v3.10
    └── urllib3 v2.5.0
sub-project1 v0.1.0
└── fastapi v0.116.1
    ├── pydantic v2.11.7
    │   ├── annotated-types v0.7.0
    │   ├── pydantic-core v2.33.2
    │   │   └── typing-extensions v4.14.1
    │   ├── typing-extensions v4.14.1
    │   └── typing-inspection v0.4.1
    │       └── typing-extensions v4.14.1
    ├── starlette v0.47.2
    │   ├── anyio v4.9.0
    │   │   ├── idna v3.10
    │   │   ├── sniffio v1.3.1
    │   │   └── typing-extensions v4.14.1
    │   └── typing-extensions v4.14.1
    └── typing-extensions v4.14.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所有的三方包都安装在根项目的虚拟环境内，&lt;code&gt;path\workspace_project\.venv\Lib\site-packages&lt;/code&gt;，这样公共依赖包只需安装一次&lt;/p&gt;
&lt;p&gt;以上的操作，其实是 &lt;code&gt;uv&lt;/code&gt; 自动在根项目的配置文件 &lt;code&gt;pyproject.toml&lt;/code&gt; 中，增加了如下配置，这样 &lt;code&gt;uv&lt;/code&gt; 才识别所有项目同属于一个工作空间&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[tool.uv.workspace]
members = [
    &quot;sub_project1&quot;,
    &quot;sub_project2&quot;,
]
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;在子项目2中使用同工作空间其它项目安装的包&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;import pandas as pd 
import fastapi

def main():
    print(&quot;Hello from sub-project2!&quot;)


if __name__ == &quot;__main__&quot;:
    main()
    print(&apos;pandas版本：&apos;,pd.__version__)
    print(&apos;fastapi版本：&apos;,fastapi.__version__)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pwd  # D:\桌面\Python\uv\workspace_project\sub_project2
uv run .\main.py
# Hello from sub-project2!
# pandas版本： 2.3.1
# fastapi版本： 0.116.1
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%96%B0%E6%99%8B%E5%8C%85%E9%A1%B9%E7%9B%AE%E5%B7%A5%E5%85%B7uv%E7%9A%84%E7%AE%80%E5%8D%95%E5%B0%9D%E8%AF%95.md&quot;&gt;Python-新晋包项目工具uv的简单尝试&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%9C%A8%E6%8C%87%E5%AE%9A%E6%96%87%E4%BB%B6%E5%A4%B9%E5%AE%89%E8%A3%85%E4%B8%89%E6%96%B9%E5%BA%93%EF%BC%8C%E5%B9%B6%E8%BF%9B%E8%A1%8C%E5%8A%A0%E8%BD%BD%E4%BD%BF%E7%94%A8.md&quot;&gt;Python-在指定文件夹安装三方库，并进行加载使用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Rust-%E6%98%AF%E5%90%A6%E4%BC%9A%E9%87%8D%E5%86%99-Python-%E8%A7%A3%E9%87%8A%E5%99%A8%E4%B8%8E%E6%9C%89%E5%85%B3%E7%9A%84%E5%BA%93%EF%BC%8C%E6%9B%BF%E4%BB%A3-C-%E8%AF%AD%E8%A8%80%E5%9C%B0%E4%BD%8D%EF%BC%9F.md&quot;&gt;Rust-是否会重写-Python-解释器与有关的库，替代-C-语言地位？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 2个好用的装饰器函数</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-2%E4%B8%AA%E5%A5%BD%E7%94%A8%E7%9A%84%E8%A3%85%E9%A5%B0%E5%99%A8%E5%87%BD%E6%95%B0/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-2%E4%B8%AA%E5%A5%BD%E7%94%A8%E7%9A%84%E8%A3%85%E9%A5%B0%E5%99%A8%E5%87%BD%E6%95%B0/</guid><description>Python 装饰器函数</description><pubDate>Tue, 22 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;装饰器：Python开发者的效率利器！ 🛠️&lt;/p&gt;
&lt;p&gt;在Python的世界里，装饰器绝对是一把强大的“瑞士军刀”。它能帮我们优雅地封装通用逻辑，大幅减少重复代码，真正实现事半功倍的开发效率。&lt;/p&gt;
&lt;p&gt;如果你是第一次接触装饰器这个概念，强烈建议先找些基础资料了解一下它的核心思想和工作原理（别担心，小编当初也是一头雾水，看别人的代码完全摸不着头脑）。打好基础再往下看，理解起来会顺畅得多，相信小编！&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;计算耗时&lt;/h1&gt;
&lt;p&gt;想知道函数执行耗时？一个装饰器轻松搞定！⏱️&lt;/p&gt;
&lt;p&gt;还在手动写 &lt;code&gt;time.time()&lt;/code&gt; 包裹你的函数来计算耗时吗？太麻烦啦！只需几行代码定义一个计时装饰器，轻轻松松给任何函数“戴上”，就能自动获取精准的执行时间&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def time_it(func):
    @wraps(func)  # 保留原始函数的元数据
    def wrapper(*args, **kwargs):
        print(&quot;开始执行----&amp;gt;&quot;)
        start_time=datetime.datetime.now()
        result = func(*args, **kwargs)
        end_time=datetime.datetime.now()
        print(f&quot;结束执行，消耗时长为：{end_time - start_time}&quot;)
        return result
    return wrapper
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;重试机制&lt;/h1&gt;
&lt;p&gt;在程序中调用外部API、访问数据库或进行网络请求时，网络环境的不稳定性往往是导致程序“意外扑街”的头号元凶！面对这种不可控因素，与其祈祷网络永远畅通，不如主动出击——引入重试机制，来增加程序的健壮性&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def retry(func=None,*,times=3):
    if func is None:
        return partial(retry,times=times)
    
    @wraps(func)
    def wrapper(*args,**kwargs):
        for attempt in range(1,times+1):
            try:
                return func(*args,**kwargs)
            except Exception as exc:
                print(f&quot;函数 {func.__name__} 进行第 {attempt} 次尝试，遇到错误：{exc}&quot;)
                sleep(SLEEP_TIME * attempt)
        print(f&quot;所有尝试均失败！！！&quot;)
        return None
    
    return wrapper
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;完整代码&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;from time import sleep
import datetime
from functools import wraps,partial  # 导入 wraps 装饰器

SLEEP_TIME=1

def time_it(func):
    @wraps(func)  # 保留原始函数的元数据
    def wrapper(*args, **kwargs):
        print(&quot;开始执行----&amp;gt;&quot;)
        start_time=datetime.datetime.now()
        result = func(*args, **kwargs)
        end_time=datetime.datetime.now()
        print(f&quot;结束执行，消耗时长为：{end_time - start_time}&quot;)
        return result
    return wrapper


def retry(func=None,*,times=3):
    if func is None:
        return partial(retry,times=times)
    
    @wraps(func)
    def wrapper(*args,**kwargs):
        for attempt in range(1,times+1):
            try:
                return func(*args,**kwargs)
            except Exception as exc:
                print(f&quot;函数 {func.__name__} 进行第 {attempt} 次尝试，遇到错误：{exc}&quot;)
                sleep(SLEEP_TIME * attempt)
        print(f&quot;所有尝试均失败！！！&quot;)
        return None
    
    return wrapper
    

if __name__==&apos;__main__&apos;:
    
    @retry
    @time_it
    def cal(x):
        total=0
        for i in range(x):
            total += i
            
        return total 
    
    print(cal(100000000))
    print(cal(&apos;100000&apos;))
    
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行测试结果
&lt;img src=&quot;./images/6641583-f164297b19a935be.png&quot; alt=&quot;测试&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E4%B8%AD%E7%9A%84Lambda%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0.md&quot;&gt;Python中的Lambda匿名函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%88%A9%E7%94%A8partial%E5%81%8F%E5%87%BD%E6%95%B0%EF%BC%8C%E7%94%9F%E6%88%90%E4%B8%8D%E5%90%8C%E7%9A%84%E8%81%9A%E5%90%88%E5%87%BD%E6%95%B0.md&quot;&gt;Python利用partial偏函数，生成不同的聚合函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97-bisect%EF%BC%8C%E6%95%B0%E7%BB%84%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95.md&quot;&gt;Python-内建模块-bisect，数组二分查找算法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 迈向强类型化的优雅转变</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E8%BF%88%E5%90%91%E5%BC%BA%E7%B1%BB%E5%9E%8B%E5%8C%96%E7%9A%84%E4%BC%98%E9%9B%85%E8%BD%AC%E5%8F%98/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E8%BF%88%E5%90%91%E5%BC%BA%E7%B1%BB%E5%9E%8B%E5%8C%96%E7%9A%84%E4%BC%98%E9%9B%85%E8%BD%AC%E5%8F%98/</guid><description>Python 迈向强类型化</description><pubDate>Mon, 16 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;Python 不再是你记忆中的“弱类型”语言了！ 随着类型注释的普及和高版本Python的演进，它正悄然蜕变为一门兼具灵活性与严谨性的现代语言&lt;/p&gt;
&lt;h1&gt;为什么使用类型注释？&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;1. 提升可读性&lt;/strong&gt;
类型注释是代码的“自文档化”工具，明确参数和返回值的类型，让代码意图一目了然&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def process_data(data: list[int], threshold: float) -&amp;gt; list[float]:
    return [x * threshold for x in data if x &amp;gt; 0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. 错误早捕获&lt;/strong&gt;
结合静态检查工具（如 mypy），在运行前发现类型错误，告别隐藏的 TypeError！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install mypy  
mypy your_script.py  # 静态检查
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. IDE智能支持&lt;/strong&gt;
VS Code/PyCharm 等工具通过类型注释提供精准的代码补全和错误提示，开发效率翻倍&lt;/p&gt;
&lt;h1&gt;Python 已悄然“强类型化”&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;动态类型 ≠ 弱类型&lt;/strong&gt;
Python 仍是动态类型语言，但类型注释的引入（PEP 484）和社区实践推动它向强类型风格演进&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;高版本特性加持（Python 3.10+）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;联合类型简化：&lt;code&gt;int | str&lt;/code&gt; 替代 &lt;code&gt;Union[int, str]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;类型守卫：用 &lt;code&gt;isinstance()&lt;/code&gt; 细化类型范围（PEP 647）&lt;/li&gt;
&lt;li&gt;模式匹配：&lt;code&gt;match/case&lt;/code&gt; 中类型推断更智能&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;如何开始？&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;1. 升级Python版本&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 推荐使用 Python 3.10 或更高版本
python --version  # 检查版本
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. 渐进式添加类型&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从关键函数参数和返回值开始&lt;/li&gt;
&lt;li&gt;无需一次性改造旧代码！&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. 常用类型示例&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from typing import Optional, TypedDict

class UserProfile(TypedDict):
    name: str
    age: Optional[int]

def greet(user: UserProfile) -&amp;gt; None:
    print(f&quot;Hello, {user[&apos;name&apos;]}!&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;拥抱改变，代码长青&lt;/h1&gt;
&lt;p&gt;类型注释不仅是“语法糖”，更是工程实践的进化。切换到 Python 高版本，用类型注释写出更健壮、更易维护的代码，迎接 Python 的强类型新时代！&lt;/p&gt;
&lt;p&gt;你目前使用的是Python哪个版本？欢迎留言交流&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%96%B0%E6%99%8B%E5%8C%85%E9%A1%B9%E7%9B%AE%E5%B7%A5%E5%85%B7uv%E7%9A%84%E7%AE%80%E5%8D%95%E5%B0%9D%E8%AF%95.md&quot;&gt;Python-新晋包项目工具uv的简单尝试&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C.md&quot;&gt;Python-标准库之pathlib，路径操作&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C.md&quot;&gt;Python-标准库之pathlib（二），路径操作&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 新晋包项目工具uv的简单尝试</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%96%B0%E6%99%8B%E5%8C%85%E9%A1%B9%E7%9B%AE%E5%B7%A5%E5%85%B7uv%E7%9A%84%E7%AE%80%E5%8D%95%E5%B0%9D%E8%AF%95/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%96%B0%E6%99%8B%E5%8C%85%E9%A1%B9%E7%9B%AE%E5%B7%A5%E5%85%B7uv%E7%9A%84%E7%AE%80%E5%8D%95%E5%B0%9D%E8%AF%95/</guid><description>Python uv工具</description><pubDate>Tue, 20 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;小编最近看公众号里面 &lt;code&gt;uv&lt;/code&gt; 文章比较多，于是也尝试着用了一下，整体感觉对于开发项目人员来说很好，方便自动管理项目依赖，后期在部署时，可以根据 &lt;code&gt;uv&lt;/code&gt; 自动构建的项目依赖来进行配置，省去各种包冲突麻烦&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.11
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;安装uv&lt;/h1&gt;
&lt;p&gt;自己本地已经安装了python，可以直接使用 pip 进行安装&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install uv -i https://pypi.tuna.tsinghua.edu.cn/simple

uv --version
#uv 0.7.3 (3c413f74b 2025-05-07)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;uv各命令&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;初始化项目&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;初始化项目时，可以指定python版本&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uv init test1 
uv init test2 -p 3.11
uv init test3 --python 3.11
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;添加依赖&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用于安装包并自动更新项目配置文件（pyproject.toml）和锁定文件（uv.lock）&lt;/p&gt;
&lt;p&gt;uv add 可以理解为 uv pip install的增强版，底层同样是利用了pip进行安装，但是uv add额外增加了更新项目配置文件的功能&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uv add pandas -i https://pypi.tuna.tsinghua.edu.cn/simple
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-1edb126b39c66360.png&quot; alt=&quot;add&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;删除依赖&lt;/strong&gt;
也会自动删除pandas依赖的其他包&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;uv remove pandas
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;显示完整依赖树&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;uv tree
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-af9db5c1022480c1.png&quot; alt=&quot;tree&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;uv python 命令&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;list	列出可用的Python安装版本
install	下载并安装Python版本
find	显示当前Python安装位置
pin	固定使用特定Python版本
dir	显示uv Python安装目录
uninstall	卸载Python版本
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;uv 升级，自己升级&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;uv self update
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;设置全局默认python版本&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;uv python pin --global 3.11
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;安装python版本&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;uv python install 3.13
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;显示已安装的 Python 版本路径&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;uv python dir
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Web/Python%E4%B8%AD%E4%B8%80%E4%B8%AA%E6%9E%84%E5%BB%BA-web-%E9%A1%B5%E9%9D%A2%E7%9A%84%E7%A5%9E%E5%A5%87%E5%BA%93-streamlit.md&quot;&gt;Python中一个构建-web-页面的神奇库-streamlit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-%E5%9F%BA%E4%BA%8Epyhive%E5%BA%93%E6%93%8D%E4%BD%9Chive.md&quot;&gt;Python-基于pyhive库操作hive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96/Python-%E5%9F%BA%E4%BA%8Eplotly%E5%BA%93%E5%BF%AB%E9%80%9F%E7%94%BB%E6%97%AD%E6%97%A5%E5%9B%BE.md&quot;&gt;Python-基于plotly库快速画旭日图&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 在指定文件夹安装三方库，并进行加载使用</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%9C%A8%E6%8C%87%E5%AE%9A%E6%96%87%E4%BB%B6%E5%A4%B9%E5%AE%89%E8%A3%85%E4%B8%89%E6%96%B9%E5%BA%93%EF%BC%8C%E5%B9%B6%E8%BF%9B%E8%A1%8C%E5%8A%A0%E8%BD%BD%E4%BD%BF%E7%94%A8/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%9C%A8%E6%8C%87%E5%AE%9A%E6%96%87%E4%BB%B6%E5%A4%B9%E5%AE%89%E8%A3%85%E4%B8%89%E6%96%B9%E5%BA%93%EF%BC%8C%E5%B9%B6%E8%BF%9B%E8%A1%8C%E5%8A%A0%E8%BD%BD%E4%BD%BF%E7%94%A8/</guid><description>Python 指定文件夹安装三方库</description><pubDate>Thu, 17 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;在公司内部的服务器中，安装三方库是需要经过层层审批，最后由运维人员进行安装，员工一般是没有权限去随意安装三方库，在审批之前需要进行测试验证可行性，那么这时就需要把三方库安装到自己有权限的目录中，然后再进行使用。小编这里经过亲身测试验证，分享出来供大家参考学习&lt;/p&gt;
&lt;h1&gt;指定文件夹下安装三方库&lt;/h1&gt;
&lt;p&gt;在python中安装三方库，默认使用 &lt;code&gt;pip&lt;/code&gt; 命令进行安装，在该命令中可以通过 &lt;code&gt;target&lt;/code&gt; 指定安装到的文件夹位置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip3 install pyspark==2.4.3 \
    --target=/mnt/disk1/datashare/python \ 
    -i https://mirrors.aliyun.com/pypi/simple/   #指定阿里源
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;加载指定文件夹下安装的三方库&lt;/h1&gt;
&lt;p&gt;在安装三方库时是安装在指定文件夹下，所以需要把指定文件夹插入到 &lt;code&gt;sys.path&lt;/code&gt; 的第1个位置，否则会加载系统自带的版本&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import sys

lib_path = &quot;/mnt/disk1/datashare/python&quot;
sys.path.insert(0,lib_path)   #插入安装三方库的文件夹

import pyspark

print(pyspark.__version__)
#2.4.3
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E4%B8%AD%E7%9A%84Lambda%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0.md&quot;&gt;Python中的Lambda匿名函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-%E5%B8%B8%E7%94%A8%E7%9A%84%E5%8A%A0%E8%A7%A3%E5%AF%86%E7%AE%97%E6%B3%95%E5%AE%9E%E4%BE%8B%E5%BA%94%E7%94%A8.md&quot;&gt;Python-常用的加解密算法实例应用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%A0%BC%E5%BC%8F%E5%8C%96%E6%96%B9%E6%B3%95%E6%80%BB%E7%BB%93.md&quot;&gt;Python-字符串格式化方法总结&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Clickhouse 读取存储在hdfs的hive表数据</title><link>https://datashare-duo.github.io/datashare-blog/posts/Clickhouse/Clickhouse-%E8%AF%BB%E5%8F%96%E5%AD%98%E5%82%A8%E5%9C%A8hdfs%E7%9A%84hive%E8%A1%A8%E6%95%B0%E6%8D%AE/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Clickhouse/Clickhouse-%E8%AF%BB%E5%8F%96%E5%AD%98%E5%82%A8%E5%9C%A8hdfs%E7%9A%84hive%E8%A1%A8%E6%95%B0%E6%8D%AE/</guid><description>hive数据同步至clikehouse</description><pubDate>Mon, 17 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;离线数据经过 hive 处理后，生成的新数据，有时需要对接至研发侧 clikehouse，供前端用户查询使用，所以会涉及到hive数据同步至clikehouse，因为hive数据底层是存储在 hdfs ，因此只要知道hive的建表语句（元数据），再结合 clikehouse 中的特定表引擎（本质是表映射），即可实现 clikehouse 直接读取hdfs数据&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;p&gt;操作系统版本 与 Clickhouse 版本&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /etc/redhat-release
# CentOS Linux release 7.2.1511 (Core)

clickhouse -V
#ClickHouse local version 24.7.2.13 (official build)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;hive中建表并插入测试数据&lt;/h1&gt;
&lt;p&gt;设置字段分割符为 &lt;code&gt;\t&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--建表语句
create table  test_bigdata.test_hdfs_ck (
uid string comment &apos;用户id&apos;,
name string comment &apos;姓名&apos;,
age bigint comment &apos;年龄&apos;,
dt string comment &apos;注册日期&apos;
)  
row format delimited fields terminated by &apos;\t&apos;
stored as textfile
;

--插入数据
insert into table test_bigdata.test_hdfs_ck
values 
(&apos;uid1&apos;,&apos;张三&apos;,&apos;18&apos;,&apos;20250101&apos;),
(&apos;uid2&apos;,&apos;john&apos;,&apos;28&apos;,&apos;20250317&apos;),
(&apos;uid3&apos;,&apos;deepseek&apos;,&apos;10&apos;,&apos;20250315&apos;)
;
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;在clikehouse中创建HDFS映射表&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;前提：需要打通不同服务器之间的网络策略&lt;/strong&gt;&lt;/em&gt;
利用 clikehouse 中的 HDFS 表引擎，指定 hdfs 的路径、hive中表的存储格式，即可创建映射表&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--创建HDFS映射表
create table test.test_hdfs_ck (
uid String comment &apos;用户id&apos;,
name String comment &apos;姓名&apos;,
age UInt16 comment &apos;年龄&apos;,
dt Date comment &apos;注册日期&apos;
)
ENGINE = HDFS(&apos;hdfs://10.20.1.1:8020/user/hive/warehouse/test_bigdata.db/test_hdfs_ck/*&apos;, &apos;TSV&apos;)
;
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;在clikehouse中创建本地表，并导入数据&lt;/h1&gt;
&lt;p&gt;用户在查询数据时，需要实时返回，有时效性要求，所以需要把hdfs的映射表数据导入本地表中&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--创建本地表
create table test.test_ck (
uid String comment &apos;用户id&apos;,
name String comment &apos;姓名&apos;,
age UInt16 comment &apos;年龄&apos;,
dt Date comment &apos;注册日期&apos;
)
ENGINE=MergeTree
PARTITION BY dt
ORDER BY uid
;

--把映射表数据导入本地表
insert into test.test_ck
select *
from test.test_hdfs_ck
;
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;注意事项&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;低版本 clickhouse 不支持创建该表类型引擎&lt;/li&gt;
&lt;li&gt;需要有权限读取hdfs指定路径，默认是clikehouse用户&lt;/li&gt;
&lt;li&gt;日期格式的解析，clickhouse 中默认可以直接解析 &lt;code&gt;yyyy-MM-dd&lt;/code&gt;，但标准规范的8位数字 &lt;code&gt;yyyyMMdd&lt;/code&gt; 在映射时，也可以自动解析&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Clickhouse-%E5%9F%BA%E7%A1%80%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B.md&quot;&gt;Clickhouse 基础使用教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Clickhouse%E4%B8%AD%E5%88%9B%E5%BB%BA%E7%94%9F%E6%88%90%E6%97%A5%E6%9C%9F%E5%BA%8F%E5%88%97%E8%87%AA%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0.md&quot;&gt;Clickhouse中创建生成日期序列自定义函数&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 基于协程的端口扫描工具</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%9F%BA%E4%BA%8E%E5%8D%8F%E7%A8%8B%E7%9A%84%E7%AB%AF%E5%8F%A3%E6%89%AB%E6%8F%8F%E5%B7%A5%E5%85%B7/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%9F%BA%E4%BA%8E%E5%8D%8F%E7%A8%8B%E7%9A%84%E7%AB%AF%E5%8F%A3%E6%89%AB%E6%8F%8F%E5%B7%A5%E5%85%B7/</guid><description>Python 端口扫描工具</description><pubDate>Tue, 14 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;端口扫描技术广泛应用于网络运维、网络安全测试、以及黑客攻击服务器等领域。在网络运维中，管理员通过端口扫描来检查服务器或设备的开放端口，确保网络安全并及时发现潜在的漏洞。在网络安全测试中，端口扫描帮助识别网络中的弱点，进而制定防护措施，提升整体安全性。而在黑客攻击的情境下，攻击者通过端口扫描发现目标设备开放的服务，从而寻找攻击入口点，实施非法入侵。因此，端口扫描不仅是安全防护的一个重要工具，也常被黑客用作攻击手段。&lt;/p&gt;
&lt;p&gt;本篇文章的目的是通过构建一个端口扫描工具，深入探讨如何在Python中利用协程进行高效的网络端口扫描。传统的端口扫描通常是串行的，效率较低，尤其在扫描大量IP时，耗时非常长。借助Python的协程特性，我们可以实现高并发的网络扫描，显著提高扫描速度，并且在处理多个任务时能够有效地节省系统资源。通过实践这一过程，读者不仅可以掌握端口扫描的基本原理，还能进一步理解如何在Python中高效地使用协程来解决实际问题。&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version)
#python 版本： 3.11.11 | packaged by Anaconda, Inc. | 
#(main, Dec 11 2024, 16:34:19) [MSC v.1929 64 bit (AMD64)]
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;效果&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;直接扫描IP地址：&lt;/strong&gt;
&lt;img src=&quot;./images/6641583-e752ae8fd2ed83de.png&quot; alt=&quot;扫描ip&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;扫描域名：&lt;/strong&gt;
&lt;img src=&quot;./images/6641583-e6eaa6e182d3cb37.png&quot; alt=&quot;扫描域名&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;完整代码&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import asyncio
import socket
from datetime import datetime


class ScanPort:
    def __init__(self, concurrency_limit=100):
        self.ip = None
        self.concurrency_limit = concurrency_limit  # 并发限制，默认是 100

    async def scan_port(self, port, semaphore):
        try:
            # 获取信号量
            async with semaphore:
                # 创建异步 TCP 连接
                conn = asyncio.open_connection(self.ip, port)
                reader, writer = await asyncio.wait_for(conn, timeout=1)
                writer.close()
                await writer.wait_closed()
                print(f&apos;Ip: {self.ip} Port: {port} IS OPEN&apos;)
        except (asyncio.TimeoutError, ConnectionRefusedError, OSError):
            pass  # 忽略连接超时或端口未开启的错误

    async def scan_ports(self):
        semaphore = asyncio.Semaphore(self.concurrency_limit)  # 限制最大并发数
        tasks = []

        for port in range(1, 65536):  # 要扫描的端口范围
            tasks.append(self.scan_port(port, semaphore))  # 为每个端口创建一个异步任务

        await asyncio.gather(*tasks)  # 并发执行所有任务

    def start(self):
        host = input(&quot;please input the host want to scan: &quot;)
        self.ip = socket.gethostbyname(host)  # 获取主机的 IP 地址
        start_time = datetime.now()

        # 执行异步扫描
        asyncio.run(self.scan_ports())

        print(&quot;port scan has done, use time:&quot;, datetime.now() - start_time)

if __name__ == &quot;__main__&quot;:
    # 运行扫描程序
    ScanPort(concurrency_limit=2000).start()  # 设置并发量限制为2000
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-%E5%88%A9%E7%94%A8aiohttp%E5%BC%82%E6%AD%A5%E6%B5%81%E5%BC%8F%E4%B8%8B%E8%BD%BD%E6%96%87%E4%BB%B6.md&quot;&gt;Python-利用aiohttp异步流式下载文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/Python-%E5%88%A9%E7%94%A8%E5%8D%8F%E7%A8%8B%E9%87%87%E9%9B%86%E6%83%B3%E7%9C%8B%E7%9A%84%E3%80%8A%E4%BA%BA%E4%B8%96%E9%97%B4%E3%80%8B%E4%B8%8B%E8%BD%BD%E5%9C%B0%E5%9D%80.md&quot;&gt;Python-利用协程采集想看的《人世间》下载地址&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Clickhouse 基础使用教程</title><link>https://datashare-duo.github.io/datashare-blog/posts/Clickhouse/Clickhouse-%E5%9F%BA%E7%A1%80%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Clickhouse/Clickhouse-%E5%9F%BA%E7%A1%80%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</guid><description>Clickhouse 基础使用教程</description><pubDate>Thu, 19 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;小编最近在做一个数据类产品项目，每天涉及到几十亿数据的汇总计算，从不同维度、不同的关联关系进行汇总统计，刚开始时项目组使用的是hive，写好大量的业务SQL计算逻辑后（中间有一些其他程序处理脚本），每天通过定时任务来生成数据，然后把生成的数据推送到研发端的ES（Elasticsearch），研发端基于ES查询数据，给到前端来展示&lt;/p&gt;
&lt;p&gt;但是，随着项目的不断深入，产品需求的快速迭代，之前的各种统计指标更新迭代，基于hive数据库的计算方式不能再满足当前快速迭代的场景。项目组经过调研，最终选择Clickhouse数据库，让研发来每天通过查询Clickhouse数据库，来统计生成各种统计指标，并把结果缓存至ES&lt;/p&gt;
&lt;p&gt;项目数据架构的大概思路：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hive每日生成明细数据，把这些明细数据导入Clickhouse&lt;/li&gt;
&lt;li&gt;在Clickhouse中生成一些中间表，供研发人员查询数据使用，方便进行各种拼接组合&lt;/li&gt;
&lt;li&gt;研发人员每日基于明细表、中间表，计算统计指标，把结果缓存至ES&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;p&gt;操作系统版本 与 Clickhouse 版本&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /etc/redhat-release
# CentOS Linux release 7.2.1511 (Core)

clickhouse -V
#ClickHouse local version 24.7.2.13 (official build)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;登录客户端&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;clickhouse-client -u xxxx --password xxxxxx -m 
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;-u 或者 --user ：指定用户名
--password ：密码
-m 或者 --multiline ：进入客户端后，运行输入多行sql语句&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;建表&lt;/h1&gt;
&lt;p&gt;在Clickhouse中，数据既可以存放到单个服务器节点，也可以把数据分散存放到集群中各个节点服务器中，这个需要看数据量大小，来选择合适的表类型&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;创建本地表&lt;/strong&gt;
如果数据量比较小的话，建议选择本地表，在数据查询时以提高性能，可以节省节点之间数据传输的时间，比如有几千万行数据的表，完全可以选择本地表，但是查询数据时，只能在当前服务器节点查询，其他服务器节点没有该表&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面以用户表为列，进行建表操作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;create table test.user_table (
uid String comment &apos;用户id&apos;,
sex String comment &apos;性别&apos;,
age UInt16 comment &apos;年龄&apos;,
phone String comment &apos;联系电话&apos;
)
engine = MergeTree()
order by uid;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;数据类型需要注意是大写开头 ，&lt;code&gt;String&lt;/code&gt;、&lt;code&gt;UInt16&lt;/code&gt;，表引擎类型也必须大写 &lt;code&gt;MergeTree&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;如果没有指定主键的话，默认用 order by 指定的字段&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;创建分布式表&lt;/strong&gt;
分布式表在Clickhouse中，只是一个视图，不实际存放数据，指向实际存放数据的本地表，所以在创建分布式表时，需要在各个服务器节点创建名字一模一样的本地表&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;--在集群中创建实际存放数据的本地表
create table test.user_event on cluster data_cluster(
uid String comment &apos;用户id&apos;,
event String comment &apos;事件名称&apos;,
c_time DateTime comment &apos;点击时间&apos;,
dt Date comment &apos;日期&apos;
)
engine = MergeTree()
partition by dt 
order by uid;

--创建分布式表
create table test.user_event_distributed (
uid String comment &apos;用户id&apos;,
event String comment &apos;事件名称&apos;,
c_time DateTime comment &apos;点击时间&apos;,
dt Date comment &apos;日期&apos;
)
engine = Distributed(&apos;data_cluster&apos;, &apos;test&apos;, &apos;user_event&apos;, rand())
;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分布式表需要选择 &lt;code&gt;Distributed&lt;/code&gt; 表引擎，其中
第1个参数：集群名称
第2个参数：数据库名
第3个参数：数据表名
第3个参数：分片key，数据被到不同服务器依据的字段，相同的值会被分配到同一台服务器&lt;/p&gt;
&lt;p&gt;如果在创建分布式表 &lt;code&gt;test.user_event_distributed&lt;/code&gt; 时没有指定 &lt;code&gt;on cluster data_cluster&lt;/code&gt;，那么创建是本地表，后续的查询只能在建表的那个节点服务器查询数据，这里小编就创建的是一个本地表&lt;/p&gt;
&lt;h1&gt;查询&lt;/h1&gt;
&lt;p&gt;Clickhouse 的sql 查询语句和hive的比较类似，使用起来基本没啥差距，只有极个别的函数不支持，下面小编列举一下自己在使用时，遇到的个别函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有 &lt;code&gt;nvl&lt;/code&gt; 函数，需要用 &lt;code&gt;coalesce&lt;/code&gt; 代替&lt;/li&gt;
&lt;li&gt;支持窗口函数，&lt;code&gt;row_number&lt;/code&gt; 等&lt;/li&gt;
&lt;li&gt;没有 &lt;code&gt;concat_ws&lt;/code&gt;，需要用 &lt;code&gt;arrayStringConcat&lt;/code&gt; 代替&lt;/li&gt;
&lt;li&gt;没有 &lt;code&gt;collect_list&lt;/code&gt;，需要用 &lt;code&gt;groupArray&lt;/code&gt; 代替&lt;/li&gt;
&lt;li&gt;一个好用的函数，&lt;code&gt;arrayZip&lt;/code&gt;，类似python中的zip&lt;/li&gt;
&lt;li&gt;没有 &lt;code&gt;split&lt;/code&gt; 函数，需要用 &lt;code&gt;splitByString&lt;/code&gt; 代替&lt;/li&gt;
&lt;li&gt;&lt;code&gt;arrayMap&lt;/code&gt;、&lt;code&gt;arraySum&lt;/code&gt;、&lt;code&gt;arraySlice&lt;/code&gt; 等函数很好用，性能高&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;表变更&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;删除特定分区&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;alter table test.user_event on cluster data_cluster drop partition &apos;2024-11-30&apos;;
alter table test.user_event on cluster data_cluster delete where dt &amp;gt; &apos;2024-11-15&apos;;
alter table test.user_event on cluster data_cluster delete where dt=&apos;2024-11-30&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;删除满足特定条件数据&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;alter table test.user_event on cluster data_cluster delete where user_id=&apos;u00001&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;自定义函数&lt;/h1&gt;
&lt;p&gt;不推荐使用外部语言编写自定义函数，例如：java、python 等，推荐使用自有的函数，逐步组合实现自定义函数，性能高&lt;/p&gt;
&lt;p&gt;一个样例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--分割字符串并把类型转换为整数
create function x_split as (x) -&amp;gt;
(
    arrayMap(
            y -&amp;gt; toUInt32(y), 
            splitByString(&apos;,&apos;, x)
        )
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Clickhouse%E4%B8%AD%E5%88%9B%E5%BB%BA%E7%94%9F%E6%88%90%E6%97%A5%E6%9C%9F%E5%BA%8F%E5%88%97%E8%87%AA%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0.md&quot;&gt;Clickhouse中创建生成日期序列自定义函数&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Clickhouse中创建生成日期序列自定义函数</title><link>https://datashare-duo.github.io/datashare-blog/posts/Clickhouse/Clickhouse%E4%B8%AD%E5%88%9B%E5%BB%BA%E7%94%9F%E6%88%90%E6%97%A5%E6%9C%9F%E5%BA%8F%E5%88%97%E8%87%AA%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Clickhouse/Clickhouse%E4%B8%AD%E5%88%9B%E5%BB%BA%E7%94%9F%E6%88%90%E6%97%A5%E6%9C%9F%E5%BA%8F%E5%88%97%E8%87%AA%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0/</guid><description>Clickhouse 自定义函数</description><pubDate>Mon, 09 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;Clickhouse 数据库最近几年在大数据领域应用越来越广，因其卓越的性能，外加支持海量数据存储与处理，国内很多大厂都有在使用。其底层使用C++语言编写，小编在使用时，感觉可以极限压榨CPU性能，计算速度远超 Hive，应用在数据产品领域，基本没啥问题&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存储的数据量，可以与Hadoop生态持平&lt;/li&gt;
&lt;li&gt;计算性能，可以与Mysql持平&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;p&gt;操作系统版本与Clickhouse版本&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /etc/redhat-release
# CentOS Linux release 7.2.1511 (Core)

clickhouse -V
#ClickHouse local version 24.7.2.13 (official build)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;效果展示&lt;/h1&gt;
&lt;p&gt;提供开始日期、结束日期，生成一个日期序列，返回的是一个数组&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select generateSeries_dt(&apos;2024-12-01&apos;,&apos;2024-12-07&apos;) as dts;
--[&apos;2024-12-01&apos;,&apos;2024-12-02&apos;,&apos;2024-12-03&apos;,&apos;2024-12-04&apos;,
--&apos;2024-12-05&apos;,&apos;2024-12-06&apos;,&apos;2024-12-07&apos;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;生成日期序列自定义函数&lt;/h1&gt;
&lt;p&gt;因Clickhouse 是用C++语言编写，如果想扩展自定义函数，需要用C++来实现或借助sql方式实现，如果想使用其他语言，则只能进行桥接（把数据输出至系统，在系统中调用其他语言处理数据，然后把系统中输出的结果，拿回到clickhouse）。这里小编借助sql 方式来实现，感觉实现起来和编写python很像&lt;/p&gt;
&lt;p&gt;利用Chatgpt的帮助，可以一步一步完成所需要的函数功能&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;create function generateSeries_dt as (start_dt,end_dt) -&amp;gt; 
(
    arrayMap(
        x -&amp;gt; toDate(start_dt) + x, 
        range(toUInt32(toDate(end_dt) - toDate(start_dt)) + 1)
    )
);
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;将字符串 start_dt 和 end_dt 转换为 Date 类型：&lt;code&gt;toDate(start_dt)&lt;/code&gt; 和 &lt;code&gt;toDate(end_dt)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;计算日期之间的差值：&lt;code&gt;toDate(end_dt) - toDate(start_dt)&lt;/code&gt;，结果是天数&lt;/li&gt;
&lt;li&gt;使用 range 函数生成从 0 到差值的整数序列：&lt;code&gt;range(toUInt32(...) + 1)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用 arrayMap 遍历序列，将每个整数加到起始日期上，生成完整的日期序列&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过上面的详细解释，感觉是不是和python很像，经过测试，其性能大概是java编写的自定义函数性能100倍&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-%E5%9F%BA%E4%BA%8Epyhive%E5%BA%93%E6%93%8D%E4%BD%9Chive.md&quot;&gt;Python-基于pyhive库操作hive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Rust-%E6%98%AF%E5%90%A6%E4%BC%9A%E9%87%8D%E5%86%99-Python-%E8%A7%A3%E9%87%8A%E5%99%A8%E4%B8%8E%E6%9C%89%E5%85%B3%E7%9A%84%E5%BA%93%EF%BC%8C%E6%9B%BF%E4%BB%A3-C-%E8%AF%AD%E8%A8%80%E5%9C%B0%E4%BD%8D%EF%BC%9F.md&quot;&gt;Rust-是否会重写-Python-解释器与有关的库，替代-C-语言地位？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E4%B8%AD%E7%9A%84Lambda%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0.md&quot;&gt;Python中的Lambda匿名函数&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>hadoop 常用命令总结</title><link>https://datashare-duo.github.io/datashare-blog/posts/Hive/hadoop-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E6%80%BB%E7%BB%93/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Hive/hadoop-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E6%80%BB%E7%BB%93/</guid><description>hadoop 常用命令总结</description><pubDate>Fri, 27 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;在本地记事本记得太多了，有的命令使用频次很低，时间长了容易忘记，分享出来后续使用时查找&lt;/p&gt;
&lt;h1&gt;常用命令&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;列出数据库下的所有表&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -ls /user/hive/warehouse/test.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;统计数据库占用磁盘的总大小&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -du -s -h /user/hive/warehouse/test.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查看数据表中的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -cat /user/hive/warehouse/test.db/test/00000_0 | head 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设置副本数
Hadoop默认是3个副本，replication factor  副本因子&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -setrep -R 1 /user/hive/warehouse/test.db/test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建文件夹&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -mkdir /user/datashare
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修改文件权限&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -chmod 700 /user/datashare
hadoop fs -chmod -R 700 /user/datashare   #递归进行，针对子文件夹
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查HDFS中的文件是否存在&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -test -e /user/hive/warehouse/test.db/test/0*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;统计文件个数&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -ls -h /user/hive/warehouse/test.db/test/dt=202310 | wc -l
hadoop fs -count /user/hive/warehouse/test.db/test/dt=202310
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;统计多个文件夹的总占用大小&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -du -s  /user/hive/warehouse/test.db/test/dt=202310*  |   awk &apos;{print $1}&apos; | awk &apos;{sum+=$1}END{print sum/1024**3 &quot; G&quot;}&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;统计每个文件夹的单独大小&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -du -s  /user/hive/warehouse/test.db/test/dt=202310*  |   awk &apos;{print $1/1024**3 &quot; G&quot;}&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;跨集群访问&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -ls hdfs://10.20.1.100:8100/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查看hadoop 版本&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查看数据缺失的块&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fsck /user/hive/warehouse/test.db/test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;复制分区至新表&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;1. CREATE TABLE new_table LIKE old_table;
2. 使用hadoop fs -cp 命令，把old_table对应的HDFS目录的文件夹全部拷贝到new_table对应的HDFS目录下；
3. 使用MSCK REPAIR TABLE new_table;修复新表的分区元数据；
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查看数据库里面各数据表的大小，并进行排序&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -du -s /user/hive/warehouse/test.db/* | sort -n | numfmt --to=iec --field=1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;numfmt --to=iec --field=1&lt;/code&gt; 的作用是仅将第一列（大小）转换为人类可读的格式，而不改变第二列（路径）的内容。
&lt;code&gt;--field=1&lt;/code&gt; 让 numfmt 只处理第一列，从而避免误修改文件路径&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;删除文件、空目录&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -rm /user/hive/warehouse/emptydir
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;删除文件夹&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;hadoop fs -rmr /user/hadoop/dir
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Rust 是否会重写 Python 解释器与有关的库，替代 C 语言地位？</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Rust-%E6%98%AF%E5%90%A6%E4%BC%9A%E9%87%8D%E5%86%99-Python-%E8%A7%A3%E9%87%8A%E5%99%A8%E4%B8%8E%E6%9C%89%E5%85%B3%E7%9A%84%E5%BA%93%EF%BC%8C%E6%9B%BF%E4%BB%A3-C-%E8%AF%AD%E8%A8%80%E5%9C%B0%E4%BD%8D%EF%BC%9F/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Rust-%E6%98%AF%E5%90%A6%E4%BC%9A%E9%87%8D%E5%86%99-Python-%E8%A7%A3%E9%87%8A%E5%99%A8%E4%B8%8E%E6%9C%89%E5%85%B3%E7%9A%84%E5%BA%93%EF%BC%8C%E6%9B%BF%E4%BB%A3-C-%E8%AF%AD%E8%A8%80%E5%9C%B0%E4%BD%8D%EF%BC%9F/</guid><description>Python Rust是否会重写</description><pubDate>Tue, 24 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;近2年随着Rust语言的大力发展，一些系统与软件开始逐渐使用Rust语言来实现，并且一些大型公司也开始逐渐转向Rust&lt;/p&gt;
&lt;p&gt;因为在学习 Polars 库时，看到该库是使用Rust实现的，小编近一年也逐渐开始学习Rust语言，了解到其中的一些思想相对其他语言来说确实比较先进，所有权概念的引入，不仅可以提升性能，而且还保证了数据安全、准确，不会有数据竞争问题的产生&lt;/p&gt;
&lt;p&gt;小编最近在处理加解密任务时，借助Rust语言实现了一个DES加解密库，借助Rust 中的 &lt;code&gt;pyo3&lt;/code&gt; 包，在Python 中借助 &lt;code&gt;maturin&lt;/code&gt; 库，可以把 Rust 实现的库转换为 Python 的包，供Python调用&lt;/p&gt;
&lt;h1&gt;DES加解密，Rust实现&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;use pyo3::prelude::*;

use openssl::provider::Provider;
use openssl::symm::{Cipher,encrypt,decrypt};
use hex;

const KEY:&amp;amp;[u8; 8]=b&quot;ABCD1234&quot;;
const IV:&amp;amp;[u8; 8]=b&quot;ABCD1234&quot;;

#[pyfunction]
fn des_encrypt(data:String)-&amp;gt; String {
    let _provider = Provider::try_load(None, &quot;legacy&quot;, true).unwrap();
    let cipher: Cipher = Cipher::des_cbc();

    let ciphertext = encrypt(cipher, KEY, Some(IV), data.as_bytes());
    
    hex::encode(&amp;amp;ciphertext.unwrap()).to_uppercase()

}

#[pyfunction]
fn des_decrypt(data:String)-&amp;gt; String {
    let _provider = Provider::try_load(None, &quot;legacy&quot;, true).unwrap();
    let cipher: Cipher = Cipher::des_cbc();
    
    match hex::decode(&amp;amp;data) {
        Ok(bytes) =&amp;gt; {
            // println!(&quot;Decoded: {:?}&quot;, bytes); // 输出: [104, 101, 108, 108, 111]
            // println!(&quot;{:?}&quot;, des_decrypt(&amp;amp;bytes));
            match decrypt(cipher, KEY, Some(IV), &amp;amp;bytes) {
                Ok(bytes) =&amp;gt; {
                    // println!(&quot;Decoded: {:#?}&quot;, bytes); // 输出: [104, 101, 108, 108, 111]
                    match String::from_utf8(bytes) {
                        Ok(string) =&amp;gt; string, // 输出: &quot;hello&quot;
                        Err(_) =&amp;gt; &quot;&quot;.to_string(),
                    }
                },
                Err(_) =&amp;gt; &quot;&quot;.to_string(),
            }
        },
        Err(_) =&amp;gt; &quot;&quot;.to_string(),
    }

}

#[pymodule]
fn des_rust(_py: Python, m: &amp;amp;PyModule) -&amp;gt; PyResult&amp;lt;()&amp;gt; {
    m.add_function(wrap_pyfunction!(des_encrypt, m)?)?;
    m.add_function(wrap_pyfunction!(des_decrypt, m)?)?;
    
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后利用 &lt;code&gt;Maturin&lt;/code&gt; 进行打包，可以生成 Python 的库/包/轮子，小编这里生成的是 &lt;code&gt;des_rust-0.1.0-cp37-abi3-win_amd64.whl&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后安装该包后，即可在Python中进行使用&lt;/p&gt;
&lt;h1&gt;Python 使用&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;from des_rust import des_decrypt,des_encrypt

data=des_decrypt(des_encrypt(&apos;DataShare&apos;))

print(data)    #DataShare
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过性能测试，效率相对使用Python实现的包，性能有大幅提升&lt;/p&gt;
&lt;h1&gt;进一步思考&lt;/h1&gt;
&lt;p&gt;通过以上的案例，小编走通了从Python中调用Rust代码的流程，结合小编学习 Rust 的思考，那么Rust + Python 结合，是否会成为将来数据分析、机器学习领域的趋势？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Python 比较灵活，拿来即用，学习起来也容易，现在普及程度也很广，最重要的是能很快出成果，处在现阶段的社会，出成果很重要，有的老板恨不得第1天晚上想出了一个idea，第2天就想要成果，当然这个也不能怨老板，只能说现阶段竞争很激烈&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rust 内存安全、性能高，可以弥补Python 的不足，截止当前已经有很多Python 库是使用Rust 实现的，随着老板的想发愈发复杂，想提升数据处理性能，只能使用底层的语言实现，但也不能另起炉灶，否则前期的工作相当于白做，而且业务也需要快速迭代&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rust + Python 结合是否会成为将来数据领域的趋势呢？让我们拭目以待&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E4%B8%8E%E6%8C%96%E6%8E%98/%E3%80%8A%E7%B2%BE%E7%9B%8A%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E3%80%8B%E8%AF%BB%E4%B9%A6%E5%88%86%E4%BA%AB-----%E5%A2%9E%E9%95%BF%E5%BC%95%E6%93%8E%E8%AF%B4.md&quot;&gt;《精益数据分析》读书分享-----增长引擎说&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/%E9%9A%8F%E7%AC%94/%E5%90%B4%E5%86%9B%E8%80%81%E5%B8%88%E7%9A%84%E3%80%8A%E8%AE%A1%E7%AE%97%E4%B9%8B%E9%AD%82%E3%80%8B%E9%83%A8%E5%88%86%E9%87%8D%E7%82%B9%E6%91%98%E8%A6%81.md&quot;&gt;吴军老师的《计算之魂》部分重点摘要&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-10-时间序列类型</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-10-%E6%97%B6%E9%97%B4%E5%BA%8F%E5%88%97%E7%B1%BB%E5%9E%8B/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-10-%E6%97%B6%E9%97%B4%E5%BA%8F%E5%88%97%E7%B1%BB%E5%9E%8B/</guid><description>Polars 时间序列类型（Time series）</description><pubDate>Mon, 05 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;polars学习系列文章，第10篇 时间序列类型（Time series）&lt;/p&gt;
&lt;p&gt;该系列文章会分享到github，大家可以去下载jupyter文件，进行参考学习
仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;小编运行环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.9

import polars as pl

print(&quot;polars 版本：&quot;,pl.__version__)
#polars 版本： 1.2.1
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;日期时间类型&lt;/h1&gt;
&lt;p&gt;Polars 原生支持解析时间序列数据，而且能执行一些复杂的操作&lt;/p&gt;
&lt;p&gt;包含的日期时间类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Date&lt;/strong&gt;：日期类型，例如：2014-07-08，内部表示为自1970-01-01的天数，用32位有符号整数表示&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Datetime&lt;/strong&gt;：日期时间类型，例如：2014-07-08 07:00:00&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Duration&lt;/strong&gt;：时间间隔类型&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time&lt;/strong&gt;：时间类型&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;从文件加载数据时，解析时间&lt;/h1&gt;
&lt;p&gt;从csv文件加载数据时，可以指定 &lt;code&gt;try_parse_dates=True&lt;/code&gt;，让polars去尝试解析日期时间&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df = pl.read_csv(&quot;./data/apple_stock.csv&quot;, try_parse_dates=True)
print(df)
#shape: (100, 2)
┌────────────┬────────┐
│ Date       ┆ Close  │
│ ---        ┆ ---    │
│ date       ┆ f64    │
╞════════════╪════════╡
│ 1981-02-23 ┆ 24.62  │
│ 1981-05-06 ┆ 27.38  │
│ 1981-05-18 ┆ 28.0   │
│ 1981-09-25 ┆ 14.25  │
│ 1982-07-08 ┆ 11.0   │
│ …          ┆ …      │
│ 2012-05-16 ┆ 546.08 │
│ 2012-12-04 ┆ 575.85 │
│ 2013-07-05 ┆ 417.42 │
│ 2013-11-07 ┆ 512.49 │
│ 2014-02-25 ┆ 522.06 │
└────────────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;字符串转换为日期时间类型&lt;/h1&gt;
&lt;p&gt;通过调用字符串的 &lt;code&gt;str.to_date&lt;/code&gt; 方法，需要指定日期时间解析时的格式&lt;/p&gt;
&lt;p&gt;日期时间解析格式，可参考该文档：&amp;lt;br/&amp;gt;
&lt;a href=&quot;https://docs.rs/chrono/latest/chrono/format/strftime/index.html&quot;&gt;https://docs.rs/chrono/latest/chrono/format/strftime/index.html&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df = pl.read_csv(&quot;./data/apple_stock.csv&quot;, try_parse_dates=False)

df = df.with_columns(pl.col(&quot;Date&quot;).str.to_date(&quot;%Y-%m-%d&quot;))
print(df)
shape: (100, 2)
┌────────────┬────────┐
│ Date       ┆ Close  │
│ ---        ┆ ---    │
│ date       ┆ f64    │
╞════════════╪════════╡
│ 1981-02-23 ┆ 24.62  │
│ 1981-05-06 ┆ 27.38  │
│ 1981-05-18 ┆ 28.0   │
│ 1981-09-25 ┆ 14.25  │
│ 1982-07-08 ┆ 11.0   │
│ …          ┆ …      │
│ 2012-05-16 ┆ 546.08 │
│ 2012-12-04 ┆ 575.85 │
│ 2013-07-05 ┆ 417.42 │
│ 2013-11-07 ┆ 512.49 │
│ 2014-02-25 ┆ 522.06 │
└────────────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;从日期时间类型中提取特定的日期类型&lt;/h1&gt;
&lt;p&gt;比如从日期时间类型列中提取年份、日期等，通过 &lt;code&gt;.dt&lt;/code&gt; 来提取&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df_with_year = df.with_columns(pl.col(&quot;Date&quot;).dt.year().alias(&quot;year&quot;))
print(df_with_year)
#shape: (100, 3)
┌────────────┬────────┬──────┐
│ Date       ┆ Close  ┆ year │
│ ---        ┆ ---    ┆ ---  │
│ date       ┆ f64    ┆ i32  │
╞════════════╪════════╪══════╡
│ 1981-02-23 ┆ 24.62  ┆ 1981 │
│ 1981-05-06 ┆ 27.38  ┆ 1981 │
│ 1981-05-18 ┆ 28.0   ┆ 1981 │
│ 1981-09-25 ┆ 14.25  ┆ 1981 │
│ 1982-07-08 ┆ 11.0   ┆ 1982 │
│ …          ┆ …      ┆ …    │
│ 2012-05-16 ┆ 546.08 ┆ 2012 │
│ 2012-12-04 ┆ 575.85 ┆ 2012 │
│ 2013-07-05 ┆ 417.42 ┆ 2013 │
│ 2013-11-07 ┆ 512.49 ┆ 2013 │
│ 2014-02-25 ┆ 522.06 ┆ 2014 │
└────────────┴────────┴──────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;混合时差&lt;/h1&gt;
&lt;p&gt;当有混合时差（例如，由于跨越夏令时），可以使用 &lt;code&gt;dt.convert_time_zone&lt;/code&gt; 来进行转换&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data = [
    &quot;2021-03-27T00:00:00+0100&quot;,
    &quot;2021-03-28T00:00:00+0100&quot;,
    &quot;2021-03-29T00:00:00+0200&quot;,
    &quot;2021-03-30T00:00:00+0200&quot;,
]
mixed_parsed = (
    pl.Series(data)
    .str.to_datetime(&quot;%Y-%m-%dT%H:%M:%S%z&quot;)
    .dt.convert_time_zone(&quot;Europe/Brussels&quot;)
)


print(mixed_parsed)
#shape: (4,)
Series: &apos;&apos; [datetime[μs, Europe/Brussels]]
[
	2021-03-27 00:00:00 CET
	2021-03-28 00:00:00 CET
	2021-03-29 00:00:00 CEST
	2021-03-30 00:00:00 CEST
]
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;日期时间数据筛选&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;from datetime import datetime

df = pl.read_csv(&quot;./data/apple_stock.csv&quot;, try_parse_dates=True)

print(df)
#shape: (100, 2)
┌────────────┬────────┐
│ Date       ┆ Close  │
│ ---        ┆ ---    │
│ date       ┆ f64    │
╞════════════╪════════╡
│ 1981-02-23 ┆ 24.62  │
│ 1981-05-06 ┆ 27.38  │
│ 1981-05-18 ┆ 28.0   │
│ 1981-09-25 ┆ 14.25  │
│ 1982-07-08 ┆ 11.0   │
│ …          ┆ …      │
│ 2012-05-16 ┆ 546.08 │
│ 2012-12-04 ┆ 575.85 │
│ 2013-07-05 ┆ 417.42 │
│ 2013-11-07 ┆ 512.49 │
│ 2014-02-25 ┆ 522.06 │
└────────────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;筛选单个日期时间对象&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;filtered_df = df.filter(
    pl.col(&quot;Date&quot;) == datetime(1995, 10, 16),
)
print(filtered_df)
#shape: (1, 2)
┌────────────┬───────┐
│ Date       ┆ Close │
│ ---        ┆ ---   │
│ date       ┆ f64   │
╞════════════╪═══════╡
│ 1995-10-16 ┆ 36.13 │
└────────────┴───────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;筛选一个日期范围&lt;/h2&gt;
&lt;p&gt;通过 &lt;code&gt;is_between&lt;/code&gt; 方法，指定一个范围&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;filtered_range_df = df.filter(
    pl.col(&quot;Date&quot;).is_between(datetime(1995, 7, 1), datetime(1995, 11, 1)),
)
print(filtered_range_df)
#shape: (2, 2)
┌────────────┬───────┐
│ Date       ┆ Close │
│ ---        ┆ ---   │
│ date       ┆ f64   │
╞════════════╪═══════╡
│ 1995-07-06 ┆ 47.0  │
│ 1995-10-16 ┆ 36.13 │
└────────────┴───────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;筛选 负数日期&lt;/h2&gt;
&lt;p&gt;考古领域数据可能会涉及这类日期&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ts = pl.Series([&quot;-1300-05-23&quot;, &quot;-1400-03-02&quot;]).str.to_date()

negative_dates_df = pl.DataFrame({&quot;ts&quot;: ts, &quot;values&quot;: [3, 4]})

negative_dates_filtered_df = negative_dates_df.filter(pl.col(&quot;ts&quot;).dt.year() &amp;lt; -1300)
print(negative_dates_filtered_df)
#shape: (1, 2)
┌─────────────┬────────┐
│ ts          ┆ values │
│ ---         ┆ ---    │
│ date        ┆ i64    │
╞═════════════╪════════╡
│ -1400-03-02 ┆ 4      │
└─────────────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6.md&quot;&gt;Python polars学习-01 读取与写入文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F.md&quot;&gt;Python polars学习-02 上下文与表达式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-03_%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2.md&quot;&gt;Python polars学习-03 数据类型转换&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-04_%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python polars学习-04 字符串数据处理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-05_%E5%8C%85%E5%90%AB%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.md&quot;&gt;Python polars学习-05 包含的数据结构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-06_Lazy-Eager-API.md&quot;&gt;Python polars学习-06 Lazy / Eager API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-07_%E7%BC%BA%E5%A4%B1%E5%80%BC.md&quot;&gt;Python polars学习-07 缺失值&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-08_%E5%88%86%E7%B1%BB%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python polars学习-08 分类数据处理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-09_%E6%95%B0%E6%8D%AE%E6%A1%86%E5%85%B3%E8%81%94%E4%B8%8E%E6%8B%BC%E6%8E%A5.md&quot;&gt;Python polars学习-09 数据框关联与拼接&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-09_数据框关联与拼接</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-09_%E6%95%B0%E6%8D%AE%E6%A1%86%E5%85%B3%E8%81%94%E4%B8%8E%E6%8B%BC%E6%8E%A5/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-09_%E6%95%B0%E6%8D%AE%E6%A1%86%E5%85%B3%E8%81%94%E4%B8%8E%E6%8B%BC%E6%8E%A5/</guid><description>Polars 数据框关联与拼接（Join 、Concat）</description><pubDate>Tue, 23 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;polars学习系列文章，第9篇 数据框关联与拼接（Join 、Concat）&lt;/p&gt;
&lt;p&gt;该系列文章会分享到github，大家可以去下载jupyter文件，进行参考学习&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;小编运行环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.9

import polars as pl

print(&quot;polars 版本：&quot;,pl.__version__)
#polars 版本： 1.2.1
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;数据框关联 Join&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;polars&lt;/code&gt; 通过指定参数 &lt;code&gt;how&lt;/code&gt;，支持以下方式的关联：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;inner&lt;/strong&gt;：类似sql中的 inner join,取2个数据框共同的部分&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;left&lt;/strong&gt;：类似sql中的 left join,取左边数据框所有数据，匹配右边数据框数据，能匹配到的进行匹配，匹配不到的用 &lt;code&gt;null&lt;/code&gt; 填充&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;full&lt;/strong&gt;：类似sql中的 full outer join，返回2个数据框的全量数据，匹配不到的用 &lt;code&gt;null&lt;/code&gt; 填充&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;cross&lt;/strong&gt;：2个数据框的笛卡尔积，数据行数为，&lt;code&gt;len(A) × len(B)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;semi&lt;/strong&gt;：用的相对比较少，左边数据框中关联字段同时存在右边数据框中，只返回左边数据框的行，有点类似 &lt;code&gt;inner join&lt;/code&gt;,但是不全完一样，即使右边数据框有多行的，左边返回的还是单行，也就是遇到关联字段存在于右边数据框，就返回&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;anti&lt;/strong&gt;：用的相对比较少，返回左边数据框中关联字段不存在右边数据框中的行，与 &lt;code&gt;semi&lt;/code&gt; 相反&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;数据准备&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;df_customers = pl.DataFrame(
    {
        &quot;customer_id&quot;: [1, 2, 3],
        &quot;name&quot;: [&quot;Alice&quot;, &quot;Bob&quot;, &quot;Charlie&quot;],
    }
)

print(df_customers)
#shape: (3, 2)
┌─────────────┬─────────┐
│ customer_id ┆ name    │
│ ---         ┆ ---     │
│ i64         ┆ str     │
╞═════════════╪═════════╡
│ 1           ┆ Alice   │
│ 2           ┆ Bob     │
│ 3           ┆ Charlie │
└─────────────┴─────────┘

df_orders = pl.DataFrame(
    {
        &quot;order_id&quot;: [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;],
        &quot;customer_id&quot;: [1, 2, 2],
        &quot;amount&quot;: [100, 200, 300],
    }
)

print(df_orders)
#shape: (3, 3)
┌──────────┬─────────────┬────────┐
│ order_id ┆ customer_id ┆ amount │
│ ---      ┆ ---         ┆ ---    │
│ str      ┆ i64         ┆ i64    │
╞══════════╪═════════════╪════════╡
│ a        ┆ 1           ┆ 100    │
│ b        ┆ 2           ┆ 200    │
│ c        ┆ 2           ┆ 300    │
└──────────┴─────────────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Inner join&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;df_inner_customer_join = df_customers.join(df_orders, 
                                           on=&quot;customer_id&quot;, 
                                           how=&quot;inner&quot;)

print(df_inner_customer_join)
#shape: (3, 4)
┌─────────────┬───────┬──────────┬────────┐
│ customer_id ┆ name  ┆ order_id ┆ amount │
│ ---         ┆ ---   ┆ ---      ┆ ---    │
│ i64         ┆ str   ┆ str      ┆ i64    │
╞═════════════╪═══════╪══════════╪════════╡
│ 1           ┆ Alice ┆ a        ┆ 100    │
│ 2           ┆ Bob   ┆ b        ┆ 200    │
│ 2           ┆ Bob   ┆ c        ┆ 300    │
└─────────────┴───────┴──────────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Left join&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;df_left_join = df_customers.join(df_orders, 
                                 on=&quot;customer_id&quot;, 
                                 how=&quot;left&quot;)

print(df_left_join)
#shape: (4, 4)
┌─────────────┬─────────┬──────────┬────────┐
│ customer_id ┆ name    ┆ order_id ┆ amount │
│ ---         ┆ ---     ┆ ---      ┆ ---    │
│ i64         ┆ str     ┆ str      ┆ i64    │
╞═════════════╪═════════╪══════════╪════════╡
│ 1           ┆ Alice   ┆ a        ┆ 100    │
│ 2           ┆ Bob     ┆ b        ┆ 200    │
│ 2           ┆ Bob     ┆ c        ┆ 300    │
│ 3           ┆ Charlie ┆ null     ┆ null   │
└─────────────┴─────────┴──────────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Outer join&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;df_outer_join = df_customers.join(df_orders, 
                                  on=&quot;customer_id&quot;, 
                                  how=&quot;full&quot;)

print(df_outer_join)
#shape: (4, 5)
┌─────────────┬─────────┬──────────┬───────────────────┬────────┐
│ customer_id ┆ name    ┆ order_id ┆ customer_id_right ┆ amount │
│ ---         ┆ ---     ┆ ---      ┆ ---               ┆ ---    │
│ i64         ┆ str     ┆ str      ┆ i64               ┆ i64    │
╞═════════════╪═════════╪══════════╪═══════════════════╪════════╡
│ 1           ┆ Alice   ┆ a        ┆ 1                 ┆ 100    │
│ 2           ┆ Bob     ┆ b        ┆ 2                 ┆ 200    │
│ 2           ┆ Bob     ┆ c        ┆ 2                 ┆ 300    │
│ 3           ┆ Charlie ┆ null     ┆ null              ┆ null   │
└─────────────┴─────────┴──────────┴───────────────────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Cross join&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;df_colors = pl.DataFrame(
    {
        &quot;color&quot;: [&quot;red&quot;, &quot;blue&quot;, &quot;green&quot;],
    }
)
print(df_colors)
#shape: (3, 1)
┌───────┐
│ color │
│ ---   │
│ str   │
╞═══════╡
│ red   │
│ blue  │
│ green │
└───────┘

df_sizes = pl.DataFrame(
    {
        &quot;size&quot;: [&quot;S&quot;, &quot;M&quot;, &quot;L&quot;],
    }
)
#print(df_sizes)

df_cross_join = df_colors.join(df_sizes, 
                               how=&quot;cross&quot;)

print(df_cross_join)
#shape: (9, 2)
┌───────┬──────┐
│ color ┆ size │
│ ---   ┆ ---  │
│ str   ┆ str  │
╞═══════╪══════╡
│ red   ┆ S    │
│ red   ┆ M    │
│ red   ┆ L    │
│ blue  ┆ S    │
│ blue  ┆ M    │
│ blue  ┆ L    │
│ green ┆ S    │
│ green ┆ M    │
│ green ┆ L    │
└───────┴──────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Semi join&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;df_cars = pl.DataFrame(
    {
        &quot;id&quot;: [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;],
        &quot;make&quot;: [&quot;ford&quot;, &quot;toyota&quot;, &quot;bmw&quot;],
    }
)
print(df_cars)
shape: (3, 2)
┌─────┬────────┐
│ id  ┆ make   │
│ --- ┆ ---    │
│ str ┆ str    │
╞═════╪════════╡
│ a   ┆ ford   │
│ b   ┆ toyota │
│ c   ┆ bmw    │
└─────┴────────┘

df_repairs = pl.DataFrame(
    {
        &quot;id&quot;: [&quot;c&quot;, &quot;c&quot;],
        &quot;cost&quot;: [100, 200],
    }
)
print(df_repairs)
#shape: (2, 2)
┌─────┬──────┐
│ id  ┆ cost │
│ --- ┆ ---  │
│ str ┆ i64  │
╞═════╪══════╡
│ c   ┆ 100  │
│ c   ┆ 200  │
└─────┴──────┘

df_semi_join = df_cars.join(df_repairs, 
                            on=&quot;id&quot;, 
                            how=&quot;semi&quot;)
print(df_semi_join)
#shape: (1, 2)
┌─────┬──────┐
│ id  ┆ make │
│ --- ┆ ---  │
│ str ┆ str  │
╞═════╪══════╡
│ c   ┆ bmw  │
└─────┴──────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Anti join&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;df_anti_join = df_cars.join(df_repairs, 
                            on=&quot;id&quot;, 
                            how=&quot;anti&quot;)

print(df_anti_join)
#shape: (2, 2)
┌─────┬────────┐
│ id  ┆ make   │
│ --- ┆ ---    │
│ str ┆ str    │
╞═════╪════════╡
│ a   ┆ ford   │
│ b   ┆ toyota │
└─────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;数据框拼接 Concat&lt;/h1&gt;
&lt;p&gt;有以下3种方式的数据框拼接：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;纵向拼接/垂直拼接：2个数据框有相同的字段，拼接后产生更长的数据框&lt;/li&gt;
&lt;li&gt;横向拼接/水平拼接：2个数据框没有重叠的字段，拼接后产生更宽的数据框&lt;/li&gt;
&lt;li&gt;对角拼接：2个数据框有不同的行与列，既有重叠的字段，也有非重叠的字段，拼接后产生即长又宽的数据框&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;纵向拼接/垂直拼接 Vertical concatenation&lt;/h2&gt;
&lt;p&gt;当没有相同的列字段时，纵向拼接会失败&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df_v1 = pl.DataFrame(
    {
        &quot;a&quot;: [1],
        &quot;b&quot;: [3],
    }
)
df_v2 = pl.DataFrame(
    {
        &quot;a&quot;: [2],
        &quot;b&quot;: [4],
    }
)
df_vertical_concat = pl.concat(
    [
        df_v1,
        df_v2,
    ],
    how=&quot;vertical&quot;,
)
print(df_vertical_concat)
#shape: (2, 2)
┌─────┬─────┐
│ a   ┆ b   │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞═════╪═════╡
│ 1   ┆ 3   │
│ 2   ┆ 4   │
└─────┴─────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;横向拼接/水平拼接 Horizontal concatenation&lt;/h2&gt;
&lt;p&gt;当2个数据框有不同的行数时，拼接后短的行会用 &lt;code&gt;null&lt;/code&gt; 进行填充&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df_h1 = pl.DataFrame(
    {
        &quot;l1&quot;: [1, 2],
        &quot;l2&quot;: [3, 4],
    }
)
df_h2 = pl.DataFrame(
    {
        &quot;r1&quot;: [5, 6],
        &quot;r2&quot;: [7, 8],
        &quot;r3&quot;: [9, 10],
    }
)
df_horizontal_concat = pl.concat(
    [
        df_h1,
        df_h2,
    ],
    how=&quot;horizontal&quot;,
)
print(df_horizontal_concat)
#shape: (2, 5)
┌─────┬─────┬─────┬─────┬─────┐
│ l1  ┆ l2  ┆ r1  ┆ r2  ┆ r3  │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞═════╪═════╪═════╪═════╪═════╡
│ 1   ┆ 3   ┆ 5   ┆ 7   ┆ 9   │
│ 2   ┆ 4   ┆ 6   ┆ 8   ┆ 10  │
└─────┴─────┴─────┴─────┴─────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;对角拼接 Diagonal concatenation&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;df_d1 = pl.DataFrame(
    {
        &quot;a&quot;: [1],
        &quot;b&quot;: [3],
    }
)
df_d2 = pl.DataFrame(
    {
        &quot;a&quot;: [2],
        &quot;d&quot;: [4],
    }
)

df_diagonal_concat = pl.concat(
    [
        df_d1,
        df_d2,
    ],
    how=&quot;diagonal&quot;,
)
print(df_diagonal_concat)
#shape: (2, 3)
┌─────┬──────┬──────┐
│ a   ┆ b    ┆ d    │
│ --- ┆ ---  ┆ ---  │
│ i64 ┆ i64  ┆ i64  │
╞═════╪══════╪══════╡
│ 1   ┆ 3    ┆ null │
│ 2   ┆ null ┆ 4    │
└─────┴──────┴──────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6.md&quot;&gt;Python polars学习-01 读取与写入文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F.md&quot;&gt;Python polars学习-02 上下文与表达式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-03_%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2.md&quot;&gt;Python polars学习-03 数据类型转换&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-04_%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python polars学习-04 字符串数据处理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-05_%E5%8C%85%E5%90%AB%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.md&quot;&gt;Python polars学习-05 包含的数据结构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-06_Lazy-Eager-API.md&quot;&gt;Python polars学习-06 Lazy / Eager API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-07_%E7%BC%BA%E5%A4%B1%E5%80%BC.md&quot;&gt;Python polars学习-07 缺失值&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-08_%E5%88%86%E7%B1%BB%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python polars学习-08 分类数据处理&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-08_分类数据处理</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-08_%E5%88%86%E7%B1%BB%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-08_%E5%88%86%E7%B1%BB%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/</guid><description>Polars 分类数据处理</description><pubDate>Mon, 08 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;polars学习系列文章，第8篇 分类数据处理（Categorical data）&lt;/p&gt;
&lt;p&gt;该系列文章会分享到github，大家可以去下载jupyter文件，进行参考学习&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;小编运行环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.9

import polars as pl

print(&quot;polars 版本：&quot;,pl.__version__)
#polars 版本： 0.20.22
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;分类数据 Categorical data&lt;/h1&gt;
&lt;p&gt;分类数据就是平时在数据库中能进行编码的数据，比如：性别、年龄、国家、城市、职业 等等，可以对这些数据进行编码，可以节省存储空间&lt;/p&gt;
&lt;p&gt;Polars 支持两种不同的数据类型来处理分类数据：&lt;code&gt;Enum&lt;/code&gt; 和 &lt;code&gt;Categorical&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当类别预先已知时使用 &lt;code&gt;Enum&lt;/code&gt;，需要提前提供所有类别&lt;/li&gt;
&lt;li&gt;当不知道类别或类别不固定时，可以使用 &lt;code&gt;Categorical&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;enum_dtype = pl.Enum([&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;])
enum_series = pl.Series(
    [&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;, &quot;Brown&quot;, &quot;Polar&quot;], 
    dtype=enum_dtype)

cat_series = pl.Series(
    [&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;, &quot;Brown&quot;, &quot;Polar&quot;], 
    dtype=pl.Categorical
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Categorical 类型&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;Categorical&lt;/code&gt; 相对比较灵活，不用提前获取所有的类别，当有新类别时，会自动进行编码&lt;/p&gt;
&lt;p&gt;当对来自2个不同的 Categorical 类别列直接进行拼接时，以下这种方式会比较慢，polars 是根据字符串出现的先后顺序进行编码，不同的字符串在不同的序列里面编码可能不一样，直接合并的话全局会再进行一次编码，速度会比较慢：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat_series = pl.Series(
    [&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;, &quot;Brown&quot;, &quot;Polar&quot;], dtype=pl.Categorical
)
cat2_series = pl.Series(
    [&quot;Panda&quot;, &quot;Brown&quot;, &quot;Brown&quot;, &quot;Polar&quot;, &quot;Polar&quot;], dtype=pl.Categorical
)

#CategoricalRemappingWarning: Local categoricals have different encodings, 
#expensive re-encoding is done to perform this merge operation. 
#Consider using a StringCache or an Enum type if the categories are known in advance
print(cat_series.append(cat2_series))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以通过使用 polars 提供的全局字符缓存 &lt;code&gt;StringCache&lt;/code&gt;，来提升数据处理效率&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;with pl.StringCache():
    cat_series = pl.Series(
        [&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;, &quot;Brown&quot;, &quot;Polar&quot;], dtype=pl.Categorical
    )
    cat2_series = pl.Series(
        [&quot;Panda&quot;, &quot;Brown&quot;, &quot;Brown&quot;, &quot;Polar&quot;, &quot;Polar&quot;], dtype=pl.Categorical
    )
    print(cat_series.append(cat2_series))
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Enum&lt;/h1&gt;
&lt;p&gt;上面来自2个不同类型列进行拼接的耗时的情况，在&lt;code&gt;Enum&lt;/code&gt;中不会存在，因为已经提前获取到了全部的类别&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dtype = pl.Enum([&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;])
cat_series = pl.Series([&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;, &quot;Brown&quot;, &quot;Polar&quot;], dtype=dtype)
cat2_series = pl.Series([&quot;Panda&quot;, &quot;Brown&quot;, &quot;Brown&quot;, &quot;Polar&quot;, &quot;Polar&quot;], dtype=dtype)

print(cat_series.append(cat2_series))
#shape: (10,)
#Series: &apos;&apos; [enum]
[
	&quot;Polar&quot;
	&quot;Panda&quot;
	&quot;Brown&quot;
	&quot;Brown&quot;
	&quot;Polar&quot;
	&quot;Panda&quot;
	&quot;Brown&quot;
	&quot;Brown&quot;
	&quot;Polar&quot;
	&quot;Polar&quot;
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果有编码的字符串类别，当不在提前获取的&lt;code&gt;Enum&lt;/code&gt;中时，则会报错：&lt;code&gt;OutOfBounds&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dtype = pl.Enum([&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;])
try:
    cat_series = pl.Series([&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;, &quot;Black&quot;], dtype=dtype)
except Exception as e:
    print(e)
#conversion from `str` to `enum` failed 
#in column &apos;&apos; for 1 out of 4 values: [&quot;Black&quot;]
#Ensure that all values in the input column are present 
#in the categories of the enum datatype.
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;比较&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Categorical vs Categorical&lt;/li&gt;
&lt;li&gt;Categorical vs String&lt;/li&gt;
&lt;li&gt;Enum vs Enum&lt;/li&gt;
&lt;li&gt;Enum vs String(该字符串必须要在提前获取的Enum中)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Categorical vs Categorical&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;with pl.StringCache():
    cat_series = pl.Series([&quot;Brown&quot;, &quot;Panda&quot;, &quot;Polar&quot;], dtype=pl.Categorical)
    cat_series2 = pl.Series([&quot;Polar&quot;, &quot;Panda&quot;, &quot;Black&quot;], dtype=pl.Categorical)
    print(cat_series == cat_series2)
#shape: (3,)
#Series: &apos;&apos; [bool]
[
	false
	true
	false
]

&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Categorical vs String&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;cat_series = pl.Series([&quot;Brown&quot;, &quot;Panda&quot;, &quot;Polar&quot;], dtype=pl.Categorical)
print(cat_series &amp;lt;= &quot;Cat&quot;)
#shape: (3,)
#Series: &apos;&apos; [bool]
[
	true
	false
	false
]

cat_series = pl.Series([&quot;Brown&quot;, &quot;Panda&quot;, &quot;Polar&quot;], dtype=pl.Categorical)
cat_series_utf = pl.Series([&quot;Panda&quot;, &quot;Panda&quot;, &quot;A Polar&quot;])
print(cat_series &amp;lt;= cat_series_utf)
#shape: (3,)
#Series: &apos;&apos; [bool]
[
	true
	true
	false
]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Enum vs Enum&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;dtype = pl.Enum([&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;])
cat_series = pl.Series([&quot;Brown&quot;, &quot;Panda&quot;, &quot;Polar&quot;], dtype=dtype)
cat_series2 = pl.Series([&quot;Polar&quot;, &quot;Panda&quot;, &quot;Brown&quot;], dtype=dtype)
print(cat_series == cat_series2)
#shape: (3,)
#Series: &apos;&apos; [bool]
[
	false
	true
	false
]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Enum vs String(该字符串必须要在提前获取的Enum中)&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;try:
    cat_series = pl.Series(
        [&quot;Low&quot;, &quot;Medium&quot;, &quot;High&quot;], dtype=pl.Enum([&quot;Low&quot;, &quot;Medium&quot;, &quot;High&quot;])
    )
    cat_series &amp;lt;= &quot;Excellent&quot;
except Exception as e:
    print(e)
#conversion from `str` to `enum` failed 
#in column &apos;&apos; for 1 out of 1 values: [&quot;Excellent&quot;]
#Ensure that all values in the input column are present 
#in the categories of the enum datatype.

dtype = pl.Enum([&quot;Low&quot;, &quot;Medium&quot;, &quot;High&quot;])
cat_series = pl.Series([&quot;Low&quot;, &quot;Medium&quot;, &quot;High&quot;], dtype=dtype)
print(cat_series &amp;lt;= &quot;Medium&quot;)
#shape: (3,)
#Series: &apos;&apos; [bool]
[
	true
	true
	false
]

dtype = pl.Enum([&quot;Low&quot;, &quot;Medium&quot;, &quot;High&quot;])
cat_series = pl.Series([&quot;Low&quot;, &quot;Medium&quot;, &quot;High&quot;], dtype=dtype)
cat_series2 = pl.Series([&quot;High&quot;, &quot;High&quot;, &quot;Low&quot;])
print(cat_series &amp;lt;= cat_series2)
#shape: (3,)
#Series: &apos;&apos; [bool]
[
	true
	true
	false
]
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6.md&quot;&gt;Python polars学习-01 读取与写入文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F.md&quot;&gt;Python polars学习-02 上下文与表达式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-03_%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2.md&quot;&gt;Python polars学习-03 数据类型转换&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-04_%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python polars学习-04 字符串数据处理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-05_%E5%8C%85%E5%90%AB%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.md&quot;&gt;Python polars学习-05 包含的数据结构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-06_Lazy-Eager-API.md&quot;&gt;Python polars学习-06 Lazy / Eager API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-07_%E7%BC%BA%E5%A4%B1%E5%80%BC.md&quot;&gt;Python polars学习-07 缺失值&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-07_缺失值</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-07_%E7%BC%BA%E5%A4%B1%E5%80%BC/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-07_%E7%BC%BA%E5%A4%B1%E5%80%BC/</guid><description>Polars 缺失值处理</description><pubDate>Tue, 25 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;polars学习系列文章，第7篇 缺失值&lt;/p&gt;
&lt;p&gt;该系列文章会分享到github，大家可以去下载jupyter文件，进行参考学习&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;小编运行环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.9

import polars as pl

print(&quot;polars 版本：&quot;,pl.__version__)
#polars 版本： 0.20.22
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;polars 中缺失值的定义&lt;/h1&gt;
&lt;p&gt;在 polars 中缺失值用 &lt;code&gt;null&lt;/code&gt; 来表示，只有这1种表示方式，这个与 pandas 不同，在 pandas 中 &lt;code&gt;NaN&lt;/code&gt;（NotaNumber）也代表是缺失值，但在polars中把 &lt;code&gt;NaN&lt;/code&gt; 归属为一种浮点数据&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df = pl.DataFrame(
    {
        &quot;value&quot;: [1,2,3, None,5,6,None,8,9],
    },
)
print(df)
#shape: (9, 1)
┌───────┐
│ value │
│ ---   │
│ i64   │
╞═══════╡
│ 1     │
│ 2     │
│ 3     │
│ null  │
│ 5     │
│ 6     │
│ null  │
│ 8     │
│ 9     │
└───────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;polars中缺失值包括的2种元信息&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;缺失值数量，可以通过 &lt;code&gt;null_count&lt;/code&gt; 方法来快速获取，因为已经是计算好的，所以调用该方法会立即返回结果&lt;/li&gt;
&lt;li&gt;有效位图（validity bitmap），代表是否是缺失值，在内存中用 0 或 1 进行编码来表示，所占的内存空间非常小，通常占用空间为（数据框长度 / 8) bytes，通过 &lt;code&gt;is_null&lt;/code&gt; 方法来查看数据是否是缺失值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;null_count_df = df.null_count()
print(null_count_df)
#shape: (1, 1)
┌───────┐
│ value │
│ ---   │
│ u32   │
╞═══════╡
│ 2     │
└───────┘


is_null_series = df.select(
    pl.col(&quot;value&quot;).is_null(),
)
print(is_null_series)
#shape: (9, 1)
┌───────┐
│ value │
│ ---   │
│ bool  │
╞═══════╡
│ false │
│ false │
│ false │
│ true  │
│ false │
│ false │
│ true  │
│ false │
│ false │
└───────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;缺失值填充&lt;/h1&gt;
&lt;p&gt;缺失值填充主要通过 &lt;code&gt;fill_null&lt;/code&gt;方法来处理，但是需求指定填充缺失值的方法&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;常量，比如用 0 来填充&lt;/li&gt;
&lt;li&gt;填充策略，例如：向前、向后 等&lt;/li&gt;
&lt;li&gt;通过表达式，比如利用其他列来填充&lt;/li&gt;
&lt;li&gt;插值法&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;df = pl.DataFrame(
    {
        &quot;col1&quot;: [1, 2, 3],
        &quot;col2&quot;: [1, None, 3],
    },
)
print(df)
#shape: (3, 2)
┌──────┬──────┐
│ col1 ┆ col2 │
│ ---  ┆ ---  │
│ i64  ┆ i64  │
╞══════╪══════╡
│ 1    ┆ 1    │
│ 2    ┆ null │
│ 3    ┆ 3    │
└──────┴──────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常量填充&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;fill_literal_df = df.with_columns(
    fill=pl.col(&quot;col2&quot;).fill_null(pl.lit(2)),
)
print(fill_literal_df)
#shape: (3, 3)
┌──────┬──────┬──────┐
│ col1 ┆ col2 ┆ fill │
│ ---  ┆ ---  ┆ ---  │
│ i64  ┆ i64  ┆ i64  │
╞══════╪══════╪══════╡
│ 1    ┆ 1    ┆ 1    │
│ 2    ┆ null ┆ 2    │
│ 3    ┆ 3    ┆ 3    │
└──────┴──────┴──────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;填充策略&lt;/h2&gt;
&lt;p&gt;填充策略：{&apos;forward&apos;, &apos;backward&apos;, &apos;min&apos;, &apos;max&apos;, &apos;mean&apos;, &apos;zero&apos;, &apos;one&apos;}&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fill_df = df.with_columns(
    forward=pl.col(&quot;col2&quot;).fill_null(strategy=&quot;forward&quot;),
    backward=pl.col(&quot;col2&quot;).fill_null(strategy=&quot;backward&quot;),
)
print(fill_df)
#shape: (3, 4)
┌──────┬──────┬─────────┬──────────┐
│ col1 ┆ col2 ┆ forward ┆ backward │
│ ---  ┆ ---  ┆ ---     ┆ ---      │
│ i64  ┆ i64  ┆ i64     ┆ i64      │
╞══════╪══════╪═════════╪══════════╡
│ 1    ┆ 1    ┆ 1       ┆ 1        │
│ 2    ┆ null ┆ 1       ┆ 3        │
│ 3    ┆ 3    ┆ 3       ┆ 3        │
└──────┴──────┴─────────┴──────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;通过表达式&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;fill_median_df = df.with_columns(
    fill=pl.col(&quot;col2&quot;).fill_null(pl.median(&quot;col2&quot;)), #类型会转换为浮点型
)
print(fill_median_df)
#shape: (3, 3)
┌──────┬──────┬──────┐
│ col1 ┆ col2 ┆ fill │
│ ---  ┆ ---  ┆ ---  │
│ i64  ┆ i64  ┆ f64  │
╞══════╪══════╪══════╡
│ 1    ┆ 1    ┆ 1.0  │
│ 2    ┆ null ┆ 2.0  │
│ 3    ┆ 3    ┆ 3.0  │
└──────┴──────┴──────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;通过插值法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;fill_interpolation_df = df.with_columns(
    fill=pl.col(&quot;col2&quot;).interpolate(),  
)
print(fill_interpolation_df)
#shape: (3, 3)
┌──────┬──────┬──────┐
│ col1 ┆ col2 ┆ fill │
│ ---  ┆ ---  ┆ ---  │
│ i64  ┆ i64  ┆ f64  │
╞══════╪══════╪══════╡
│ 1    ┆ 1    ┆ 1.0  │
│ 2    ┆ null ┆ 2.0  │
│ 3    ┆ 3    ┆ 3.0  │
└──────┴──────┴──────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6.md&quot;&gt;Python polars学习-01 读取与写入文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F.md&quot;&gt;Python polars学习-02 上下文与表达式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-03_%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2.md&quot;&gt;Python polars学习-03 数据类型转换&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-04_%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python polars学习-04 字符串数据处理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-05_%E5%8C%85%E5%90%AB%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.md&quot;&gt;Python polars学习-05 包含的数据结构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-06_Lazy-Eager-API.md&quot;&gt;Python polars学习-06 Lazy / Eager API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-06_Lazy-Eager-API</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-06_Lazy-Eager-API/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-06_Lazy-Eager-API/</guid><description>Polars Lazy（延迟、惰性）、Eager（即时、实时）计算引擎</description><pubDate>Thu, 20 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;polars学习系列文章，第6篇 Lazy / Eager API &amp;lt;br/&amp;gt;
&lt;strong&gt;Lazy：&lt;/strong&gt; 延迟、惰性&amp;lt;br/&amp;gt;
&lt;strong&gt;Eager：&lt;/strong&gt; 即时、实时&lt;/p&gt;
&lt;p&gt;该系列文章会分享到github，大家可以去下载jupyter文件，进行参考学习&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;小编运行环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.9

import polars as pl

print(&quot;polars 版本：&quot;,pl.__version__)
#polars 版本： 0.20.22
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Lazy / Eager API 区别&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Eager API（即时、实时）&lt;/strong&gt;
实时进行计算，每一步操作都会进行计算，类似pandas那样，每操作一步都会进行计算，得到这一步的结果，所见即所得，如果没有明确指定或者调用特定的方法之外，polars 基本都是使用该模式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lazy API（延迟、惰性）&lt;/strong&gt;
推迟进行计算，把所有的操作步骤先记下来，Query plan（查询计划），等到需要结果时，才统一进行计算，polars 会对这些计算步骤自动进行优化，提升性能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pl.scan_csv&lt;/code&gt; 等 &lt;code&gt;pl.scan_&lt;/code&gt; 函数&lt;/li&gt;
&lt;li&gt;调用DataFrame 的 &lt;code&gt;.lazy&lt;/code&gt; 方法，转换为 Lazy 模式&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Eager API 数据处理案例&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;df = pl.read_csv(&quot;./data/iris.csv&quot;)
df_small = df.filter(pl.col(&quot;Sepal.Length&quot;) &amp;gt; 5)
df_agg = df_small.group_by(&quot;Species&quot;).agg(pl.col(&quot;Sepal.Width&quot;).mean())
print(df_agg)

#shape: (3, 2)
┌────────────┬─────────────┐
│ Species    ┆ Sepal.Width │
│ ---        ┆ ---         │
│ str        ┆ f64         │
╞════════════╪═════════════╡
│ versicolor ┆ 2.804255    │
│ virginica  ┆ 2.983673    │
│ setosa     ┆ 3.713636    │
└────────────┴─────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Lazy API 数据处理案例&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;q = (
    pl.scan_csv(&quot;./data/iris.csv&quot;)
    .filter(pl.col(&quot;Sepal.Length&quot;) &amp;gt; 5)
    .group_by(&quot;Species&quot;)
    .agg(pl.col(&quot;Sepal.Width&quot;).mean())
)

df = q.collect()
print(df)

#shape: (3, 2)
┌────────────┬─────────────┐
│ Species    ┆ Sepal.Width │
│ ---        ┆ ---         │
│ str        ┆ f64         │
╞════════════╪═════════════╡
│ virginica  ┆ 2.983673    │
│ versicolor ┆ 2.804255    │
│ setosa     ┆ 3.713636    │
└────────────┴─────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在数据处理中会对&lt;code&gt;Sepal.Length&lt;/code&gt;进行过滤，polars 在把数据加载进内存时，只会加载符合条件的数据行，同时计算时只用到了 &lt;code&gt;Species&lt;/code&gt;、&lt;code&gt;Sepal.Width&lt;/code&gt; 2列，polars 只会加载这2 列到内存，进行计算&lt;/p&gt;
&lt;p&gt;这样的话会显著降低内存和CPU的负载，从而能够在内存中容纳更大的数据集并加快处理速度&lt;/p&gt;
&lt;h1&gt;使用建议&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;如果你是在进行探索性分析，想知道中间的每个步骤数据情况，那么可以使用 Eager 模式&lt;/li&gt;
&lt;li&gt;如果想得到最终的计算结果，那么可以使用 Lazy 模式，让polars对中间的计算进行优化，提升数据处理效率&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;注：在大部分情况下，Eager API 背后其实调用的是 Lazy API，Eager 模式其实也是有查询优化&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6.md&quot;&gt;Python polars学习-01 读取与写入文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F.md&quot;&gt;Python polars学习-02 上下文与表达式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-03_%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2.md&quot;&gt;Python polars学习-03 数据类型转换&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-04_%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python polars学习-04 字符串数据处理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-05_%E5%8C%85%E5%90%AB%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.md&quot;&gt;Python polars学习-05 包含的数据结构&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-05_包含的数据结构</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-05_%E5%8C%85%E5%90%AB%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-05_%E5%8C%85%E5%90%AB%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</guid><description>Polars 包含的数据结构是：Series、DataFrame</description><pubDate>Fri, 14 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;polars学习系列文章，第5篇 包含的数据结构，与 &lt;code&gt;pandas&lt;/code&gt; 一样，&lt;code&gt;polars&lt;/code&gt; 包含的数据结构是：&lt;code&gt;Series&lt;/code&gt;、&lt;code&gt;DataFrame&lt;/code&gt;，大部分操作与&lt;code&gt;pandas&lt;/code&gt; 保持一致，减少了大家的学习难度&lt;/p&gt;
&lt;p&gt;该系列文章会分享到github，大家可以去下载jupyter文件，进行参考学习&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;小编运行环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.9

import polars as pl

print(&quot;polars 版本：&quot;,pl.__version__)
#polars 版本： 0.20.22
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Series 数据列&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;Series&lt;/code&gt; 是一维的数据结构，其有相同的数据类型，可以理解为数据库中的一列&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import polars as pl

s = pl.Series(&quot;a&quot;, [1, 2, 3, 4, 5])
print(s)

shape: (5,)
Series: &apos;a&apos; [i64]
[
	1
	2
	3
	4
	5
]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;数据列的操作&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;print(s.min())  #1
print(s.max())  #5
print(s.mean())  #3.0
print(s.count())   #5
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;DataFrame 数据框&lt;/h1&gt;
&lt;p&gt;DataFrame 是一个二维的数据结构，其是由一系列的 Series 组成，可以理解为一张数据表，包含很多列&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from datetime import datetime

df = pl.DataFrame(
    {
        &quot;integer&quot;: [1, 2, 3, 4, 5],
        &quot;date&quot;: [
            datetime(2022, 1, 1),
            datetime(2022, 1, 2),
            datetime(2022, 1, 3),
            datetime(2022, 1, 4),
            datetime(2022, 1, 5),
        ],
        &quot;float&quot;: [4.0, 5.0, 6.0, 7.0, 8.0],
    }
)

print(df)

shape: (5, 3)
┌─────────┬─────────────────────┬───────┐
│ integer ┆ date                ┆ float │
│ ---     ┆ ---                 ┆ ---   │
│ i64     ┆ datetime[μs]        ┆ f64   │
╞═════════╪═════════════════════╪═══════╡
│ 1       ┆ 2022-01-01 00:00:00 ┆ 4.0   │
│ 2       ┆ 2022-01-02 00:00:00 ┆ 5.0   │
│ 3       ┆ 2022-01-03 00:00:00 ┆ 6.0   │
│ 4       ┆ 2022-01-04 00:00:00 ┆ 7.0   │
│ 5       ┆ 2022-01-05 00:00:00 ┆ 8.0   │
└─────────┴─────────────────────┴───────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Head&lt;/h2&gt;
&lt;p&gt;默认展示前5行数据，也可以传出要展示的行数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;print(df.head())
#shape: (5, 3)
┌─────────┬─────────────────────┬───────┐
│ integer ┆ date                ┆ float │
│ ---     ┆ ---                 ┆ ---   │
│ i64     ┆ datetime[μs]        ┆ f64   │
╞═════════╪═════════════════════╪═══════╡
│ 1       ┆ 2022-01-01 00:00:00 ┆ 4.0   │
│ 2       ┆ 2022-01-02 00:00:00 ┆ 5.0   │
│ 3       ┆ 2022-01-03 00:00:00 ┆ 6.0   │
│ 4       ┆ 2022-01-04 00:00:00 ┆ 7.0   │
│ 5       ┆ 2022-01-05 00:00:00 ┆ 8.0   │
└─────────┴─────────────────────┴───────┘

print(df.head(3))
#shape: (3, 3)
┌─────────┬─────────────────────┬───────┐
│ integer ┆ date                ┆ float │
│ ---     ┆ ---                 ┆ ---   │
│ i64     ┆ datetime[μs]        ┆ f64   │
╞═════════╪═════════════════════╪═══════╡
│ 1       ┆ 2022-01-01 00:00:00 ┆ 4.0   │
│ 2       ┆ 2022-01-02 00:00:00 ┆ 5.0   │
│ 3       ┆ 2022-01-03 00:00:00 ┆ 6.0   │
└─────────┴─────────────────────┴───────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Tail&lt;/h2&gt;
&lt;p&gt;默认展示最后5行数据，也可以传出要展示的行数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;print(df.tail())
#shape: (5, 3)
┌─────────┬─────────────────────┬───────┐
│ integer ┆ date                ┆ float │
│ ---     ┆ ---                 ┆ ---   │
│ i64     ┆ datetime[μs]        ┆ f64   │
╞═════════╪═════════════════════╪═══════╡
│ 1       ┆ 2022-01-01 00:00:00 ┆ 4.0   │
│ 2       ┆ 2022-01-02 00:00:00 ┆ 5.0   │
│ 3       ┆ 2022-01-03 00:00:00 ┆ 6.0   │
│ 4       ┆ 2022-01-04 00:00:00 ┆ 7.0   │
│ 5       ┆ 2022-01-05 00:00:00 ┆ 8.0   │
└─────────┴─────────────────────┴───────┘

print(df.tail(3))
#shape: (3, 3)
┌─────────┬─────────────────────┬───────┐
│ integer ┆ date                ┆ float │
│ ---     ┆ ---                 ┆ ---   │
│ i64     ┆ datetime[μs]        ┆ f64   │
╞═════════╪═════════════════════╪═══════╡
│ 3       ┆ 2022-01-03 00:00:00 ┆ 6.0   │
│ 4       ┆ 2022-01-04 00:00:00 ┆ 7.0   │
│ 5       ┆ 2022-01-05 00:00:00 ┆ 8.0   │
└─────────┴─────────────────────┴───────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Sample 随机抽样&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;print(df.sample(3))
#shape: (3, 3)
┌─────────┬─────────────────────┬───────┐
│ integer ┆ date                ┆ float │
│ ---     ┆ ---                 ┆ ---   │
│ i64     ┆ datetime[μs]        ┆ f64   │
╞═════════╪═════════════════════╪═══════╡
│ 5       ┆ 2022-01-05 00:00:00 ┆ 8.0   │
│ 3       ┆ 2022-01-03 00:00:00 ┆ 6.0   │
│ 1       ┆ 2022-01-01 00:00:00 ┆ 4.0   │
└─────────┴─────────────────────┴───────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Describe 数据概况&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;print(df.describe())
#shape: (9, 4)
┌────────────┬──────────┬─────────────────────┬──────────┐
│ statistic  ┆ integer  ┆ date                ┆ float    │
│ ---        ┆ ---      ┆ ---                 ┆ ---      │
│ str        ┆ f64      ┆ str                 ┆ f64      │
╞════════════╪══════════╪═════════════════════╪══════════╡
│ count      ┆ 5.0      ┆ 5                   ┆ 5.0      │
│ null_count ┆ 0.0      ┆ 0                   ┆ 0.0      │
│ mean       ┆ 3.0      ┆ 2022-01-03 00:00:00 ┆ 6.0      │
│ std        ┆ 1.581139 ┆ null                ┆ 1.581139 │
│ min        ┆ 1.0      ┆ 2022-01-01 00:00:00 ┆ 4.0      │
│ 25%        ┆ 2.0      ┆ 2022-01-02 00:00:00 ┆ 5.0      │
│ 50%        ┆ 3.0      ┆ 2022-01-03 00:00:00 ┆ 6.0      │
│ 75%        ┆ 4.0      ┆ 2022-01-04 00:00:00 ┆ 7.0      │
│ max        ┆ 5.0      ┆ 2022-01-05 00:00:00 ┆ 8.0      │
└────────────┴──────────┴─────────────────────┴──────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6.md&quot;&gt;Python polars学习-01 读取与写入文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F.md&quot;&gt;Python polars学习-02 上下文与表达式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-03_%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2.md&quot;&gt;Python polars学习-03 数据类型转换&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-04_%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python polars学习-04 字符串数据处理&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-04_字符串数据处理</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-04_%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-04_%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/</guid><description>Polars 字符串数据处理</description><pubDate>Thu, 23 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;polars学习系列文章，第4篇 字符串数据处理 &amp;lt;br/&amp;gt;
该系列文章会分享到github，大家可以去下载jupyter文件，进行参考学习&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;小编运行环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.9

import polars as pl

print(&quot;polars 版本：&quot;,pl.__version__)
#polars 版本： 0.20.22
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;字符串长度&lt;/h1&gt;
&lt;p&gt;可以获取字符串中的字符数或者字节数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df = pl.DataFrame({&quot;animal&quot;: [&quot;Crab&quot;, &quot;cat and dog&quot;, &quot;rab$bit&quot;, &apos;张&apos;,None]})

out = df.select(
    pl.col(&quot;animal&quot;).str.len_bytes().alias(&quot;byte_count&quot;),  #字节数
    pl.col(&quot;animal&quot;).str.len_chars().alias(&quot;letter_count&quot;),  #字符串数
)
print(out)

shape: (5, 2)
┌────────────┬──────────────┐
│ byte_count ┆ letter_count │
│ ---        ┆ ---          │
│ u32        ┆ u32          │
╞════════════╪══════════════╡
│ 4          ┆ 4            │
│ 11         ┆ 11           │
│ 7          ┆ 7            │
│ 3          ┆ 1            │
│ null       ┆ null         │
└────────────┴──────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;判断是否包含特定字符串或正则字符串&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;contains：包含指定的字符串，或正则表达式字符串，返回ture/false&lt;/li&gt;
&lt;li&gt;starts_with：判断是否以指定的字符串开头，返回ture/false&lt;/li&gt;
&lt;li&gt;ends_with：判断是否以指定的字符串结尾，返回ture/false&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果包含了特殊的字符，但又不是正则表达式，需要设置参数&lt;code&gt;literal=True&lt;/code&gt;,&lt;code&gt;literal&lt;/code&gt;默认是 &lt;code&gt;False&lt;/code&gt;,代表字符是正则表达式字符串&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;out = df.select(
    pl.col(&quot;animal&quot;),
    pl.col(&quot;animal&quot;).str.contains(&quot;cat|bit&quot;).alias(&quot;regex&quot;),
    pl.col(&quot;animal&quot;).str.contains(&quot;rab$&quot;, literal=True).alias(&quot;literal&quot;),  #匹配$原始字符
    pl.col(&quot;animal&quot;).str.contains(&quot;rab$&quot;).alias(&quot;regex_pattern&quot;),
    pl.col(&quot;animal&quot;).str.starts_with(&quot;rab&quot;).alias(&quot;starts_with&quot;),
    pl.col(&quot;animal&quot;).str.ends_with(&quot;dog&quot;).alias(&quot;ends_with&quot;),
)
print(out)

shape: (5, 6)
┌─────────────┬───────┬─────────┬───────────────┬─────────────┬───────────┐
│ animal      ┆ regex ┆ literal ┆ regex_pattern ┆ starts_with ┆ ends_with │
│ ---         ┆ ---   ┆ ---     ┆ ---           ┆ ---         ┆ ---       │
│ str         ┆ bool  ┆ bool    ┆ bool          ┆ bool        ┆ bool      │
╞═════════════╪═══════╪═════════╪═══════════════╪═════════════╪═══════════╡
│ Crab        ┆ false ┆ false   ┆ true          ┆ false       ┆ false     │
│ cat and dog ┆ true  ┆ false   ┆ false         ┆ false       ┆ true      │
│ rab$bit     ┆ true  ┆ true    ┆ false         ┆ true        ┆ false     │
│ 张          ┆ false ┆ false   ┆ false         ┆ false       ┆ false     │
│ null        ┆ null  ┆ null    ┆ null          ┆ null        ┆ null      │
└─────────────┴───────┴─────────┴───────────────┴─────────────┴───────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正则表达式的各种标识，需要写到字符串开始，用括号括起来，&lt;code&gt;(?iLmsuxU)&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;out=pl.DataFrame({&quot;s&quot;: [&quot;AAA&quot;, &quot;aAa&quot;, &quot;aaa&quot;]}).with_columns(
    default_match=pl.col(&quot;s&quot;).str.contains(&quot;AA&quot;),
    insensitive_match=pl.col(&quot;s&quot;).str.contains(&quot;(?i)AA&quot;)  #忽略大小写
)

print(out)

shape: (3, 3)
┌─────┬───────────────┬───────────────────┐
│ s   ┆ default_match ┆ insensitive_match │
│ --- ┆ ---           ┆ ---               │
│ str ┆ bool          ┆ bool              │
╞═════╪═══════════════╪═══════════════════╡
│ AAA ┆ true          ┆ true              │
│ aAa ┆ false         ┆ true              │
│ aaa ┆ false         ┆ true              │
└─────┴───────────────┴───────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;根据正则表达式提取特定字符&lt;/h1&gt;
&lt;p&gt;使用&lt;code&gt;extract&lt;/code&gt;方法，根据提供的正则表达式模式，进行提取匹配到的字符串,需要提供想要获取的组索引 &lt;code&gt;group_index&lt;/code&gt;，默认是第1个&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df = pl.DataFrame(
    {
        &quot;a&quot;: [
            &quot;http://vote.com/ballon_dor?candidate=messi&amp;amp;ref=polars&quot;,
            &quot;http://vote.com/ballon_dor?candidat=jorginho&amp;amp;ref=polars&quot;,
            &quot;http://vote.com/ballon_dor?candidate=ronaldo&amp;amp;ref=polars&quot;,
        ]
    }
)
out = df.select(
    a1=pl.col(&quot;a&quot;).str.extract(r&quot;candidate=(\w+)&quot;, group_index=1),
    a2=pl.col(&quot;a&quot;).str.extract(r&quot;candidate=(\w+)&quot;, group_index=0),
    a3=pl.col(&quot;a&quot;).str.extract(r&quot;candidate=(\w+)&quot;)  #默认获取第1个
)
print(out)

shape: (3, 3)
┌─────────┬───────────────────┬─────────┐
│ a1      ┆ a2                ┆ a3      │
│ ---     ┆ ---               ┆ ---     │
│ str     ┆ str               ┆ str     │
╞═════════╪═══════════════════╪═════════╡
│ messi   ┆ candidate=messi   ┆ messi   │
│ null    ┆ null              ┆ null    │
│ ronaldo ┆ candidate=ronaldo ┆ ronaldo │
└─────────┴───────────────────┴─────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果想获取所有正则表达式匹配到的字符串，需要使用 &lt;code&gt;extract_all&lt;/code&gt; 方法，结果是一个列表&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df = pl.DataFrame({&quot;foo&quot;: [&quot;123 bla 45 asd&quot;, &quot;xyz 678 910t&quot;]})
out = df.select(
    pl.col(&quot;foo&quot;).str.extract_all(r&quot;(\d+)&quot;).alias(&quot;extracted_nrs&quot;),
)
print(out)

shape: (2, 1)
┌────────────────┐
│ extracted_nrs  │
│ ---            │
│ list[str]      │
╞════════════════╡
│ [&quot;123&quot;, &quot;45&quot;]  │
│ [&quot;678&quot;, &quot;910&quot;] │
└────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;字符串替换&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;replace：替换第一次匹配到的字符串，为新的字符串&lt;/li&gt;
&lt;li&gt;replace_all：替换所有匹配到的字符串，为新的字符串&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;df = pl.DataFrame({&quot;id&quot;: [1, 2], &quot;text&quot;: [&quot;abc123abc&quot;, &quot;abc456&quot;]})
out = df.with_columns(
    s1=pl.col(&quot;text&quot;).str.replace(r&quot;abc\b&quot;, &quot;ABC&quot;), #\b 字符串结束位置，以 abc 出现在字符串结尾处
    s2=pl.col(&quot;text&quot;).str.replace(&quot;a&quot;, &quot;-&quot;), #只替换第一次出现的 a
    s3=pl.col(&quot;text&quot;).str.replace_all(&quot;a&quot;, &quot;-&quot;, literal=True) #替换所有的 a
)
print(out)

shape: (2, 5)
┌─────┬───────────┬───────────┬───────────┬───────────┐
│ id  ┆ text      ┆ s1        ┆ s2        ┆ s3        │
│ --- ┆ ---       ┆ ---       ┆ ---       ┆ ---       │
│ i64 ┆ str       ┆ str       ┆ str       ┆ str       │
╞═════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ 1   ┆ abc123abc ┆ abc123ABC ┆ -bc123abc ┆ -bc123-bc │
│ 2   ┆ abc456    ┆ abc456    ┆ -bc456    ┆ -bc456    │
└─────┴───────────┴───────────┴───────────┴───────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6.md&quot;&gt;Python polars学习-01 读取与写入文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F.md&quot;&gt;Python polars学习-02 上下文与表达式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-03_%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2.md&quot;&gt;Python polars学习-03 数据类型转换&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-03_数据类型转换</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-03_%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-03_%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2/</guid><description>Polars 数据类型转换</description><pubDate>Mon, 13 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;polars学习系列文章，第3篇 数据类型转换 &amp;lt;br/&amp;gt;
该系列文章会分享到github，大家可以去下载jupyter文件&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;小编运行环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.5 

import polars as pl

print(&quot;polars 版本：&quot;,pl.__version__)
#polars 版本： 0.20.22
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;数据类型转换&lt;/h1&gt;
&lt;p&gt;数据类型转换，主要是通过 &lt;code&gt;cast&lt;/code&gt; 方法来进行操作，该方法中有个参数 &lt;code&gt;strict&lt;/code&gt; ，该参数决定当原数据类型不能转换为目标数据类型时，应该如何处理&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;严格模式， &lt;code&gt;strict=True&lt;/code&gt;(该参数默认是True)，就会进行报错，打印出详细的错误信息&lt;/li&gt;
&lt;li&gt;非严格模式， &lt;code&gt;strict=False&lt;/code&gt; ,不会报错，无法转换为目标数据类型的值都会被置为 &lt;code&gt;null&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;code&gt;pandas&lt;/code&gt; 中数据类型转换使用的是 &lt;code&gt;astype&lt;/code&gt; 方法&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;示例&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;数值类型  Numerics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;浮点型数值转换为整型时，会向下取整；大范围的数据类型转换为小范围数据类型时，如果数值溢出时，默认会报错，如果设置了 &lt;code&gt;strict=False&lt;/code&gt;，则会被置为 &lt;code&gt;null&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df = pl.DataFrame(
    {
        &quot;integers&quot;: [1, 2, 3, 4, 5],
        &quot;big_integers&quot;: [1, 10000002, 3, 10000004, 10000005],
        &quot;floats&quot;: [4.0, 5.0, 6.0, 7.0, 8.0],
        &quot;floats_with_decimal&quot;: [4.532, 5.5, 6.5, 7.5, 8.5],
    }
)

print(df)
shape: (5, 4)
┌──────────┬──────────────┬────────┬─────────────────────┐
│ integers ┆ big_integers ┆ floats ┆ floats_with_decimal │
│ ---      ┆ ---          ┆ ---    ┆ ---                 │
│ i64      ┆ i64          ┆ f64    ┆ f64                 │
╞══════════╪══════════════╪════════╪═════════════════════╡
│ 1        ┆ 1            ┆ 4.0    ┆ 4.532               │
│ 2        ┆ 10000002     ┆ 5.0    ┆ 5.5                 │
│ 3        ┆ 3            ┆ 6.0    ┆ 6.5                 │
│ 4        ┆ 10000004     ┆ 7.0    ┆ 7.5                 │
│ 5        ┆ 10000005     ┆ 8.0    ┆ 8.5                 │
└──────────┴──────────────┴────────┴─────────────────────┘

out=df.select(
        pl.col(&quot;integers&quot;).cast(pl.Float32).alias(&quot;integers_as_floats&quot;),
        pl.col(&quot;floats&quot;).cast(pl.Int32).alias(&quot;floats_as_integers&quot;),
        pl.col(&quot;floats_with_decimal&quot;).cast(pl.Int32).alias(&quot;floats_with_decimal_as_integers&quot;)
    )

print(out)
shape: (5, 3)
┌────────────────────┬────────────────────┬─────────────────────────────────┐
│ integers_as_floats ┆ floats_as_integers ┆ floats_with_decimal_as_integers │
│ ---                ┆ ---                ┆ ---                             │
│ f32                ┆ i32                ┆ i32                             │
╞════════════════════╪════════════════════╪═════════════════════════════════╡
│ 1.0                ┆ 4                  ┆ 4                               │
│ 2.0                ┆ 5                  ┆ 5                               │
│ 3.0                ┆ 6                  ┆ 6                               │
│ 4.0                ┆ 7                  ┆ 7                               │
│ 5.0                ┆ 8                  ┆ 8                               │
└────────────────────┴────────────────────┴─────────────────────────────────┘

#如果不溢出的类型转换，可以节省内存
out=df.select(
        pl.col(&quot;integers&quot;).cast(pl.Int16).alias(&quot;integers_smallfootprint&quot;),
        pl.col(&quot;floats&quot;).cast(pl.Float32).alias(&quot;floats_smallfootprint&quot;),
    )

print(out)
shape: (5, 2)
┌─────────────────────────┬───────────────────────┐
│ integers_smallfootprint ┆ floats_smallfootprint │
│ ---                     ┆ ---                   │
│ i16                     ┆ f32                   │
╞═════════════════════════╪═══════════════════════╡
│ 1                       ┆ 4.0                   │
│ 2                       ┆ 5.0                   │
│ 3                       ┆ 6.0                   │
│ 4                       ┆ 7.0                   │
│ 5                       ┆ 8.0                   │
└─────────────────────────┴───────────────────────┘

try:
    out = df.select(pl.col(&quot;big_integers&quot;).cast(pl.Int8))
    print(out)
except Exception as e:
    print(e)
#conversion from `i64` to `i8` failed in column &apos;big_integers&apos; for 3 out of 5 values: [10000002, 10000004, 10000005]

out=df.select(pl.col(&quot;big_integers&quot;).cast(pl.Int8, strict=False))
print(out)
shape: (5, 1)
┌──────────────┐
│ big_integers │
│ ---          │
│ i8           │
╞══════════════╡
│ 1            │
│ null         │
│ 3            │
│ null         │
│ null         │
└──────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;字符串类型  Strings&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df = pl.DataFrame(
    {
        &quot;integers&quot;: [1, 2, 3, 4, 5],
        &quot;float&quot;: [4.0, 5.03, 6.0, 7.0, 8.0],
        &quot;floats_as_string&quot;: [&quot;4.0&quot;, &quot;5.0&quot;, &quot;6.0&quot;, &quot;7.0&quot;, &quot;8.0&quot;],
    }
)

print(df)
shape: (5, 3)
┌──────────┬───────┬──────────────────┐
│ integers ┆ float ┆ floats_as_string │
│ ---      ┆ ---   ┆ ---              │
│ i64      ┆ f64   ┆ str              │
╞══════════╪═══════╪══════════════════╡
│ 1        ┆ 4.0   ┆ 4.0              │
│ 2        ┆ 5.03  ┆ 5.0              │
│ 3        ┆ 6.0   ┆ 6.0              │
│ 4        ┆ 7.0   ┆ 7.0              │
│ 5        ┆ 8.0   ┆ 8.0              │
└──────────┴───────┴──────────────────┘

out=df.select(
        pl.col(&quot;integers&quot;).cast(pl.String),
        pl.col(&quot;float&quot;).cast(pl.String),
        pl.col(&quot;floats_as_string&quot;).cast(pl.Float64),
    )

print(out)
shape: (5, 3)
┌──────────┬───────┬──────────────────┐
│ integers ┆ float ┆ floats_as_string │
│ ---      ┆ ---   ┆ ---              │
│ str      ┆ str   ┆ f64              │
╞══════════╪═══════╪══════════════════╡
│ 1        ┆ 4.0   ┆ 4.0              │
│ 2        ┆ 5.03  ┆ 5.0              │
│ 3        ┆ 6.0   ┆ 6.0              │
│ 4        ┆ 7.0   ┆ 7.0              │
│ 5        ┆ 8.0   ┆ 8.0              │
└──────────┴───────┴──────────────────┘

df = pl.DataFrame({&quot;strings_not_float&quot;: [&quot;4.0&quot;, &quot;not_a_number&quot;, &quot;6.0&quot;, &quot;7.0&quot;, &quot;8.0&quot;]})
print(df)
shape: (5, 1)
┌───────────────────┐
│ strings_not_float │
│ ---               │
│ str               │
╞═══════════════════╡
│ 4.0               │
│ not_a_number      │
│ 6.0               │
│ 7.0               │
│ 8.0               │
└───────────────────┘

#运行会报错
out=df.select(pl.col(&quot;strings_not_float&quot;).cast(pl.Float64))

#设置非严格模式，忽略错误，置为null
out=df.select(pl.col(&quot;strings_not_float&quot;).cast(pl.Float64,strict=False))
print(out)
shape: (5, 1)
┌───────────────────┐
│ strings_not_float │
│ ---               │
│ f64               │
╞═══════════════════╡
│ 4.0               │
│ null              │
│ 6.0               │
│ 7.0               │
│ 8.0               │
└───────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;布尔类型  Booleans&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;数值型与布尔型可以相互转换，但是不允许字符型转换为布尔型&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;df = pl.DataFrame(
    {
        &quot;integers&quot;: [-1, 0, 2, 3, 4],
        &quot;floats&quot;: [0.0, 1.0, 2.0, 3.0, 4.0],
        &quot;bools&quot;: [True, False, True, False, True],
    }
)

print(df)
shape: (5, 3)
┌──────────┬────────┬───────┐
│ integers ┆ floats ┆ bools │
│ ---      ┆ ---    ┆ ---   │
│ i64      ┆ f64    ┆ bool  │
╞══════════╪════════╪═══════╡
│ -1       ┆ 0.0    ┆ true  │
│ 0        ┆ 1.0    ┆ false │
│ 2        ┆ 2.0    ┆ true  │
│ 3        ┆ 3.0    ┆ false │
│ 4        ┆ 4.0    ┆ true  │
└──────────┴────────┴───────┘

out=df.select(pl.col(&quot;integers&quot;).cast(pl.Boolean), 
              pl.col(&quot;floats&quot;).cast(pl.Boolean)
             )
print(out)
shape: (5, 2)
┌──────────┬────────┐
│ integers ┆ floats │
│ ---      ┆ ---    │
│ bool     ┆ bool   │
╞══════════╪════════╡
│ true     ┆ false  │
│ false    ┆ true   │
│ true     ┆ true   │
│ true     ┆ true   │
│ true     ┆ true   │
└──────────┴────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;时间类型  Dates&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Date&lt;/code&gt; 或 &lt;code&gt;Datetime&lt;/code&gt; 等时间数据类型表示为自纪元（1970年1月1日）以来的天数（&lt;code&gt;Date&lt;/code&gt;）和微秒数（&lt;code&gt;Datetime&lt;/code&gt;），因此数值类型与时间数据类型能直接相互转换&lt;/p&gt;
&lt;p&gt;字符串类型与时间类型，可以通过 dt.to_string、str.to_datetime进行相互转换&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from datetime import date, datetime

df = pl.DataFrame(
    {
        &quot;date&quot;: pl.date_range(date(2022, 1, 1), date(2022, 1, 5), eager=True),
        &quot;datetime&quot;: pl.datetime_range(
            datetime(2022, 1, 1), datetime(2022, 1, 5), eager=True
        ),
    }
)

print(df)
shape: (5, 2)
┌────────────┬─────────────────────┐
│ date       ┆ datetime            │
│ ---        ┆ ---                 │
│ date       ┆ datetime[μs]        │
╞════════════╪═════════════════════╡
│ 2022-01-01 ┆ 2022-01-01 00:00:00 │
│ 2022-01-02 ┆ 2022-01-02 00:00:00 │
│ 2022-01-03 ┆ 2022-01-03 00:00:00 │
│ 2022-01-04 ┆ 2022-01-04 00:00:00 │
│ 2022-01-05 ┆ 2022-01-05 00:00:00 │
└────────────┴─────────────────────┘

out=df.select(pl.col(&quot;date&quot;).cast(pl.Int64),
              pl.col(&quot;datetime&quot;).cast(pl.Int64)
             )

print(out)
shape: (5, 2)
┌───────┬──────────────────┐
│ date  ┆ datetime         │
│ ---   ┆ ---              │
│ i64   ┆ i64              │
╞═══════╪══════════════════╡
│ 18993 ┆ 1640995200000000 │
│ 18994 ┆ 1641081600000000 │
│ 18995 ┆ 1641168000000000 │
│ 18996 ┆ 1641254400000000 │
│ 18997 ┆ 1641340800000000 │
└───────┴──────────────────┘

df = pl.DataFrame(
    {
        &quot;date&quot;: pl.date_range(date(2022, 1, 1), date(2022, 1, 5), eager=True),
        &quot;string&quot;: [
            &quot;2022-01-01&quot;,
            &quot;2022-01-02&quot;,
            &quot;2022-01-03&quot;,
            &quot;2022-01-04&quot;,
            &quot;2022-01-05&quot;,
        ],
    }
)

print(df)
shape: (5, 2)
┌────────────┬────────────┐
│ date       ┆ string     │
│ ---        ┆ ---        │
│ date       ┆ str        │
╞════════════╪════════════╡
│ 2022-01-01 ┆ 2022-01-01 │
│ 2022-01-02 ┆ 2022-01-02 │
│ 2022-01-03 ┆ 2022-01-03 │
│ 2022-01-04 ┆ 2022-01-04 │
│ 2022-01-05 ┆ 2022-01-05 │
└────────────┴────────────┘

out=df.select(
    pl.col(&quot;date&quot;).dt.to_string(&quot;%Y-%m-%d&quot;),
    pl.col(&quot;string&quot;).str.to_datetime(&quot;%Y-%m-%d&quot;),
    pl.col(&quot;string&quot;).str.to_date(&quot;%Y-%m-%d&quot;).alias(&quot;string_to_data&quot;)
)

print(out)
shape: (5, 3)
┌────────────┬─────────────────────┬────────────────┐
│ date       ┆ string              ┆ string_to_data │
│ ---        ┆ ---                 ┆ ---            │
│ str        ┆ datetime[μs]        ┆ date           │
╞════════════╪═════════════════════╪════════════════╡
│ 2022-01-01 ┆ 2022-01-01 00:00:00 ┆ 2022-01-01     │
│ 2022-01-02 ┆ 2022-01-02 00:00:00 ┆ 2022-01-02     │
│ 2022-01-03 ┆ 2022-01-03 00:00:00 ┆ 2022-01-03     │
│ 2022-01-04 ┆ 2022-01-04 00:00:00 ┆ 2022-01-04     │
│ 2022-01-05 ┆ 2022-01-05 00:00:00 ┆ 2022-01-05     │
└────────────┴─────────────────────┴────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6.md&quot;&gt;Python polars学习-01 读取与写入文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F.md&quot;&gt;Python polars学习-02 上下文与表达式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-pandas-%E9%87%8C%E9%9D%A2%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%9D%91%EF%BC%8Castype%E8%A6%81%E6%85%8E%E7%94%A8.md&quot;&gt;Python pandas 里面的数据类型坑，astype要慎用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-pandas-str-replace-%E4%B8%8D%E8%B5%B7%E4%BD%9C%E7%94%A8.md&quot;&gt;Python pandas.str.replace 不起作用&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-02 上下文与表达式</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-02_%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%8E%E8%A1%A8%E8%BE%BE%E5%BC%8F/</guid><description>Polars Contexts 上下文 与 Expressions 表达式</description><pubDate>Mon, 29 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;polars学习系列文章，第2篇，上下文与表达式 &amp;lt;br/&amp;gt;
该系列文章会分享到github，大家可以去下载jupyter文件&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;上下文与表达式概述&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;官方文档表述：&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Polars has developed its own Domain Specific Language (DSL) for transforming data.
The language is very easy to use and allows for complex queries that remain human readable.
The two core components of the language are Contexts and Expressions&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;机器翻译：&lt;/strong&gt;
Polars 开发了自己的特定领域语言 (DSL)，用于转换数据。
该语言非常容易使用，允许进行复杂的查询，但仍保持人类可读性。
该语言的两个核心组成部分是上下文和表达式&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;小编加工后的翻译：&lt;/strong&gt;
Polars 自己设计了一套用于处理数据的功能。
该功能易于使用，而且能以易理解的方式进行复杂的数据处理。
上下文与表达式是该功能的两个核心组成部分。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Contexts 上下文&lt;/strong&gt;
上下文是指需要计算表达式的上下文&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;选择：df.select(...)，df.with_columns(...)&lt;/li&gt;
&lt;li&gt;过滤：df.filter()&lt;/li&gt;
&lt;li&gt;分组聚合：df.group_by(...).agg(...)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. Expressions 表达式&lt;/strong&gt;
表达式是许多数据科学运算的核心：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;选取特定的列&lt;/li&gt;
&lt;li&gt;从一列中抽取特定的行&lt;/li&gt;
&lt;li&gt;将一列与值相乘&lt;/li&gt;
&lt;li&gt;从一个日期列中，提取年份&lt;/li&gt;
&lt;li&gt;将一列字符串转换为小写&lt;/li&gt;
&lt;li&gt;......&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;综上所述，在Polars中，Contexts 上下文 与 Expressions 表达式，需要结合使用&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;小编运行环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
#python 版本： 3.11.5 

import polars as pl

print(&quot;polars 版本：&quot;,pl.__version__)
#polars 版本： 0.20.22
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;演示数据&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;df=pl.read_csv(&apos;./data/iris.csv&apos;)

print(df.head(10))
#shape: (10, 6)
┌───────┬──────────────┬─────────────┬──────────────┬─────────────┬─────────┐
│ index ┆ Sepal.Length ┆ Sepal.Width ┆ Petal.Length ┆ Petal.Width ┆ Species │
│ ---   ┆ ---          ┆ ---         ┆ ---          ┆ ---         ┆ ---     │
│ i64   ┆ f64          ┆ f64         ┆ f64          ┆ f64         ┆ str     │
╞═══════╪══════════════╪═════════════╪══════════════╪═════════════╪═════════╡
│ 1     ┆ 5.1          ┆ 3.5         ┆ 1.4          ┆ 0.2         ┆ setosa  │
│ 2     ┆ 4.9          ┆ 3.0         ┆ 1.4          ┆ 0.2         ┆ setosa  │
│ 3     ┆ 4.7          ┆ 3.2         ┆ 1.3          ┆ 0.2         ┆ setosa  │
│ 4     ┆ 4.6          ┆ 3.1         ┆ 1.5          ┆ 0.2         ┆ setosa  │
│ 5     ┆ 5.0          ┆ 3.6         ┆ 1.4          ┆ 0.2         ┆ setosa  │
│ 6     ┆ 5.4          ┆ 3.9         ┆ 1.7          ┆ 0.4         ┆ setosa  │
│ 7     ┆ 4.6          ┆ 3.4         ┆ 1.4          ┆ 0.3         ┆ setosa  │
│ 8     ┆ 5.0          ┆ 3.4         ┆ 1.5          ┆ 0.2         ┆ setosa  │
│ 9     ┆ 4.4          ┆ 2.9         ┆ 1.4          ┆ 0.2         ┆ setosa  │
│ 10    ┆ 4.9          ┆ 3.1         ┆ 1.5          ┆ 0.1         ┆ setosa  │
└───────┴──────────────┴─────────────┴──────────────┴─────────────┴─────────┘

df.shape
#(150, 6)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;选取需要的列&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;df.select(pl.col(&quot;Sepal.Length&quot;))  #选取特定的列

df.select(pl.col(&quot;Sepal.Length&quot;,&quot;Petal.Length&quot;))

df.select(pl.col(&quot;*&quot;))  #选取所有列

df.select(pl.all())  #选取所有列

df.select(pl.col(&quot;*&quot;).exclude(&quot;index&quot;, &quot;Species&quot;))  #选取列时，排除特定列

df.select(pl.col(&quot;^.*Length$&quot;))  #支持正则表达式，需要以 ^ 开始 $ 结尾

df.select(pl.col(pl.Float64))  #根据列的类型，进行选取
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;筛选出需要的行&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;df.filter(pl.col(&quot;Sepal.Length&quot;)&amp;gt;5)  

df.filter((pl.col(&quot;Sepal.Length&quot;)&amp;gt;5) &amp;amp; (pl.col(&quot;Petal.Length&quot;)&amp;gt;5))  
#需要把2个条件分别括起来！！！

df.filter((pl.col(&quot;Sepal.Length&quot;)&amp;gt;5) | (pl.col(&quot;Petal.Length&quot;)&amp;gt;5))

df.select(pl.col(&quot;Sepal.Width&quot;,&quot;Petal.Width&quot;).filter(pl.col(&quot;Sepal.Length&quot;)&amp;gt;5))
#根据过滤条件，选取特定列
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;增加新列&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;df.with_columns(pl.lit(10),pl.lit(2).alias(&quot;lit_5&quot;))  #增加常数列，并设置别名

df.with_columns(pl.max(&quot;Sepal.Length&quot;).alias(&quot;max_Sepal.Length&quot;),
                pl.min(&quot;Sepal.Length&quot;).alias(&quot;min_Sepal.Length&quot;),
                pl.mean(&quot;Sepal.Length&quot;).alias(&quot;avg_Sepal.Length&quot;),
                pl.std(&quot;Sepal.Length&quot;).alias(&quot;std_Sepal.Length&quot;)
               )  #有点类似窗口函数
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;数值列运算&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;df.select(pl.col(&quot;Sepal.Length&quot;),
          (pl.col(&quot;Sepal.Length&quot;)*100).alias(&quot;Sepal.Length * 100&quot;),
          (pl.col(&quot;Sepal.Length&quot;)/100).alias(&quot;Sepal.Length / 100&quot;),
          (pl.col(&quot;Sepal.Length&quot;)/pl.max(&quot;Sepal.Length&quot;)).alias(&quot;Sepal.Length /max_Sepal.Length&quot;)
         )
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;字段串列运算&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;df.select(pl.col(&quot;Species&quot;),
          pl.col(&quot;Species&quot;).str.len_bytes().alias(&quot;byte_count&quot;),
          pl.col(&quot;Species&quot;).str.len_chars().alias(&quot;chars_count&quot;)
         )

df.select(pl.col(&quot;Species&quot;),
          pl.col(&quot;Species&quot;).str.contains(&quot;set|vir&quot;).alias(&quot;regex&quot;),
          pl.col(&quot;Species&quot;).str.starts_with(&quot;set&quot;).alias(&quot;starts_with&quot;),
          pl.col(&quot;Species&quot;).str.ends_with(&quot;ca&quot;).alias(&quot;ends_with&quot;),
         )
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;去重统计&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;df.select(pl.col(&quot;Species&quot;).n_unique())
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;分组聚合运算&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;df.group_by(&quot;Species&quot;).agg(
    pl.len(),
    pl.col(&quot;index&quot;),
    pl.count(&quot;Sepal.Length&quot;).name.suffix(&quot;_count_1&quot;),  #别名，另一种方式
    pl.col(&quot;Sepal.Length&quot;).count().name.suffix(&quot;_count_2&quot;),
    pl.mean(&quot;Sepal.Length&quot;).name.suffix(&quot;_mean&quot;),
    pl.std(&quot;Sepal.Length&quot;).name.suffix(&quot;_std&quot;),
)

df.group_by(&quot;Species&quot;).agg(
    (pl.col(&quot;Sepal.Length&quot;)&amp;gt;5).sum().alias(&quot;Sepal.Length&amp;gt;5&quot;),
    (pl.col(&quot;Petal.Length&quot;)&amp;gt;5).sum().alias(&quot;Petal.Length&amp;gt;5&quot;),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;排序&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;df.sort(&quot;Sepal.Length&quot;,descending=True)

df.sort([&quot;Sepal.Length&quot;,&quot;Petal.Length&quot;],descending=[True,False])
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6/&quot;&gt;Python polars学习-01 读取与写入文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-pandas%E9%81%8D%E5%8E%86%E8%A1%8C%E6%95%B0%E6%8D%AE%E7%9A%842%E7%A7%8D%E6%96%B9%E6%B3%95.md&quot;&gt;Python pandas遍历行数据的2种方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-%E5%88%A9%E7%94%A8pandas%E5%AF%B9%E6%95%B0%E6%8D%AE%E8%BF%9B%E8%A1%8C%E7%89%B9%E5%AE%9A%E6%8E%92%E5%BA%8F.md&quot;&gt;Python 利用pandas对数据进行特定排序&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-pandas-str-replace-%E4%B8%8D%E8%B5%B7%E4%BD%9C%E7%94%A8.md&quot;&gt;Python pandas.str.replace 不起作用&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>polars学习-01 读取与写入文件</title><link>https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/polars-%E5%AD%A6%E4%B9%A0/Python_polars%E5%AD%A6%E4%B9%A0-01_%E8%AF%BB%E5%8F%96%E4%B8%8E%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6/</guid><description>Polars 数据读取与写入文件</description><pubDate>Wed, 24 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;在Python数据处理与分析中，大家在处理数据时，使用的基本都是 &lt;code&gt;Pandas&lt;/code&gt; ，该库非常好用。随着 Rust 的出圈，基于其开发的 &lt;code&gt;Polars&lt;/code&gt; 库，逐渐赢得大家的喜爱，在某些功能上更优于 &lt;code&gt;Pandas&lt;/code&gt;。于是小编在自学的过程中，逐步整理一些资料供大家参考学习，这些资料会分享到github&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/DataShare-duo/polars_learn&quot;&gt;https://github.com/DataShare-duo/polars_learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PS：为了学习 &lt;code&gt;Polars&lt;/code&gt;，小编先了解一遍 Rust，《Rust权威指南》&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys
print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])
# python 版本：3.11.5 

import polars as pl
print(&quot;polars 版本：&quot;,pl.__version__)
# polars 版本： 0.20.22
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;读取文件&lt;/h1&gt;
&lt;p&gt;polars读取文件数据的方式基本与pands一致，所以上手起来很方便，以下演示是在jupyter notebook中执行&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;读取csv文件&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;data_csv=pl.read_csv(&apos;./data/iris.csv&apos;)

data_csv.shape
#(150, 6)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;读取 excel 文件&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;默认解析引擎 &lt;code&gt;xlsx2csv&lt;/code&gt;，需要额外安装 &lt;code&gt;pip install xlsx2csv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;设置 &lt;code&gt;engine=&apos;calamine&apos;&lt;/code&gt; 时，需要额外安装 &lt;code&gt;pip install fastexcel&lt;/code&gt;，建议用该解析引擎，速度更快&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;data_excel=pl.read_excel(&apos;./data/iris.xlsx&apos;,sheet_name=&apos;iris&apos;,engine=&apos;calamine&apos;)

data_excel.shape
#(150, 6)

%timeit pl.read_excel(&apos;./data/iris.xlsx&apos;,sheet_name=&apos;iris&apos;)
#13.9 ms ± 69.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit pl.read_excel(&apos;./data/iris.xlsx&apos;,sheet_name=&apos;iris&apos;,engine=&apos;calamine&apos;)  
#2.9 ms ± 69.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;读取 txt 文件&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;data_txt=pl.read_csv(&apos;./data/iris.txt&apos;,separator=&apos;\t&apos;)

data_txt.shape
#(150, 6)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;读取网络上的文件&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;url=&apos;https://raw.githubusercontent.com/DataShare-duo/Data_for_ML-Deeplearning/master/iris.csv&apos;

data_url=pl.read_csv(url)

data_url.shape
#(150, 6)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;写入文件&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;写入csv文件&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;data_csv.write_csv(&apos;./data/data_write.csv&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;写入excel文件&lt;/strong&gt;
默认的浮点数为3位，可以通过 &lt;code&gt;float_precision&lt;/code&gt; 参数进行设置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;data_csv.write_excel(&apos;./data/data_write.xlsx&apos;,float_precision=1)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-pandas%E9%81%8D%E5%8E%86%E8%A1%8C%E6%95%B0%E6%8D%AE%E7%9A%842%E7%A7%8D%E6%96%B9%E6%B3%95.md&quot;&gt;Python pandas遍历行数据的2种方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-%E5%88%A9%E7%94%A8pandas%E5%AF%B9%E6%95%B0%E6%8D%AE%E8%BF%9B%E8%A1%8C%E7%89%B9%E5%AE%9A%E6%8E%92%E5%BA%8F.md&quot;&gt;Python 利用pandas对数据进行特定排序&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-pandas-str-replace-%E4%B8%8D%E8%B5%B7%E4%BD%9C%E7%94%A8.md&quot;&gt;Python pandas.str.replace 不起作用&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 利用partial偏函数，生成不同的聚合函数</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%88%A9%E7%94%A8partial%E5%81%8F%E5%87%BD%E6%95%B0%EF%BC%8C%E7%94%9F%E6%88%90%E4%B8%8D%E5%90%8C%E7%9A%84%E8%81%9A%E5%90%88%E5%87%BD%E6%95%B0/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%88%A9%E7%94%A8partial%E5%81%8F%E5%87%BD%E6%95%B0%EF%BC%8C%E7%94%9F%E6%88%90%E4%B8%8D%E5%90%8C%E7%9A%84%E8%81%9A%E5%90%88%E5%87%BD%E6%95%B0/</guid><description>Python partial偏函数</description><pubDate>Tue, 26 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;介绍&lt;/h1&gt;
&lt;p&gt;偏函数(&lt;code&gt;functools.partial&lt;/code&gt;)，主要用来解决函数中某些参数是已知的固定值。利用偏函数的概念，可以生成一些新的函数，在调用这些新函数时，不用再传递固定值的参数，这样可以使代码更简洁&lt;/p&gt;
&lt;p&gt;下面列举一些偏函数的巧妙使用方法，在使用偏函数时，需要从标准库&lt;code&gt;functools&lt;/code&gt;中导入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from functools import partial
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])   
#python 版本： 3.11.4
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;生成不同的聚合函数&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;1. 创建底层的元函数、函数类&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from functools import partial

def aggregation_fn_meta(aggregation_fn, values):
    return aggregation_fn(values)

def aggregation_fn_class(aggregation_fn):
    return partial(aggregation_fn_meta, aggregation_fn)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 基于函数类，来生成不同的聚合函数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基于内建函数创建（python中可以直接使用的函数）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sum_fn=aggregation_fn_class(sum)
sum_fn([1,2,3,4,5,1,2,10])   #28

max_fn=aggregation_fn_class(max)
max_fn([1,2,3,4,5,1,2,10])   #10

min_fn=aggregation_fn_class(min)
min_fn([1,2,3,4,5,1,2,10])
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;基于自定义函数创建&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;def count(values):
    return len(values)

count_fn=aggregation_fn_class(count)
count_fn([1,2,3,4,5,1,2,10])    #8


def distinct_count(values):
    return len(set(values))

distinct_count_fn=aggregation_fn_class(distinct_count)
distinct_count_fn([1,2,3,4,5,1,2,10])   #6
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C.md&quot;&gt;Python 标准库之pathlib，路径操作&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E8%AE%B0%E5%BD%95re%E6%AD%A3%E5%88%99%E6%A8%A1%E5%9D%97%EF%BC%8C%E6%96%B9%E4%BE%BF%E5%90%8E%E6%9C%9F%E6%9F%A5%E6%89%BE%E4%BD%BF%E7%94%A8.md&quot;&gt;Python 记录re正则模块，方便后期查找使用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97-bisect%EF%BC%8C%E6%95%B0%E7%BB%84%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95.md&quot;&gt;Python 内建模块 bisect，数组二分查找算法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python-字典已经是有序的，你知道吗？</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%AD%97%E5%85%B8%E5%B7%B2%E7%BB%8F%E6%98%AF%E6%9C%89%E5%BA%8F%E7%9A%84%EF%BC%8C%E4%BD%A0%E7%9F%A5%E9%81%93%E5%90%97%EF%BC%9F/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%AD%97%E5%85%B8%E5%B7%B2%E7%BB%8F%E6%98%AF%E6%9C%89%E5%BA%8F%E7%9A%84%EF%BC%8C%E4%BD%A0%E7%9F%A5%E9%81%93%E5%90%97%EF%BC%9F/</guid><description>Python 字典</description><pubDate>Tue, 21 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;随着Python版本的更新，背后的一些数据结构会进行不断优化迭代，重新进行架构设计，以实现内存减少、性能提升。其中字典的底层数据结构在Python3.6版本时，重新进行了设计，从而优化了字典的内存占用&lt;/p&gt;
&lt;p&gt;具体的底层细节这里不做过多介绍，感兴趣的同学可以看一下这篇文章：
&lt;strong&gt;《为什么Python 3.6以后字典有序并且效率更高？》&lt;/strong&gt;
地址：&lt;a href=&quot;https://zhuanlan.zhihu.com/p/73426505&quot;&gt;https://zhuanlan.zhihu.com/p/73426505&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;该文章的评论精彩评论：&lt;/em&gt;
一句话解释：从Python3.6开始，dict的实现由 &lt;strong&gt;哈希表&lt;/strong&gt; 改成 &lt;strong&gt;链式哈希表&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])   
#python 版本： 3.11.4
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;测试代码&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#创建测试数据
keys=[chr(i) for i in range(97,123)]
values=range(1,27)

#生成字典
dic={}
for key,value in zip(keys,values):
    dic[key]=value

#打印字典
print(dic)
#{&apos;a&apos;: 1, &apos;b&apos;: 2, &apos;c&apos;: 3, &apos;d&apos;: 4, &apos;e&apos;: 5, &apos;f&apos;: 6, 
#&apos;g&apos;: 7, &apos;h&apos;: 8, &apos;i&apos;: 9, &apos;j&apos;: 10, &apos;k&apos;: 11, &apos;l&apos;: 12,
# &apos;m&apos;: 13, &apos;n&apos;: 14, &apos;o&apos;: 15, &apos;p&apos;: 16, &apos;q&apos;: 17, 
#&apos;r&apos;: 18,&apos;s&apos;: 19, &apos;t&apos;: 20, &apos;u&apos;: 21, &apos;v&apos;: 22,
# &apos;w&apos;: 23, &apos;x&apos;: 24, &apos;y&apos;: 25, &apos;z&apos;: 26}


#遍历字典
for key,value in dic.items():
    print(key,&apos;:&apos;,value,end=&apos;,&apos;)
#a : 1,b : 2,d : 4,e : 5,f : 6,g : 7,h : 8,j : 10,
#k : 11,l : 12,n : 14,o : 15,p : 16,q : 17,r : 18,
#s : 19,t : 20,u : 21,v : 22,w : 23,x : 24,z : 26,

#删除测试
del dic[&apos;c&apos;]
del dic[&apos;y&apos;]
del dic[&apos;i&apos;]
del dic[&apos;m&apos;]

print(dic)
#{&apos;a&apos;: 1, &apos;b&apos;: 2, &apos;d&apos;: 4, &apos;e&apos;: 5, &apos;f&apos;: 6, &apos;g&apos;: 7, 
#&apos;h&apos;: 8, &apos;j&apos;: 10, &apos;k&apos;: 11, &apos;l&apos;: 12, &apos;n&apos;: 14, &apos;o&apos;: 15,
#&apos;p&apos;: 16, &apos;q&apos;: 17, &apos;r&apos;: 18, &apos;s&apos;: 19, &apos;t&apos;: 20,
#&apos;u&apos;: 21, &apos;v&apos;: 22, &apos;w&apos;: 23, &apos;x&apos;: 24, &apos;z&apos;: 26}

&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;结论&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;经过添加、删除操作可以看出，字典是按添加键值对时的先后顺序保存数据，是有序的&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C.md&quot;&gt;Python 标准库之pathlib，路径操作&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E8%AE%B0%E5%BD%95re%E6%AD%A3%E5%88%99%E6%A8%A1%E5%9D%97%EF%BC%8C%E6%96%B9%E4%BE%BF%E5%90%8E%E6%9C%9F%E6%9F%A5%E6%89%BE%E4%BD%BF%E7%94%A8.md&quot;&gt;Python 记录re正则模块，方便后期查找使用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97-bisect%EF%BC%8C%E6%95%B0%E7%BB%84%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95.md&quot;&gt;Python 内建模块 bisect，数组二分查找算法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E6%A0%87%E5%87%86%E5%BA%93heapq%EF%BC%8C%E5%A0%86%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%93%8D%E4%BD%9C%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python 标准库heapq，堆数据结构操作详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-math%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python math模块详解&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 扑克牌发牌游戏</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%89%91%E5%85%8B%E7%89%8C%E5%8F%91%E7%89%8C%E6%B8%B8%E6%88%8F/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%89%91%E5%85%8B%E7%89%8C%E5%8F%91%E7%89%8C%E6%B8%B8%E6%88%8F/</guid><description>Python 扑克牌游戏</description><pubDate>Thu, 16 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;最近在看《Python - 100天从新手到大师》时，运行了一下代码，感觉挺有意思。一个简单的小游戏，包含了pyhon的很多知识，分享出来，供大家参考学习&lt;/p&gt;
&lt;p&gt;小编对扑克牌的排序进行了简单修改，使相同大小的牌放在一起&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;《Python - 100天从新手到大师》，感兴趣的同学可以去学习该教程 &amp;lt;br/&amp;gt;
地址：https://github.com/jackfrued/Python-100-Days&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;发牌结果&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-2ccfc95166690490.png&quot; alt=&quot;发牌结果&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])   
#python 版本： 3.11.4
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;完整代码&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;&quot;&quot;&quot;
===========================
@Software: PyCharm
@Platform: Win10
@Author : DataShare
===========================
&quot;&quot;&quot;

from enum import Enum, unique
import random


@unique
class Suite(Enum):
    &quot;&quot;&quot;花色&quot;&quot;&quot;

    SPADE, HEART, CLUB, DIAMOND = range(4)

    def __lt__(self, other):
        return self.value &amp;lt; other.value


class Card:
    &quot;&quot;&quot;牌&quot;&quot;&quot;

    def __init__(self, suite, face):
        &quot;&quot;&quot;初始化方法&quot;&quot;&quot;
        self.suite = suite
        self.face = face

    def show(self):
        &quot;&quot;&quot;显示牌面&quot;&quot;&quot;
        suites = [&apos;♠︎&apos;, &apos;♥︎&apos;, &apos;♣︎&apos;, &apos;♦︎&apos;]
        faces = [&apos;&apos;, &apos;A&apos;, &apos;2&apos;, &apos;3&apos;, &apos;4&apos;, &apos;5&apos;, &apos;6&apos;,
                 &apos;7&apos;, &apos;8&apos;, &apos;9&apos;, &apos;10&apos;, &apos;J&apos;, &apos;Q&apos;, &apos;K&apos;]
        return f&apos;{suites[self.suite.value]}{faces[self.face]}&apos;

    def __repr__(self):
        return self.show()


class Poker:
    &quot;&quot;&quot;扑克&quot;&quot;&quot;

    def __init__(self):
        self.index = 0
        self.cards = [Card(suite, face)
                      for suite in Suite
                      for face in range(1, 14)]

    def shuffle(self):
        &quot;&quot;&quot;洗牌（随机乱序）&quot;&quot;&quot;
        random.shuffle(self.cards)
        self.index = 0

    def deal(self):
        &quot;&quot;&quot;发牌&quot;&quot;&quot;
        card = self.cards[self.index]
        self.index += 1
        return card

    @property
    def has_more(self):
        return self.index &amp;lt; len(self.cards)


class Player:
    &quot;&quot;&quot;玩家&quot;&quot;&quot;

    def __init__(self, name):
        self.name = name
        self.cards = []

    def get_one(self, card):
        &quot;&quot;&quot;摸一张牌&quot;&quot;&quot;
        self.cards.append(card)

    def sort(self, comp=lambda card: (card.face, card.suite)):
        &quot;&quot;&quot;整理手上的牌&quot;&quot;&quot;
        self.cards.sort(key=comp)


def main():
    &quot;&quot;&quot;主函数&quot;&quot;&quot;
    poker = Poker()
    poker.shuffle()
    players = [Player(&apos;东邪&apos;), Player(&apos;西毒&apos;), 
               Player(&apos;南帝&apos;), Player(&apos;北丐&apos;)]
    while poker.has_more:
        for player in players:
                player.get_one(poker.deal())
    for player in players:
        player.sort()
        print(player.name, end=&apos;: &apos;)
        print(player.cards)

if __name__ == &apos;__main__&apos;:
    main()

&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C.md&quot;&gt;Python 标准库之pathlib，路径操作&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E8%AE%B0%E5%BD%95re%E6%AD%A3%E5%88%99%E6%A8%A1%E5%9D%97%EF%BC%8C%E6%96%B9%E4%BE%BF%E5%90%8E%E6%9C%9F%E6%9F%A5%E6%89%BE%E4%BD%BF%E7%94%A8.md&quot;&gt;Python 记录re正则模块，方便后期查找使用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97-bisect%EF%BC%8C%E6%95%B0%E7%BB%84%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95.md&quot;&gt;Python 内建模块 bisect，数组二分查找算法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>在Linux服务器上部署Jupyter-notebook</title><link>https://datashare-duo.github.io/datashare-blog/posts/Linux/%E5%9C%A8Linux%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E9%83%A8%E7%BD%B2Jupyter-notebook/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Linux/%E5%9C%A8Linux%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E9%83%A8%E7%BD%B2Jupyter-notebook/</guid><description>Linux 部署Jupyter-notebook</description><pubDate>Fri, 13 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;小编在刚开始学习Python时，是在Python官网下载的原生版本，用的是自带的编码环境，后来了解到在数据分析、数据科学领域用Jupyter notebook比较好，于是直到现在也是一直在用Jupyter notebook，也偶尔用PyCharm做开发。在数据分析与处理中Jupyter notebook还是很方便，可以直接查看数据，可以写文档，可以画图 等很多优点，感觉Jupyter notebook 就是是为了数据分析、数据挖掘、机器学习而生的&lt;/p&gt;
&lt;p&gt;如果用过Jupyter notebook，大家都知道，它是一个网页界面，服务端和客户端分离，每次启动都会在后台运行一个cmd/terminal窗口，可以理解为服务端，而使用的浏览器界面，可以理解为客户端。既然是服务端与客户端分开的，那么服务端就可以部署到服务器上，可以充分利用服务器的计算资源、存储资源，更甚者可以用GPU资源。其实在服务器部署Jupyter notebook，做机器学习的同学，应该对这个很熟悉，但是不一定亲手部署过
&lt;img src=&quot;./images/6641583-01c945ebf7ff1a19.png&quot; alt=&quot;Jupyter notebook&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;浏览器-客户端&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-e95e84098eee9c4c.png&quot; alt=&quot;客户端&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;cmd-服务端&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-74e25860d043bc20.png&quot; alt=&quot;服务端&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;必要前提！！！&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;需要对Linux服务器要有所了解，如果在工作中压根就没使用过服务器，且不知道ssh，那小编劝你暂时先别看这篇文章，可以先去多学一些Python知识，后面随着知识的积累，慢慢的你就会接触到服务器&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;小编服务器环境&lt;/h1&gt;
&lt;p&gt;硬件：谷歌云虚拟机实例，1G内存，100G硬盘&lt;/p&gt;
&lt;p&gt;系统：64位 Debian，Debian GNU/Linux 11&lt;/p&gt;
&lt;h1&gt;服务器部署流程&lt;/h1&gt;
&lt;p&gt;在服务器上安装Jupyter notebook，一共分为4步，最终实现在本地电脑来访问&lt;/p&gt;
&lt;p&gt;因为Anaconda自带Jupyter notebook，并且可以创建虚拟环境，使用起来非常方便，所以强烈推荐使用Anaconda，可以让你少采坑&lt;/p&gt;
&lt;h2&gt;第1步：下载Anaconda&lt;/h2&gt;
&lt;p&gt;Anaconda 下载地址：&lt;a href=&quot;https://www.anaconda.com/download#downloads&quot;&gt;https://www.anaconda.com/download#downloads&lt;/a&gt;
&lt;img src=&quot;./images/6641583-98e2c2c5dfe9a154.png&quot; alt=&quot;下载Anaconda&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在服务器上直接下载（谷歌服务器下载很快）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wget https://repo.anaconda.com/archive/Anaconda3-2023.09-0-Linux-x86_64.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-f98732cbd997ee92.png&quot; alt=&quot;服务器下载&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;第2步：安装Anaconda&lt;/h2&gt;
&lt;p&gt;在服务器上直接安装Anaconda，在安装中一直点击回车或空格键，在许可条款、最后配置的地方输入 yes 即可&lt;/p&gt;
&lt;p&gt;在安装时确保硬盘存储空间要足够，小编在安装是最开始只有10G硬盘资源，一直报错，后来扩大硬盘后解决了&lt;/p&gt;
&lt;p&gt;安装完成后，命令行提示符前会有多了个 &lt;code&gt;(base)&lt;/code&gt;，这个是Anaconda默认的基础虚假环境，小编下载的是截止发文章时最新版Anaconda，里面集成的是 &lt;strong&gt;Python 3.11.5&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash Anaconda3-2023.09-0-Linux-x86_64.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-504d8afa088872c6.png&quot; alt=&quot;安装完成&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;第3步：对Jupyter notebook进行配置&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;生成配置文件，运行后会显示配置文件的存放位置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;jupyter notebook --generate-config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-4c0e4c6521f0b838.png&quot; alt=&quot;生成配置文件&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对配置文件进行修改&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;## The IP address the notebook server will listen on.
#  Default: &apos;localhost&apos;
# 设置可以访问的ip, 默认是localhost, 将其改为 &apos;*&apos;
c.NotebookApp.ip = &apos;*&apos;


## The directory to use for notebooks and kernels.
#  Default: &apos;&apos;
# 默认打开目录
c.NotebookApp.notebook_dir = &apos;/home/data123share66/python&apos;


## Whether to open in a browser after starting.
#                          The specific browser used is platform dependent and
#                          determined by the python standard library `webbrowser`
#                          module, unless it is overridden using the --browser
#                          (NotebookApp.browser) configuration option.
#  Default: True
# Jupyter notebook启动后是否打开浏览器, 设为 False 即可
c.NotebookApp.open_browser = False


## Hashed password to use for web authentication.
#  
#                        To generate, type in a python/IPython shell:
#  
#                          from notebook.auth import passwd; passwd()
#  
#                        The string should be of the form type:salt:hashed-
#  password.
#  Default: &apos;&apos;
c.NotebookApp.password = &apos;argon2:$argon2id$v=19$m=10240,t=10,p=8$Ny6WDdoLBm88cUMyOqgNqg$s3WObP81eU51RT2j8D8DULPM1OAPOnzYfODW8olB0xw&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;小编这里在生成密码是用的 &lt;code&gt;datashare&lt;/code&gt; ，在输入时屏幕不会显示&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-5319a3ec995b55e5.png&quot; alt=&quot;生成密码&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;第4步：启动Jupyter notebook，并在本地电脑远程访问&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;1、服务器启动Jupyter notebook&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;jupyter notebook --ip=0.0.0.0 --port=9999
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;2、在本地电脑浏览器远程访问
在浏览器输入服务器的IP地址:9999，小编这里是&lt;code&gt;34.81.173.39:9999&lt;/code&gt;，访问后，会出现如下页面&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-daf83c49b251af83.png&quot; alt=&quot;远程访问&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后输入密码 &lt;code&gt;datashare&lt;/code&gt; 进行登录，成功登录后界面如下所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-90d3f2a3d51c9f4b.png&quot; alt=&quot;登录后界面&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3、创建一个notebook，查看python版本
&lt;img src=&quot;./images/6641583-be2f0d0a52dfd098.png&quot; alt=&quot;查看python版本&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Jupyter 好用的扩展插件&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1、安装jupyter_contrib_nbextensions&lt;/strong&gt;
该插件会扩展jupyter的很多功能，如目录，自动补全等，在服务器终端依次运行如下命令&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pip install jupyter_contrib_nbextensions

jupyter-contrib-nbextension install --user
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;打开jupyter会发现多了一个菜单栏 &lt;code&gt;Nbextension&lt;/code&gt;
&lt;img src=&quot;./images/6641583-83c8f70b62746854.png&quot; alt=&quot;Nbextension&quot; /&gt;
对Nbextension进行配置，勾选需要的功能
&lt;img src=&quot;./images/6641583-cef33d4184f191aa.png&quot; alt=&quot;Nbextension配置&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2、安装nb_conda&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;conda install nb_conda
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装完成后，需要在服务器重新启动一下Jupyter notebook，会发现多了一个菜单栏 &lt;code&gt;Conda&lt;/code&gt;
&lt;img src=&quot;./images/6641583-63924b8af5a35ac4.png&quot; alt=&quot;nb_conda&quot; /&gt;
在服务器创建一个虚拟环境 python312，然后刷新一下页面，就可以看到虚拟环境 python312&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conda create -n python312 python=3.12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-d2c51835c05d66f8.png&quot; alt=&quot;虚拟环境&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;多个Python版本kernel配置&lt;/h1&gt;
&lt;p&gt;虽然上面已经创建了虚拟环境，并显示出来了，但是在创建新的notebook时并显示python312，因为python312存在不同的虚拟环境里面，这个需要我们再进行配置
&lt;img src=&quot;./images/6641583-d3c70ec83ea11a22.png&quot; alt=&quot;单个kernel&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Jupyter Notebook允许用户在同一个notebook中使用多个不同的IPython内核&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1、安装Jupyter Notebook和IPython内核&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;conda create -n python312 python=3.12   #上面安装过的可以忽略
conda activate python312
pip install jupyter
pip install ipykernel
pip install ipywidgets
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2、安装新的kernel内核&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;conda activate python312   #切换虚拟环境
ipython kernel install --name &quot;python312&quot; --user
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;3、服务器端重新启动Jupyter notebook&lt;/strong&gt;
建一个python312内核的notebook，查看当前内核的python解释器版本
&lt;img src=&quot;./images/6641583-3b480948aa884963.png&quot; alt=&quot;切换为新内核&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Linux-%EF%BC%88Centos-7%EF%BC%89%E4%B8%AD-Anaconda%E7%8E%AF%E5%A2%83%E7%AE%A1%E7%90%86%EF%BC%8C%E5%AE%89%E8%A3%85%E4%B8%8D%E5%90%8C%E7%9A%84%E7%89%88%E6%9C%ACPython%E5%8C%85.md&quot;&gt;Linux （Centos 7）中 Anaconda环境管理，安装不同的版本Python包&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E5%B8%B8%E7%94%A8%E8%AF%AD%E5%8F%A5%E6%B1%87%E6%80%BB.md&quot;&gt;Python常用语句汇总&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E5%B8%88%E5%B8%B8%E7%94%A8%E7%9A%84-Linux-%E5%91%BD%E4%BB%A4%E6%80%BB%E7%BB%93.md&quot;&gt;数据分析师常用的 Linux 命令总结&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 标准库之pathlib，路径操作</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93%E4%B9%8Bpathlib%EF%BC%8C%E8%B7%AF%E5%BE%84%E6%93%8D%E4%BD%9C/</guid><description>Python pathlib基础库</description><pubDate>Wed, 27 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;pathlib&lt;/code&gt; 标准库是在 Python3.4 引入，到现在最近版 3.11 已更新了好几个版本，主要是用于路径操作，相比之前的路径操作方法 &lt;code&gt;os.path&lt;/code&gt; 有一些优势，有兴趣的同学可以学习下&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;官方文档：&lt;/strong&gt; &lt;a href=&quot;https://docs.python.org/zh-cn/3/library/pathlib.html&quot;&gt;https://docs.python.org/zh-cn/3/library/pathlib.html&lt;/a&gt;
&lt;img src=&quot;./images/6641583-9e5a96f92df24f82.png&quot; alt=&quot;官方pathlib图片&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;小编环境&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])   #python 版本： 3.11.4
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;主要方法、函数&lt;/h1&gt;
&lt;p&gt;该模块中主要使用的是 &lt;code&gt;Path&lt;/code&gt; 类&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h2&gt;导入模块&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;from pathlib import Path
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h2&gt;获取当前工作目录&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;Path.cwd()   #WindowsPath(&apos;D:/桌面/Python/标准库&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h2&gt;获取用户 home 目录&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;Path.home()   #WindowsPath(&apos;C:/Users/admin&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h2&gt;获取绝对路径&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;file = Path(&apos;pathlib_demo1.py&apos;)
print(file)   #WindowsPath(&apos;pathlib_demo1.py&apos;)
file.resolve()  #WindowsPath(&apos;D:/桌面/Python/标准库/pathlib_demo1.py&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h2&gt;获取文件属性&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;file = Path(&apos;pathlib_demo1.py&apos;)
print(file)   #WindowsPath(&apos;pathlib_demo1.py&apos;)

file.stat()  
&apos;&apos;&apos;
os.stat_result(st_mode=33206, st_ino=1970324837176895, st_dev=2522074357, 
st_nlink=1, st_uid=0, st_gid=0, st_size=273, 
st_atime=1695642854, st_mtime=1695611301, st_ctime=1695611241)
&apos;&apos;&apos;

#文件大小
file.stat().st_size   #273B

#最近访问时间 access ，It represents the time of most recent access 
file.stat().st_atime  #1695625134.9083948

#创建时间 create，It represents the time of most recent metadata change on Unix and creation time on Windows.
file.stat().st_ctime  #1695611241.5981772

#修改时间  modify，It represents the time of most recent content modification
file.stat().st_mtime  #1695611301.1193473
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h2&gt;查看当前工作目录文件及文件夹&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;for f in path.iterdir():
    print(f)
    print(&apos;is_file:&apos;,f.is_file())  #判断是否为文件
    print(&apos;is_dir:&apos;,f.is_dir())   #判断是否为文件夹
    print(&apos;=&apos;*30)

&apos;&apos;&apos;
D:\桌面\Python\标准库\.ipynb_checkpoints
is_file: False
is_dir: True
==============================
D:\桌面\Python\标准库\pathlib.ipynb
is_file: True
is_dir: False
==============================
D:\桌面\Python\标准库\pathlib_demo1.py
is_file: True
is_dir: False
==============================
&apos;&apos;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h2&gt;路径的各个组成部分&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;file=Path(&apos;D:\桌面\Python\标准库\pathlib_demo1.py&apos;)

file.name  #&apos;pathlib_demo1.py&apos;
file.stem  #&apos;pathlib_demo1&apos;
file.suffix   #&apos;.py&apos;
file.parent   #WindowsPath(&apos;D:/桌面/Python/标准库&apos;)
file.anchor  #&apos;D:\\&apos;
file.parent.parent  #WindowsPath(&apos;D:/桌面/Python&apos;)

#获取所有的父级路径，层层递进
list(file.parents)
&apos;&apos;&apos;
[WindowsPath(&apos;D:/桌面/Python/标准库&apos;),
 WindowsPath(&apos;D:/桌面/Python&apos;),
 WindowsPath(&apos;D:/桌面&apos;),
 WindowsPath(&apos;D:/&apos;)]
&apos;&apos;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h2&gt;路径拼接&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;支持2种方式&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#第1种方式：使用 /
Path.home() / &apos;dir&apos; / &apos;file.txt&apos;  #WindowsPath(&apos;C:/Users/admin/dir/file.txt&apos;)

#第2种方式：使用方法
Path.home().joinpath(&apos;dir&apos;, &apos;file.txt&apos;)  #WindowsPath(&apos;C:/Users/admin/dir/file.txt&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h2&gt;判断路径、文件是否存在&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;#当前文件件里面是否存在 子目录 archive/demo.txt 文件
Path(&quot;archive/demo.txt&quot;).exists()  #False

#当前文件件里面是否存在 二级子目录 dir/subdir  
Path(&apos;dir/subdir&apos;).exists()   #True

#当前文件件里面是否存在 pathlib_demo1.py 文件
Path(&quot;pathlib_demo1.py&quot;).exists()  #True
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E8%AE%B0%E5%BD%95re%E6%AD%A3%E5%88%99%E6%A8%A1%E5%9D%97%EF%BC%8C%E6%96%B9%E4%BE%BF%E5%90%8E%E6%9C%9F%E6%9F%A5%E6%89%BE%E4%BD%BF%E7%94%A8.md&quot;&gt;Python 记录re正则模块，方便后期查找使用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97-bisect%EF%BC%8C%E6%95%B0%E7%BB%84%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95.md&quot;&gt;Python 内建模块 bisect，数组二分查找算法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E6%A0%87%E5%87%86%E5%BA%93heapq%EF%BC%8C%E5%A0%86%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%93%8D%E4%BD%9C%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python 标准库heapq，堆数据结构操作详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-math%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python math模块详解&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 记录re正则模块，方便后期查找使用</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E8%AE%B0%E5%BD%95re%E6%AD%A3%E5%88%99%E6%A8%A1%E5%9D%97%EF%BC%8C%E6%96%B9%E4%BE%BF%E5%90%8E%E6%9C%9F%E6%9F%A5%E6%89%BE%E4%BD%BF%E7%94%A8/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E8%AE%B0%E5%BD%95re%E6%AD%A3%E5%88%99%E6%A8%A1%E5%9D%97%EF%BC%8C%E6%96%B9%E4%BE%BF%E5%90%8E%E6%9C%9F%E6%9F%A5%E6%89%BE%E4%BD%BF%E7%94%A8/</guid><description>Python re正则模块</description><pubDate>Tue, 12 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;前言&lt;/h1&gt;
&lt;p&gt;小编第一次了解正则，是在VBA编程时用到，当时看了很多的学习资料，来了解和学习正则。因为现在数据录入、数据存放相对都比较规范，使用正则的场景越来越少，但运用正则在杂乱的数据中提取一些有用数据还是很方便，最近阅读书籍时又看到了正则相关的内容，于是总结了一下，分享出来，供大家参考学习&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;官方文档&lt;/strong&gt;：https://docs.python.org/zh-cn/3/library/re.html&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Excelhome精选正则文章&lt;/strong&gt; &amp;lt;br/&amp;gt;
正则文章：&lt;a href=&quot;https://club.excelhome.net/thread-1128647-1-3.html&quot;&gt;正则表达式入门与提高---VBA平台的正则学习参考资料&lt;/a&gt; &amp;lt;br/&amp;gt;
地址：https://club.excelhome.net/thread-1128647-1-3.html&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;环境与正则库版本&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import sys
import re 

print(&apos;python 版本：&apos;,sys.version.split(&apos;|&apos;)[0])   #python 版本： 3.11.4
print(&apos;re 正则库版本：&apos;,re.__version__)  #re 正则库版本： 2.2.1
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;正则模块中的函数/方法&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;re.compile&lt;/strong&gt;
将正则表达式模式编译为一个正则表达式对象，方便多次使用&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import re

text=&apos;Does this text match the pattern?&apos;
regexes=re.compile(&apos;this&apos;)
print(regexes)   #re.compile(&apos;this&apos;)
print(regexes.search(text))  #&amp;lt;re.Match object; span=(5, 9), match=&apos;this&apos;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;re.search&lt;/strong&gt;
在给定的字符串中 查找/匹配 正则表达式模式，&lt;strong&gt;首次&lt;/strong&gt;出现的位置，如果能匹配到，则返回相应的正则表达式对象；如果匹配不到，则返回 &lt;code&gt;None&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import re

pattern=&apos;this&apos;
text=&apos;Does this text match the text pattern?&apos;

match=re.search(pattern,text)

print(match)  #&amp;lt;re.Match object; span=(5, 9), match=&apos;this&apos;&amp;gt;
print(match.re)  #re.compile(&apos;this&apos;)
print(match.re.pattern)  #this
print(match.string)  #Does this text match the text pattern?
print(match.start())  #5
print(match.end())  #9
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;re.match&lt;/strong&gt;
在给定的字符串&lt;strong&gt;开头&lt;/strong&gt;进行匹配，如果在开头能与给定的正则表达式模式匹配，则返回相应的正则表达式对象；如果匹配不到，则返回 &lt;code&gt;None&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import re

text=&apos;Does this text match the text pattern?&apos;

match1=re.match(&apos;Does&apos;,text)
print(match1)   #&amp;lt;re.Match object; span=(0, 4), match=&apos;Does&apos;&amp;gt;
print(match1.span())  #(0, 4)

match2=re.match(&apos;this&apos;,text)
print(match2)  #None
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;re.fullmatch&lt;/strong&gt;
如果整个字符串需要与给定的正则表达式模式匹配，则返回相应的相应的正则表达式对象；如果匹配不到，则返回 &lt;code&gt;None&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import re

text=&apos;Does this text match the text pattern?&apos;

match1=re.fullmatch(&apos;Does this text match the text pattern\?&apos;,text)
print(match1)   #&amp;lt;re.Match object; span=(0, 38), match=&apos;Does this text match the text pattern?&apos;&amp;gt;

match2=re.fullmatch(&apos;Does this text&apos;,text)
print(match2)  #None


match3=re.fullmatch(&apos;Does .* pattern\?&apos;,text)
print(match3)  #&amp;lt;re.Match object; span=(0, 38), match=&apos;Does this text match the text pattern?&apos;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;re.findall&lt;/strong&gt;
对字符串与给定的正则表达式模式，从左至右进行查找，匹配结果按照找到的顺序进行返回，返回结果是以字符串列表或字符串元组列表的形式，如果匹配不到，返回空列表的形式&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import re

text=&apos;Does this text match the text pattern?&apos;

matches1=re.findall(&apos;text&apos;,text)
print(matches1)   #[&apos;text&apos;, &apos;text&apos;]

matches2=re.findall(&apos;regexes&apos;,text)
print(matches2)   #[]
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;re.finditer&lt;/strong&gt;
与 &lt;code&gt;findall&lt;/code&gt; 方法类似，结果返回的是一个迭代器，并且每个元素是匹配到的正则表达式对象&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import re

text=&apos;Does this text match the text pattern?&apos;

matches1=re.finditer(&apos;text&apos;,text)
print(matches1)  #&amp;lt;callable_iterator object at 0x0000024D0E9018D0&amp;gt;
for match in matches1:
    print(match) 
    #&amp;lt;re.Match object; span=(10, 14), match=&apos;text&apos;&amp;gt;   
    #&amp;lt;re.Match object; span=(25, 29), match=&apos;text&apos;&amp;gt;

matches2=re.findall(&apos;regexes&apos;,text)
print(matches2)  #[]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;本篇文章只介绍了几个常用的方法，重点是方法的含义，而没有介绍元字符相关的内容，如果对正则表达式感兴趣，可以深入学习拓展知识范围&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97-bisect%EF%BC%8C%E6%95%B0%E7%BB%84%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95.md&quot;&gt;Python 内建模块 bisect，数组二分查找算法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E6%A0%87%E5%87%86%E5%BA%93heapq%EF%BC%8C%E5%A0%86%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%93%8D%E4%BD%9C%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python 标准库heapq，堆数据结构操作详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-math%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python math模块详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python%E5%86%85%E7%BD%AE%E7%9A%84-os-%E6%A8%A1%E5%9D%97%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0%E3%80%81%E6%96%B9%E6%B3%95.md&quot;&gt;Python内置的 os 模块常用函数、方法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Hive 中把一行记录拆分为多行记录</title><link>https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive-%E4%B8%AD%E6%8A%8A%E4%B8%80%E8%A1%8C%E8%AE%B0%E5%BD%95%E6%8B%86%E5%88%86%E4%B8%BA%E5%A4%9A%E8%A1%8C%E8%AE%B0%E5%BD%95/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive-%E4%B8%AD%E6%8A%8A%E4%B8%80%E8%A1%8C%E8%AE%B0%E5%BD%95%E6%8B%86%E5%88%86%E4%B8%BA%E5%A4%9A%E8%A1%8C%E8%AE%B0%E5%BD%95/</guid><description>Hive 一行记录拆分为多行记录</description><pubDate>Fri, 04 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;业务场景：统计每个小时视频同时在线观看人数，因后台的业务数据是汇总之后的，只有开始时间、结束时间，没有每小时的详细日志数据，无法直接进行统计，所以需要对每条业务数据进行拆分，来统计每个小时的同时数&lt;/p&gt;
&lt;p&gt;&lt;em&gt;当然，如果有详细的日志数据也是直接可以统计的，但是正常情况下，日志数据会非常大，如果每个用户每30秒会产生一条数据，那么每天会产生大量的数据，如此大量的数据，很难长期保存&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;模拟数据与需求效果展示&lt;/h1&gt;
&lt;p&gt;对每行数据，按每小时进行拆分，结果如下所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-ca2dd9fb8c49c103.png&quot; alt=&quot;模拟数据与需求效果展示&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;创建测试数据&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;--创建临时表
create table test.tmp_datashare
(user_id string comment &apos;用户id&apos;,
start_time string comment &apos;开始时间&apos;,
end_time string comment &apos;结束时间&apos;)
comment &apos;业务数据&apos;
row format delimited fields terminated by &apos;\t&apos; 
lines terminated by &apos;\n&apos;;

--加载数据
load data local inpath &apos;/tmp/datashare.txt&apos; 
overwrite into table test.tmp_datashare;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;测试数据：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-328a0e61c587bacc.png&quot; alt=&quot;测试数据&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;数据处理过程&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据处理的要点：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要借助以下两个函数生成连续序列，然后用开始时间与该序列进行加和，生成相应的结果
&lt;code&gt;space&lt;/code&gt;：空格字符串函数，语法: space(int n)，返回长度为n的空字符串
&lt;code&gt;posexplode&lt;/code&gt;：炸裂函数，会同时返回两个值，数据的下标索引、数据的值&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;具体代码如下：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;左右滑动查看代码&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set hive.cli.print.header=true;

with a as(select user_id,start_time,end_time
		from test.tmp_datashare
		),
	b as(select user_id,start_time,end_time,pos
		from a 
		lateral view posexplode(
			split(
				space(
					cast((unix_timestamp(substr(end_time,1,13),&apos;yyyy-MM-dd HH&apos;)-
							unix_timestamp(substr(start_time,1,13),&apos;yyyy-MM-dd HH&apos;))/3600 as int)), 
				&apos; &apos;)
			) tmp as pos,val
		)
select user_id,start_time,end_time,
from_unixtime(unix_timestamp(start_time,&apos;yyyy-MM-dd HH:mm:ss&apos;)+3600*pos,
	&apos;yyyy-MM-dd HH&apos;) as start_time_every_hh
from b 
order by user_id,start_time_every_hh
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;结果数据：&lt;/strong&gt;
&lt;img src=&quot;./images/6641583-722fa2b75ce69b3e.png&quot; alt=&quot;结果数据&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Hive%E4%B8%AD%E5%AF%B9%E7%9B%B8%E9%82%BB%E8%AE%BF%E9%97%AE%E6%97%B6%E9%97%B4%E8%BF%9B%E8%A1%8C%E5%BD%92%E5%B9%B6%E5%88%86%E7%BB%84.md&quot;&gt;Hive中对相邻访问时间进行归并分组&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive-%E6%95%B0%E6%8D%AE%E8%81%9A%E5%90%88%E6%88%90%E9%94%AE%E5%80%BC%E5%AF%B9%E6%97%B6%EF%BC%8C%E6%A0%B9%E6%8D%AE%E5%80%BC%E5%A4%A7%E5%B0%8F%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F.md&quot;&gt;Hive 数据聚合成键值对时，根据值大小进行排序&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive%E4%B8%AD%E7%9A%84%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0.md&quot;&gt;Hive中的常用函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive%E4%B8%AD%E5%90%84%E7%A7%8D%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E8%BD%AC%E6%8D%A2%E6%96%B9%E6%B3%95%E6%80%BB%E7%BB%93.md&quot;&gt;Hive中各种日期格式转换方法总结&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive---HQL%E6%94%AF%E6%8C%81%E7%9A%842%E7%A7%8D%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E9%A3%8E%E6%A0%BC%EF%BC%8C%E4%BD%A0%E5%96%9C%E6%AC%A2%E5%93%AA%E4%B8%80%E7%A7%8D%EF%BC%9F.md&quot;&gt;Hive HQL支持的2种查询语句风格，你喜欢哪一种？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Excel中的标准差 stdev.S 和 stdev.P 区别</title><link>https://datashare-duo.github.io/datashare-blog/posts/EXCEL%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E4%B8%8EVBA/Excel%E4%B8%AD%E7%9A%84%E6%A0%87%E5%87%86%E5%B7%AEstdev-S%E5%92%8Cstdev-P%E5%8C%BA%E5%88%AB/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/EXCEL%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E4%B8%8EVBA/Excel%E4%B8%AD%E7%9A%84%E6%A0%87%E5%87%86%E5%B7%AEstdev-S%E5%92%8Cstdev-P%E5%8C%BA%E5%88%AB/</guid><description>Excel中2个函数 stdev.S 和 stdev.P 计算标准差</description><pubDate>Fri, 30 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;标准差这个指标在平时使用比较多，主要是用来计算数据的离散程度，在Excel中有相关的函数，可以直接来计算，其他的编程语言里面也有相关的函数。&lt;/p&gt;
&lt;p&gt;Excel中提供了2个函数 stdev.S 和 stdev.P ，都可以用来计算标准差，但这两者应该如何合理使用呢？又有什么区别呢？本篇文章将对这两个函数进行详细的讲解&lt;/p&gt;
&lt;h1&gt;stdev.S和stdev.P区别&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;1、先看微软文档给出的解释&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-c785a27165cb785b.png&quot; alt=&quot;stdev.S&quot; /&gt;
&lt;img src=&quot;./images/6641583-fb590d33f39d80a5.png&quot; alt=&quot;stdev.P&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2、源自网络文章的理解&lt;/strong&gt;
当你只知道一小部分样本，想要通过其 &lt;strong&gt;【估算】&lt;/strong&gt; 这部分 &lt;strong&gt;【样本代表的总体】&lt;/strong&gt; 的 &lt;strong&gt;【标准差】&lt;/strong&gt; ——选择stdev.S（2010版之后叫stdev.S，老版叫stdev。这个S就是sample，样本的意思）&lt;/p&gt;
&lt;p&gt;当你拿到的数据已经是 &lt;strong&gt;整体数据&lt;/strong&gt; 了，想要计算这部分数据精确的标准差——选择stdev.P(2010版之后叫stdev.P，老版叫stdevP。这个P我猜是population，在统计学上有“总体”之意）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3、公式对比&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;stdev.S&lt;/strong&gt; 计算公式：&lt;/p&gt;
&lt;p&gt;$$\sqrt{\frac{\sum(x-\overline{x})^2}{n-1}}$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;stdev.P&lt;/strong&gt; 计算公式：&lt;/p&gt;
&lt;p&gt;$$\sqrt{\frac{\sum(x-\overline{x})^2}{n}}$$&lt;/p&gt;
&lt;p&gt;从计算公式可以看出，唯一的区别就是根号中的分母不一样，这个涉及到自由度的概念（理解起来比较复杂），我们可以直接硬记住这个公式即可&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4、总结&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据是抽取的样本时用stdev.S 【其他编程语言中用的是这个】&lt;/li&gt;
&lt;li&gt;数据是全量时用stdev.P&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E7%94%A8xlwings%E5%BA%93%E5%A4%84%E7%90%86Excel.md&quot;&gt;Python用xlwings库处理Excel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/%E5%83%8Fexcel%E9%80%8F%E8%A7%86%E8%A1%A8%E4%B8%80%E6%A0%B7%E4%BD%BF%E7%94%A8pandas%E9%80%8F%E8%A7%86%E5%87%BD%E6%95%B0.md&quot;&gt;像excel透视表一样使用pandas透视函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E9%80%9A%E8%BF%87%E4%BF%AE%E6%94%B9%E7%B3%BB%E7%BB%9F%E6%B3%A8%E5%86%8C%E8%A1%A8%EF%BC%8C%E5%BC%BA%E5%88%B6%E8%AE%BE%E7%BD%AEExcel%E5%AE%8F%E4%BF%A1%E4%BB%BB%E7%BA%A7%E5%88%AB.md&quot;&gt;Python通过修改系统注册表，强制设置Excel宏信任级别&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Hive 中对相邻访问时间进行归并分组</title><link>https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive%E4%B8%AD%E5%AF%B9%E7%9B%B8%E9%82%BB%E8%AE%BF%E9%97%AE%E6%97%B6%E9%97%B4%E8%BF%9B%E8%A1%8C%E5%BD%92%E5%B9%B6%E5%88%86%E7%BB%84/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive%E4%B8%AD%E5%AF%B9%E7%9B%B8%E9%82%BB%E8%AE%BF%E9%97%AE%E6%97%B6%E9%97%B4%E8%BF%9B%E8%A1%8C%E5%BD%92%E5%B9%B6%E5%88%86%E7%BB%84/</guid><description>Hive 相邻时间进行归并分组</description><pubDate>Wed, 24 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;对用户每天的访问次数进行统计时，需要对用户访问页面相邻的时间间隔小于30分钟归并为一组（算是一次），这样可以统计出用户每天的访问次数（忽略隔天问题）。这个问题如果用python来处理可能比较方便，可以循环遍历每行，进行两两之间的比较。利用Hive来处理数据，劣势就是不能循环遍历不够灵活，但是也能处理，只是过程相对比较复杂&lt;/p&gt;
&lt;h1&gt;模拟数据与预想的效果&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-f3de28f31095115f.png&quot; alt=&quot;归并分组&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;创建测试数据&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;--创建临时表
create table test.tmp_datashare
(user_id string comment &apos;用户id&apos;,
url string comment &apos;网页&apos;,
create_time string comment &apos;访问时间&apos;)
comment &apos;用户访问日志&apos;
row format delimited fields terminated by &apos;\t&apos; lines terminated by &apos;\n&apos;;

--加载数据
load data local inpath &apos;/tmp/datashare.txt&apos; overwrite into table test.tmp_datashare;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;测试数据：&lt;/strong&gt;
&lt;img src=&quot;./images/6641583-03172fd0c8e84a88.png&quot; alt=&quot;测试数据&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;数据处理过程&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据处理的难点：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;1、时间处理需要用到 &lt;code&gt;UNIX_TIMESTAMP&lt;/code&gt; 转换为时间戳&lt;/p&gt;
&lt;p&gt;2、运用窗口函数 &lt;code&gt;LAG&lt;/code&gt; 提取前一行的访问时间&lt;/p&gt;
&lt;p&gt;3、再次运用窗口函数 &lt;code&gt;SUM&lt;/code&gt; 进行归并分组&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;具体代码如下：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;with a as (select user_id,url,create_time,
			lag(create_time,1) over(partition by user_id order by create_time) as last_1_time
		from clwtest.tmp_datashare
	),
	b as (select user_id,url,create_time,
		case 
			when last_1_time is null then 1
			when (unix_timestamp(create_time,&apos;yyyy-MM-dd HH:mm:ss&apos;)-
				unix_timestamp(last_1_time,&apos;yyyy-MM-dd HH:mm:ss&apos;))/60&amp;lt;30 then 0
			else 1
		end as group_tmp
	from a
	),
	c as (select user_id,url,create_time,
		sum(group_tmp) over(partition by user_id order by create_time) as group_id
	from b
	)
select user_id,url,create_time,group_id
from c
order by user_id,create_time

&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;结果数据：&lt;/strong&gt;
&lt;img src=&quot;./images/6641583-97bd8e734f50c3ce.png&quot; alt=&quot;结果数据&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Hive-%E6%95%B0%E6%8D%AE%E8%81%9A%E5%90%88%E6%88%90%E9%94%AE%E5%80%BC%E5%AF%B9%E6%97%B6%EF%BC%8C%E6%A0%B9%E6%8D%AE%E5%80%BC%E5%A4%A7%E5%B0%8F%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F.md&quot;&gt;Hive 数据聚合成键值对时，根据值大小进行排序&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive%E4%B8%AD%E7%9A%84%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0.md&quot;&gt;Hive中的常用函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive%E4%B8%AD%E5%90%84%E7%A7%8D%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E8%BD%AC%E6%8D%A2%E6%96%B9%E6%B3%95%E6%80%BB%E7%BB%93.md&quot;&gt;Hive中各种日期格式转换方法总结&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive---HQL%E6%94%AF%E6%8C%81%E7%9A%842%E7%A7%8D%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E9%A3%8E%E6%A0%BC%EF%BC%8C%E4%BD%A0%E5%96%9C%E6%AC%A2%E5%93%AA%E4%B8%80%E7%A7%8D%EF%BC%9F.md&quot;&gt;Hive HQL支持的2种查询语句风格，你喜欢哪一种？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 内建模块-bisect，数组二分查找算法</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97-bisect%EF%BC%8C%E6%95%B0%E7%BB%84%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%86%85%E5%BB%BA%E6%A8%A1%E5%9D%97-bisect%EF%BC%8C%E6%95%B0%E7%BB%84%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95/</guid><description>Python bisect基础库</description><pubDate>Wed, 10 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;介绍&lt;/h1&gt;
&lt;p&gt;bisect模块提供了一种只针对 &lt;strong&gt;已排序的序列&lt;/strong&gt; 的方法，快速找到插入元素的位置，这个模块使用二分查找算法，算法的时间复杂度相对更低一些，可以用于程序优化提升性能&lt;/p&gt;
&lt;p&gt;官方文档：https://docs.python.org/3/library/bisect.html#module-bisect&lt;/p&gt;
&lt;p&gt;函数分为 &lt;code&gt;bisect&lt;/code&gt;、&lt;code&gt;insort&lt;/code&gt; 两大块&lt;/p&gt;
&lt;h1&gt;各函数详解&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;bisect、bisect_right&lt;/strong&gt;
这两个函数功能一模一样，&lt;code&gt;bisect&lt;/code&gt; 是对 &lt;code&gt;bisect_right&lt;/code&gt; 的引用，用于查找元素在已经排序的序列中应该插入的位置，返回值为最靠右 or 最大的索引位置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;l = [1, 23, 45, 12, 23, 42, 54, 123, 14, 52, 3]
l.sort()

print(l)  #[1, 3, 12, 14, 23, 23, 42, 45, 52, 54, 123]
print(bisect.bisect(l, 3))  #2
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;bisect_left&lt;/strong&gt;
返回值为最靠左 or 最小的索引&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;l = [1, 23, 45, 12, 23, 42, 54, 123, 14, 52, 3]
l.sort()

print(l)  #[1, 3, 12, 14, 23, 23, 42, 45, 52, 54, 123]
print(bisect.bisect_left(l, 3))  #1
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;insort、insort_right&lt;/strong&gt;
这两个函数功能一模一样，&lt;code&gt;insort&lt;/code&gt; 是对 &lt;code&gt;insort_right&lt;/code&gt; 的引用，用于将一个元素插入到已经排序的序列中，并且保持序列的排序状态，插入位置为最靠右 or 最大的索引位置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;l = [1, 23, 45, 12, 23, 42, 54, 123, 14, 52, 3]
l.sort()

print(l)  #[1, 3, 12, 14, 23, 23, 42, 45, 52, 54, 123]

bisect.insort(l, 3.0)
print(l)  #[1, 3, 3.0, 12, 14, 23, 23, 42, 45, 52, 54, 123]
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;insort_left&lt;/strong&gt;
插入位置为最靠左 or 最小的索引位置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;li = [1, 23, 45, 12, 23, 42, 54, 123, 14, 52, 3]
li.sort()

print(li)  #[1, 3, 12, 14, 23, 23, 42, 45, 52, 54, 123]

bisect.insort_left(li, 3.0)
print(li)  #[1, 3.0, 3, 12, 14, 23, 23, 42, 45, 52, 54, 123]
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;官方文档案例&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;def grade(score, breakpoints=[60, 70, 80, 90], grades=&apos;FDCBA&apos;):
    i = bisect.bisect(breakpoints, score)
    return grades[i]

[grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]
#[&apos;F&apos;, &apos;A&apos;, &apos;C&apos;, &apos;C&apos;, &apos;B&apos;, &apos;A&apos;, &apos;A&apos;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python-%E6%A0%87%E5%87%86%E5%BA%93heapq%EF%BC%8C%E5%A0%86%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%93%8D%E4%BD%9C%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python 标准库heapq，堆数据结构操作详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python-math%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python math模块详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python%E5%86%85%E7%BD%AE%E7%9A%84-os-%E6%A8%A1%E5%9D%97%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0%E3%80%81%E6%96%B9%E6%B3%95.md&quot;&gt;Python内置的 os 模块常用函数、方法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 标准库heapq，堆数据结构操作详解</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93heapq%EF%BC%8C%E5%A0%86%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%93%8D%E4%BD%9C%E8%AF%A6%E8%A7%A3/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E6%A0%87%E5%87%86%E5%BA%93heapq%EF%BC%8C%E5%A0%86%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%93%8D%E4%BD%9C%E8%AF%A6%E8%A7%A3/</guid><description>Python heapq基础库</description><pubDate>Fri, 17 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;注：本文章由ChatGPT gpt-3.5-turbo 生成，小编进行略微调整&lt;/em&gt;
&lt;em&gt;提出的问题：heapq详细讲解&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;最近小编在读《Python Cookbook》书籍时，遇到一个新的标准库 &lt;code&gt;heapq&lt;/code&gt;，该库主要涉及堆数据结构，自己之前没有用过，所以就问了一下 ChatGPT，给出的内容非常详细且容易理解，分享出来供大家参考&lt;/p&gt;
&lt;h1&gt;heapq介绍&lt;/h1&gt;
&lt;p&gt;heapq 是 Python 标准库中的一个基于堆的优先队列实现。它提供了一些函数来实现对列表中的元素进行加入、弹出、替换等操作，同时也支持对列表中的元素进行建堆、堆排序等高级功能。本文将详细介绍 heapq 的使用方法和内部实现原理。&lt;/p&gt;
&lt;h1&gt;基本用法&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;1、heapq.heappush 和 heapq.heappop&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;heapq.heappush(lst, item)：将元素 item 加入到列表 lst 中，并保持 lst 始终为一个堆。&lt;/p&gt;
&lt;p&gt;heapq.heappop(lst)：从列表 lst 中弹出最小的元素，并保持 lst 始终为一个堆。&lt;/p&gt;
&lt;p&gt;下面是一个示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import heapq

lst = [10, 30, 2, 20, 50]  # 初始列表
heapq.heapify(lst)        # 建堆
print(lst)                # 输出 [2, 20, 10, 30, 50]

heapq.heappush(lst, 5)    # 将 5 加入到 lst 中
print(lst)                # 输出 [2, 5, 10, 30, 50, 20]

min_item = heapq.heappop(lst)  # 弹出最小元素
print(min_item, lst)           # 输出 2 [5, 20, 10, 30, 50]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2、heapq.heapreplace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;heapq.heapreplace(lst, item)：将最小元素替换为 item，并保持 lst 始终为一个堆。&lt;/p&gt;
&lt;p&gt;这个函数相当于先执行 heapq.heappop(lst)，再执行 heapq.heappush(lst, item)。使用该函数可以避免在先弹出再加入元素时，列表中出现不合法的状态。例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import heapq

lst = [10, 30, 2, 20, 50]   # 初始列表
heapq.heapify(lst)          # 建堆
print(lst)                  # 输出 [2, 20, 10, 30, 50]

heapq.heapreplace(lst, 5)   # 用 5 替换最小元素 2
print(lst)                  # 输出 [5, 20, 10, 30, 50]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3、heapq.nlargest 和 heapq.nsmallest&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;heapq.nlargest(n, lst)：返回列表 lst 中前 n 个最大的元素，按照从大到小的顺序排序。&lt;/p&gt;
&lt;p&gt;heapq.nsmallest(n, lst)：返回列表 lst 中前 n 个最小的元素，按照从小到大的顺序排序。&lt;/p&gt;
&lt;p&gt;这两个函数的实现都是先使用 heapq.heappush 和 heapq.heappop 对列表进行处理，之后返回前 n 个元素。示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import heapq

lst = [10, 30, 2, 20, 50]  # 初始列表
heapq.heapify(lst)        # 建堆
print(lst)                # 输出 [2, 20, 10, 30, 50]

print(heapq.nlargest(3, lst))  # 输出 [50, 30, 20]
print(heapq.nsmallest(3, lst)) # 输出 [2, 10, 20]
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;内部实现原理&lt;/h1&gt;
&lt;p&gt;Heap 是一种树形数据结构，通常用二叉树来实现。堆树的最上面是根节点，根节点下面的每个节点都比它自己所有的子节点都大（称为大根堆）或者都小（称为小根堆）。根据这个性质，堆树可以快速地找到最大或者最小元素。&lt;/p&gt;
&lt;p&gt;Python 中的 heapq 模块实现是使用了一种叫做“二叉堆”的数据结构。二叉堆由固定数量的元素组成，堆的根节点包含所有能够在其中的元素中具有最小或者最大关键字的元素。我们称这个根节点为“最小堆”或者“最大堆”。堆中的每一个其他的节点都符合堆的性质：最小堆中的每一个节点都比它的子节点小；最大堆中的每一个节点都比它的子节点大。&lt;/p&gt;
&lt;p&gt;这种数据结构可以直接用一个数组来实现，每个元素在数组中顺序存储，并按照堆的性质排列。数组的第一个元素是根节点，也就是堆的最小或最大元素。根据元素在数组中的位置，可以快速地用简单的数学运算找到它的子节点和父节点&lt;/p&gt;
&lt;p&gt;二叉堆分为两种类型：最小堆和最大堆。在 Python 中的 heapq 模块中使用最小堆&lt;/p&gt;
&lt;p&gt;Python 中，可以以列表的形式存储二叉堆，将列表作为二叉树，树的根节点即为第一个元素，树的子节点为列表中其左右孩子。具体来说，以第 k 个节点为例，其左孩子为第 2k+1 个节点，右孩子为第 2k+2 个节点，其父节点为第(k-1)//2 个节点&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;通过使用 heapq 模块提供的高效的堆算法，可以快速地实现对列表中元素的排序、寻找最大/最小值等常见操作&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Python-math%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3.md&quot;&gt;Python math模块详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python%E5%86%85%E7%BD%AE%E7%9A%84-os-%E6%A8%A1%E5%9D%97%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0%E3%80%81%E6%96%B9%E6%B3%95.md&quot;&gt;Python内置的 os 模块常用函数、方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E5%8A%A0%E8%BD%BDtxt%E6%95%B0%E6%8D%AE%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98%E5%8D%87%E7%BA%A7%E7%89%88%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md&quot;&gt;Python加载txt数据乱码问题升级版解决方法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Hive 中的各种常用set设置</title><link>https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive-%E4%B8%AD%E7%9A%84%E5%90%84%E7%A7%8D%E5%B8%B8%E7%94%A8set%E8%AE%BE%E7%BD%AE/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive-%E4%B8%AD%E7%9A%84%E5%90%84%E7%A7%8D%E5%B8%B8%E7%94%A8set%E8%AE%BE%E7%BD%AE/</guid><description>Hive 常用set设置</description><pubDate>Wed, 23 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;平时在跑数据时，需要在查询语句前设置一些set语句，这些set语句中其中有一些是配置hive的各功能，另一些是可以达到优化的目的，本篇文章对一些常用的set语句进行总结&lt;/p&gt;
&lt;h1&gt;常用set设置&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;查询结果显示表头&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;执行完查询语句，输出结果时，会一起把字段的名字也打印出来&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set hive.cli.print.header=true;  --默认为false，不打印表头
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;展示当前使用的数据库&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;主要是在命令行模式中使用，方便核查是否切换到相应的数据库下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set hive.cli.print.current.db=true;  --默认为false，不显示当前数据库名字
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;设置是否使用元数据中的统计信息&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如想要看数据一共有多少行的话，一般是从元数据中的统计信息直接获取，但有时这个统计信息没有更新，得到的是历史的统计信息，则需要修改为 &lt;code&gt;false&lt;/code&gt;，然后再进行查询，才能统计出准确的数据&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set hive.compute.query.using.stats=false;   --默认为true，使用元数据中的统计信息，提升查询效率
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;设置Fetch抓取，不走job，不用执行MapReduce&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一般用于快速获取样例数据，&lt;code&gt;select * from talbe_xxx limit 100&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set hive.fetch.task.conversion=more;  
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;设置查询任取走哪个队列&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一般公司的服务器集群中会配置好几个队列，不同的队列优先级不一样，并且资源配置有可能不一样，生产环境的任务肯定优先级高、计算资源多，数据分析的任务一般是单独的队列，计算资源少&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set mapreduce.job.queuename=root.db;   --运维人员设置的队列名字
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;是否开启严格模式&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一般运维人员会设置为严格模式 &lt;code&gt;strict&lt;/code&gt;，防止大量数据计算占用资源，多出现在笛卡尔积join时；或者查询的是分区表，但没有指定分区，明明sql语句没有逻辑错误，但是一直报错无法运行，可以尝试修改为非严格模式，看是否能运行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set hive.mapred.mode=nonstrict;    --nonstrict，strict   
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;with as 语句存储在本地，从而做到with…as语句只执行一次，来提高效率&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对应喜欢用 &lt;code&gt;with as&lt;/code&gt; 形式查询的话，可以设置一下这个，来提升效率&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set hive.optimize.cte.materialize.threshold=1;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;配置计算引擎&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hive底层的计算由分布式计算框架实现,目前支持三种计算引擎，分别是MapReduce、Tez、 Spark，默认为MapReduce&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;MapReduce引擎&lt;/strong&gt;：多job串联，基于磁盘，落盘的地方比较多。虽然慢，但一定能跑出结果。一般处理，周、月、年指标。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spark引擎&lt;/strong&gt;：虽然在Shuffle过程中也落盘，但是并不是所有算子都需要Shuffle，尤其是多算子过程，中间过程不落盘 DAG有向无环图。 兼顾了可靠性和效率。一般处理天指标。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tez引擎&lt;/strong&gt;：完全基于内存。 注意：如果数据量特别大，慎重使用。容易OOM。一般用于快速出结果，数据量比较小的场景。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;set hive.execution.engine=mr;    --mr、tez、spark
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;其他set设置&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;set hive.exec.parallel=true;    --开启任务并行执行 
set hive.exec.parallel.thread.number=8;   -- 同一个sql允许并行任务的最大线程数
set hive.exec.max.dynamic.partitions=1000           -- 在所有执行MR的节点上，最大一共可以创建多少个动态分区。
set hive.exec.max.dynamic.partitions.pernode=100   -- 在每个执行MR的节点上，最大可以创建多少个动态分区
set hive.auto.convert.join = false;    --取消小表加载至内存中
set hive.mapjoin.smalltable.filesize=25000000;   --设置小表大小
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Hive-%E6%95%B0%E6%8D%AE%E8%81%9A%E5%90%88%E6%88%90%E9%94%AE%E5%80%BC%E5%AF%B9%E6%97%B6%EF%BC%8C%E6%A0%B9%E6%8D%AE%E5%80%BC%E5%A4%A7%E5%B0%8F%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F.md&quot;&gt;Hive 数据聚合成键值对时，根据值大小进行排序&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive%E4%B8%AD%E7%9A%84%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0.md&quot;&gt;Hive中的常用函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive%E4%B8%AD%E5%90%84%E7%A7%8D%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E8%BD%AC%E6%8D%A2%E6%96%B9%E6%B3%95%E6%80%BB%E7%BB%93.md&quot;&gt;Hive中各种日期格式转换方法总结&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive---HQL%E6%94%AF%E6%8C%81%E7%9A%842%E7%A7%8D%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E9%A3%8E%E6%A0%BC%EF%BC%8C%E4%BD%A0%E5%96%9C%E6%AC%A2%E5%93%AA%E4%B8%80%E7%A7%8D%EF%BC%9F.md&quot;&gt;Hive HQL支持的2种查询语句风格，你喜欢哪一种？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Hive 数据聚合成键值对时，根据值大小进行排序</title><link>https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive-%E6%95%B0%E6%8D%AE%E8%81%9A%E5%90%88%E6%88%90%E9%94%AE%E5%80%BC%E5%AF%B9%E6%97%B6%EF%BC%8C%E6%A0%B9%E6%8D%AE%E5%80%BC%E5%A4%A7%E5%B0%8F%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive-%E6%95%B0%E6%8D%AE%E8%81%9A%E5%90%88%E6%88%90%E9%94%AE%E5%80%BC%E5%AF%B9%E6%97%B6%EF%BC%8C%E6%A0%B9%E6%8D%AE%E5%80%BC%E5%A4%A7%E5%B0%8F%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F/</guid><description>Hive 数据排序</description><pubDate>Thu, 17 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;最近对用户的行为数据进行统计分析时，需要列出不同用户的具体详情，方便进行观察，在hive中虽然有排序函数，但是处理键值对数据时，不能根据值进行排序，需要巧妙借助中间过程来处理，总结出来与大家进行分享，也方便后面自己查找使用&lt;/p&gt;
&lt;h1&gt;预想效果&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-35ef6a6cc9cfc362.webp&quot; alt=&quot;键值对排序&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;创建测试数据&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;--创建临时表
use test;
create table tmp_datashare
(id string comment &apos;用户id&apos;,
click string comment &apos;点击位置&apos;,
cnt int comment &apos;点击次数&apos;)
COMMENT &apos;用户点击行为统计&apos;
ROW FORMAT DELIMITED FIELDS TERMINATED BY &apos;\t&apos; LINES TERMINATED BY &apos;\n&apos;;

--加载数据
load data local inpath &apos;/tmp/datashare.txt&apos; overwrite into table tmp_datashare;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;测试数据：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-87b347576a9c9041.webp&quot; alt=&quot;测试数据&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;数据处理过程&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;数据处理具体步骤：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;运用窗口函数进行降序排列增加一个添加辅助列&lt;/li&gt;
&lt;li&gt;对数据进行拼接并补全数字，比如：id_1中 &lt;code&gt;首页：20，降序序号：2&lt;/code&gt;，需要转换为 &lt;code&gt;00002:首页:20&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;然后再进行分组聚合运用&lt;code&gt;sort_array&lt;/code&gt;进行排序，并进行拼接&lt;/li&gt;
&lt;li&gt;最后再进行替换&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;具体代码如下：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;with a as (select id,click,cnt,
			row_number() over(partition by id order by cnt desc) as rn
		from tmp_datashare
			),
	b as (select id,click,cnt,
			concat(lpad(rn, 5, &apos;0&apos;), &apos;#&apos;, click, &apos;:&apos;,cnt) as click_cnt_temp_1
		from a
		),
	c as (select id,
			concat_ws(&apos;;&apos;,
				sort_array(collect_list(click_cnt_temp_1))
				) as click_cnt_temp_2
		from b
		group by id
		)
select id,regexp_replace(click_cnt_temp_2,&apos;\\d+#&apos;,&apos;&apos;) as click_cnt
from c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;结果数据：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-4b5516695d911ee4.webp&quot; alt=&quot;结果数据&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Hive%E4%B8%AD%E7%9A%84%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0.md&quot;&gt;Hive中的常用函数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive%E4%B8%AD%E5%90%84%E7%A7%8D%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E8%BD%AC%E6%8D%A2%E6%96%B9%E6%B3%95%E6%80%BB%E7%BB%93.md&quot;&gt;Hive中各种日期格式转换方法总结&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive---HQL%E6%94%AF%E6%8C%81%E7%9A%842%E7%A7%8D%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E9%A3%8E%E6%A0%BC%EF%BC%8C%E4%BD%A0%E5%96%9C%E6%AC%A2%E5%93%AA%E4%B8%80%E7%A7%8D%EF%BC%9F.md&quot;&gt;Hive HQL支持的2种查询语句风格，你喜欢哪一种？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Hive 中的常用函数</title><link>https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive%E4%B8%AD%E7%9A%84%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive%E4%B8%AD%E7%9A%84%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0/</guid><description>Hive 常用函数</description><pubDate>Thu, 11 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;现阶段各个公司的数据慢慢的增多，很多数据都是存放在基于Hadoop的集群上，数据的查询一般使用的是hive，很多公司的数据中台也是使用hive来进行数据处理，本篇文章就来分享下在hive中常用的函数&lt;/p&gt;
&lt;h1&gt;常用函数&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;set类设置&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查询结果显示表头&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;set hive.cli.print.header=true;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设置Fetch抓取，不走job&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;set hive.fetch.task.conversion=more;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;展示数据库&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;set hive.cli.print.current.db=true;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修改是否使用静默&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;set hive.compute.query.using.stats=false;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;日期类函数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当天&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select current_date()
运行结果：&apos;2022-08-11&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;当月第一天&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select trunc(current_date(),&apos;MM&apos;)      
运行结果：&apos;2022-08-01&apos;
select date_format(to_date(trunc(current_date(),&apos;MM&apos;)),&quot;yyyyMMdd&quot;) 
运行结果：&apos;20220801&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;当月最后一天&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select last_day(current_date)  
运行结果：&apos;2022-08-31&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;上个月&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select date_format(add_months(CURRENT_DATE,-1),&apos;yyyyMM&apos;)
运行结果：&apos;202207&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;周几&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select pmod(datediff(current_date(),&apos;1900-01-08&apos;),7)+1
运行结果：&apos;4&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;获取当前时间戳&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select unix_timestamp()
运行结果：&apos;1660212154&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;字符串类函数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字符拼接&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;--concat（参数1,参数2,...参数n）
select concat(&apos;a&apos;,&apos;b&apos;,&apos;c&apos;)
运行结果：&apos;abc&apos;

select concat(&apos;a&apos;,&apos;b&apos;,null,&apos;c&apos;)   --包含一个null的话，结果为null
运行结果：NULL
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;字符以分割符进行拼接&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;--concat_ws(分隔符,参数1,参数2,...参数n)
select concat_ws(&apos;,&apos;,&apos;a&apos;,&apos;b&apos;,&apos;c&apos;)
运行结果：&apos;a,b,c&apos;

select concat_ws(&apos;,&apos;,&apos;a&apos;,null,&apos;c&apos;)   --会忽略null
运行结果：&apos;a,c&apos;

select concat_ws(&apos;,&apos;,null,null,null)  --返回空字符，而不是null
运行结果：&apos;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;窗口类函数&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ROW_NUMBER() –从1开始，按照顺序，生成分组内记录的序列&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RANK() 生成数据项在分组中的排名，排名相等会在名次中留下空位&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DENSE_RANK() 生成数据项在分组中的排名，排名相等会在名次中不会留下空位&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LAG(col,n,DEFAULT) 用于统计窗口内往上第n行值
第一个参数为列名，第二个参数为往上第n行（可选，默认为1），第三个参数为默认值（当往上第n行为NULL时候，取默认值，如不指定，则为NULL）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LEAD(col,n,DEFAULT) 用于统计窗口内往下第n行值
第一个参数为列名，第二个参数为往下第n行（可选，默认为1），第三个参数为默认值（当往下第n行为NULL时候，取默认值，如不指定，则为NULL）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;更多窗口函数可参考&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;《Hive分析函数系列文章》：&amp;lt;br/&amp;gt;
&lt;a href=&quot;http://lxw1234.com/archives/2015/07/367.htm&quot;&gt;http://lxw1234.com/archives/2015/07/367.htm&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Hive%E4%B8%AD%E5%90%84%E7%A7%8D%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E8%BD%AC%E6%8D%A2%E6%96%B9%E6%B3%95%E6%80%BB%E7%BB%93.md&quot;&gt;Hive中各种日期格式转换方法总结&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Hive---HQL%E6%94%AF%E6%8C%81%E7%9A%842%E7%A7%8D%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E9%A3%8E%E6%A0%BC%EF%BC%8C%E4%BD%A0%E5%96%9C%E6%AC%A2%E5%93%AA%E4%B8%80%E7%A7%8D%EF%BC%9F.md&quot;&gt;Hive HQL支持的2种查询语句风格，你喜欢哪一种？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 中一个好用的地址解析工具cpca（chinese_province_city_area_mapper）</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E4%B8%AD%E4%B8%80%E4%B8%AA%E5%A5%BD%E7%94%A8%E7%9A%84%E5%9C%B0%E5%9D%80%E8%A7%A3%E6%9E%90%E5%B7%A5%E5%85%B7cpca%EF%BC%88chinese_province_city_area_mapper%EF%BC%89/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E4%B8%AD%E4%B8%80%E4%B8%AA%E5%A5%BD%E7%94%A8%E7%9A%84%E5%9C%B0%E5%9D%80%E8%A7%A3%E6%9E%90%E5%B7%A5%E5%85%B7cpca%EF%BC%88chinese_province_city_area_mapper%EF%BC%89/</guid><description>Python 地址解析工具</description><pubDate>Wed, 16 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;简介&lt;/h1&gt;
&lt;p&gt;gihub地址：
&lt;a href=&quot;https://github.com/DQinYuan/chinese_province_city_area_mapper&quot;&gt;https://github.com/DQinYuan/chinese_province_city_area_mapper&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cpca&lt;/code&gt;---chinese province city area，&lt;strong&gt;一个用于提取简体中文字符串中省，市和区并能够进行映射，检验和简单绘图的python模块&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[&quot;徐汇区虹漕路461号58号楼5楼&quot;, &quot;泉州市洛江区万安塘西工业区&quot;] &amp;lt;br/&amp;gt;
↓ &amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;省&lt;/th&gt;
&lt;th&gt;市&lt;/th&gt;
&lt;th&gt;区&lt;/th&gt;
&lt;th&gt;地址&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;上海市&lt;/td&gt;
&lt;td&gt;上海市&lt;/td&gt;
&lt;td&gt;徐汇区&lt;/td&gt;
&lt;td&gt;虹漕路461号58号楼5楼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;福建省&lt;/td&gt;
&lt;td&gt;泉州市&lt;/td&gt;
&lt;td&gt;洛江区&lt;/td&gt;
&lt;td&gt;万安塘西工业区&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;“地址”列：代表去除了省市区之后的具体地址&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;安装介绍&lt;/h1&gt;
&lt;p&gt;该库目前仅支持Python3，在命令行直接进行安装即可：
&lt;code&gt;pip install cpca&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;windows 中需要C/C++编译环境的支持&lt;/strong&gt;，需要下载另外的软件，然后再进行安装
http://go.microsoft.com/fwlink/?LinkId=691126&lt;/p&gt;
&lt;p&gt;编译环境的安装教程：
https://o7planning.org/11467/install-microsoft-visual-cpp-build-tools&lt;/p&gt;
&lt;h1&gt;基本使用方法&lt;/h1&gt;
&lt;h4&gt;常规用法&lt;/h4&gt;
&lt;p&gt;会自动补全相应的省、市、区&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-c7be7d3c8c3e82d8.webp&quot; alt=&quot;常规用法&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import cpca

location_str = [&quot;徐汇区虹漕路461号58号楼5楼&quot;, 
                &quot;泉州市洛江区万安塘西工业区&quot;, 
                &quot;北京朝阳区北苑华贸城&quot;]

data=cpca.transform(location_str)

data

l=[&apos;灵宝市函谷关镇&apos;]

df = cpca.transform(l)
df

df.loc[0,&quot;市&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;h4&gt;重名情况&lt;/h4&gt;
&lt;p&gt;中国的区级行政单位非常的多，经常有重名的情况，比如“北京市朝阳区”和“吉林省长春市朝阳区”，当有上级地址信息的时候，cpca 能够根据上级地址 推断出这是哪个区，但是如果没有上级地址信息，单纯只有一个区名的时候， cpca 就没法推断了，只能随便选一个了， 通过 umap 参数你可以指定这种情况下该选择哪一个&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-e76c3f6056b4e95c.webp&quot; alt=&quot;重名情况&quot; /&gt;&lt;/p&gt;
&lt;p&gt;从例子可以看出，umap 字典的 key 是区名，value 是区的 adcode，这里 &lt;code&gt;110105&lt;/code&gt; 就是北京市朝阳区的 adcode，具体的 adcode 可以去全国行政区划查询平台上查询&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;全国行政区划查询平台：&lt;/strong&gt; http://xzqh.mca.gov.cn/map&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96/Python-%E5%9F%BA%E4%BA%8Epyecharts%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%8F%E7%BA%AC%E5%BA%A6%E7%83%AD%E5%8A%9B%E5%9B%BE%E5%8F%AF%E8%A7%86%E5%8C%96.md&quot;&gt;Python 基于pyecharts自定义经纬度热力图可视化&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/%E5%88%A9%E7%94%A8Python%E8%AE%A1%E7%AE%97%E4%B8%A4%E4%B8%AA%E5%9C%B0%E7%90%86%E4%BD%8D%E7%BD%AE%E4%B9%8B%E9%97%B4%E7%9A%84%E4%B8%AD%E7%82%B9.md&quot;&gt;利用Python计算两个地理位置之间的中点&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>SecureCRT 利用Python脚本自动登陆服务器，自动验证Google-Authenticator动态验证码</title><link>https://datashare-duo.github.io/datashare-blog/posts/Linux/SecureCRT%E5%88%A9%E7%94%A8Python%E8%84%9A%E6%9C%AC%E8%87%AA%E5%8A%A8%E7%99%BB%E9%99%86%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E8%87%AA%E5%8A%A8%E9%AA%8C%E8%AF%81Google-Authenticator%E5%8A%A8%E6%80%81%E9%AA%8C%E8%AF%81%E7%A0%81/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Linux/SecureCRT%E5%88%A9%E7%94%A8Python%E8%84%9A%E6%9C%AC%E8%87%AA%E5%8A%A8%E7%99%BB%E9%99%86%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E8%87%AA%E5%8A%A8%E9%AA%8C%E8%AF%81Google-Authenticator%E5%8A%A8%E6%80%81%E9%AA%8C%E8%AF%81%E7%A0%81/</guid><description>Linux 利用Python脚本自动登陆服务器</description><pubDate>Tue, 18 Jan 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;本地连接远端的服务器，SecureCRT可以说是一大利器，可以保存密码、设置自动登陆等，每次都可以一键直连服务器&lt;/p&gt;
&lt;p&gt;最近因公司加强了服务器登陆验证，增加了二次认证，必须用Google Authenticator输入6位动态验证码，才能成功登陆，这样的话每次都得打开手机，手动输入验证码比较麻烦&lt;/p&gt;
&lt;p&gt;在 &lt;strong&gt;Python&lt;/strong&gt; 中有这样的库 &lt;strong&gt;&lt;code&gt;pyotp&lt;/code&gt;&lt;/strong&gt; 可以直接生成Google Authenticator输入6位动态验证码，前提是你知道谷歌验证码对应的密钥，一般是在最开始让扫描二维的下方会提示出来
&lt;img src=&quot;./images/6641583-9f8fb33899255edd.webp&quot; alt=&quot;密钥&quot; /&gt;&lt;/p&gt;
&lt;p&gt;SecureCRT支持利用一些语言脚本来实现自动登陆，比如：python、vbs，本篇文章来介绍如何利用 &lt;strong&gt;python&lt;/strong&gt; 脚本自动登陆
&lt;img src=&quot;./images/6641583-e934a70f3e36ab52.webp&quot; alt=&quot;登陆动作&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;SecureCRT版本&lt;/h1&gt;
&lt;p&gt;电脑为Win10操作系统&lt;/p&gt;
&lt;p&gt;SecureCRT版本：Version 6.7.0 (build 153)&lt;/p&gt;
&lt;p&gt;SecureCRT中的python版本：python2.6   （可以在安装文件里面查看到）&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-efcf26b29721bf65.webp&quot; alt=&quot;SecureCRT版本&quot; /&gt;
&lt;img src=&quot;./images/6641583-3d29d04307c1aa48.webp&quot; alt=&quot;支持python版本&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;由于没有更新SecureCRT版本，一直用的老版本，支持的python也算是比较老了！！！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最新的SecureCRT版本是支持python3，但是需要进行一些设置，相对比较麻烦，感兴趣的话可以看看这篇文章：&lt;/p&gt;
&lt;p&gt;《How-To: Use Python 3.8 with SecureCRT v9.0 for Windows》&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://forums.vandyke.com/showthread.php?t=14295&quot;&gt;https://forums.vandyke.com/showthread.php?t=14295&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;遇到问题&lt;/h1&gt;
&lt;p&gt;参考网上分享的一些例子，在 &lt;code&gt;import pyotp&lt;/code&gt; 时总是会报错&lt;/p&gt;
&lt;p&gt;《python 实现 jumpserver 自动登录》&amp;lt;br/&amp;gt;
&lt;a href=&quot;https://mp.weixin.qq.com/s/aLazW8WUVfvsICnHXes3CA&quot;&gt;https://mp.weixin.qq.com/s/aLazW8WUVfvsICnHXes3CA&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-5bb1acb71ad6588a.webp&quot; alt=&quot;报错&quot; /&gt;&lt;/p&gt;
&lt;p&gt;即使添加了python包路径也不行，一直报错，&lt;code&gt;pyotp&lt;/code&gt; 是兼容python2、python3所有版本&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-441b387ecdec557e.webp&quot; alt=&quot;添加路径&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;解决方法&lt;/h1&gt;
&lt;p&gt;通过提示可以看出，&lt;code&gt;import sys&lt;/code&gt; 时并没有报错，说明python内置的包，是可以直接导入使用的，经过测试把 &lt;code&gt;pyotp&lt;/code&gt; 源码中涉及到生成动态码的库import时，没有报错，说明已经走通了&lt;/p&gt;
&lt;p&gt;这时就需要剖析 &lt;code&gt;pyotp&lt;/code&gt; 源码，有哪些是生成生成动态码必须的，把冗余的代码全部剔除即可，经过分析也就是两个类有用，如下所示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class OTP(object):
    def __init__(self, s, digits=6, digest= hashlib.sha1, name= None,issuer= None):
        self.digits = digits
        self.digest = digest
        self.secret = s
        self.name = name or &apos;Secret&apos;
        self.issuer = issuer
        
    def generate_otp(self, input):
        if input &amp;lt; 0:
            raise ValueError(&apos;input must be positive integer&apos;)
        hasher = hmac.new(self.byte_secret(), self.int_to_bytestring(input), self.digest)
        hmac_hash = bytearray(hasher.digest())
        offset = hmac_hash[-1] &amp;amp; 0xf
        code = ((hmac_hash[offset] &amp;amp; 0x7f) &amp;lt;&amp;lt; 24 |
                (hmac_hash[offset + 1] &amp;amp; 0xff) &amp;lt;&amp;lt; 16 |
                (hmac_hash[offset + 2] &amp;amp; 0xff) &amp;lt;&amp;lt; 8 |
                (hmac_hash[offset + 3] &amp;amp; 0xff))
        str_code = str(code % 10 ** self.digits)
        while len(str_code) &amp;lt; self.digits:
            str_code = &apos;0&apos; + str_code

        return str_code

    def byte_secret(self):
        secret = self.secret
        missing_padding = len(secret) % 8
        if missing_padding != 0:
            secret += &apos;=&apos; * (8 - missing_padding)
        return base64.b32decode(secret, casefold=True)

    @staticmethod
    def int_to_bytestring(i, padding= 8):
        result = bytearray()
        while i != 0:
            result.append(i &amp;amp; 0xFF)
            i &amp;gt;&amp;gt;= 8
        # It&apos;s necessary to convert the final result from bytearray to bytes
        # because the hmac functions in python 2.6 and 3.3 don&apos;t work with
        # bytearray
        return bytes(bytearray(reversed(result)).rjust(padding, b&apos;\0&apos;))
        
        
class TOTP(OTP):
    def __init__(self, s, digits= 6, digest=hashlib.sha1, name=None,issuer=None, interval= 30):
        self.interval = interval
        super(TOTP,self).__init__(s=s, digits=digits, digest=digest, name=name, issuer=issuer)

    def now(self):
        return self.generate_otp(self.timecode(datetime.datetime.now()))

    def timecode(self, for_time):
        if for_time.tzinfo:
            return int(calendar.timegm(for_time.utctimetuple()) / self.interval)
        else:
            return int(time.mktime(for_time.timetuple()) / self.interval)
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;完整代码&lt;/h1&gt;
&lt;p&gt;以下为SecureCRT利用Python脚本自动登陆服务器的完整代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# $language = &quot;Python&quot;
# $interface = &quot;1.0&quot;

import calendar
import datetime
import hashlib
import time
import base64
import hmac

class OTP(object):
    def __init__(self, s, digits=6, digest= hashlib.sha1, name= None,issuer= None):
        self.digits = digits
        self.digest = digest
        self.secret = s
        self.name = name or &apos;Secret&apos;
        self.issuer = issuer
        
    def generate_otp(self, input):
        if input &amp;lt; 0:
            raise ValueError(&apos;input must be positive integer&apos;)
        hasher = hmac.new(self.byte_secret(), self.int_to_bytestring(input), self.digest)
        hmac_hash = bytearray(hasher.digest())
        offset = hmac_hash[-1] &amp;amp; 0xf
        code = ((hmac_hash[offset] &amp;amp; 0x7f) &amp;lt;&amp;lt; 24 |
                (hmac_hash[offset + 1] &amp;amp; 0xff) &amp;lt;&amp;lt; 16 |
                (hmac_hash[offset + 2] &amp;amp; 0xff) &amp;lt;&amp;lt; 8 |
                (hmac_hash[offset + 3] &amp;amp; 0xff))
        str_code = str(code % 10 ** self.digits)
        while len(str_code) &amp;lt; self.digits:
            str_code = &apos;0&apos; + str_code

        return str_code

    def byte_secret(self):
        secret = self.secret
        missing_padding = len(secret) % 8
        if missing_padding != 0:
            secret += &apos;=&apos; * (8 - missing_padding)
        return base64.b32decode(secret, casefold=True)

    @staticmethod
    def int_to_bytestring(i, padding= 8):
        result = bytearray()
        while i != 0:
            result.append(i &amp;amp; 0xFF)
            i &amp;gt;&amp;gt;= 8
        # It&apos;s necessary to convert the final result from bytearray to bytes
        # because the hmac functions in python 2.6 and 3.3 don&apos;t work with
        # bytearray
        return bytes(bytearray(reversed(result)).rjust(padding, b&apos;\0&apos;))
        
        
class TOTP(OTP):
    def __init__(self, s, digits= 6, digest=hashlib.sha1, name=None,issuer=None, interval= 30):
        self.interval = interval
        super(TOTP,self).__init__(s=s, digits=digits, digest=digest, name=name, issuer=issuer)

    def now(self):
        return self.generate_otp(self.timecode(datetime.datetime.now()))

    def timecode(self, for_time):
        if for_time.tzinfo:
            return int(calendar.timegm(for_time.utctimetuple()) / self.interval)
        else:
            return int(time.mktime(for_time.timetuple()) / self.interval)

username=&apos;aaa&apos;
password=&apos;aaa&apos;
google_author_secret_key=&apos;自己的密钥&apos;

def Main():
    tab = crt.GetScriptTab()
    if tab.Session.Connected != True:
        crt.Dialog.MessageBox(&quot;Session Not Connected&quot;)
        return
    tab.Screen.Synchronous = True
    
   
    tab.Screen.WaitForStrings([&apos;Password: &apos;])
    tab.Screen.Send(password+&apos;\r\n&apos;)
    tab.Screen.WaitForStrings([&apos;Please enter 6 digits.[MFA auth]: &apos;])
    vc = TOTP(google_author_secret_key).now()
    tab.Screen.Send(&quot;{vc}\r\n&quot;.format(vc=vc))
    
    return


Main()

&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E5%B8%88%E5%B8%B8%E7%94%A8%E7%9A%84-Linux-%E5%91%BD%E4%BB%A4%E6%80%BB%E7%BB%93.md&quot;&gt;数据分析师常用的 Linux 命令总结&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%9F%BA%E4%BA%8Essh%E8%BF%9E%E6%8E%A5%E8%BF%9C%E7%A8%8BMysql%E6%95%B0%E6%8D%AE%E5%BA%93.md&quot;&gt;Python 基于ssh连接远程Mysql数据库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Linux-%EF%BC%88Centos-7%EF%BC%89%E4%B8%AD-Anaconda%E7%8E%AF%E5%A2%83%E7%AE%A1%E7%90%86%EF%BC%8C%E5%AE%89%E8%A3%85%E4%B8%8D%E5%90%8C%E7%9A%84%E7%89%88%E6%9C%ACPython%E5%8C%85.md&quot;&gt;Linux （Centos 7）中 Anaconda环境管理，安装不同的版本Python包&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>数据分析师常用的-Linux-命令总结</title><link>https://datashare-duo.github.io/datashare-blog/posts/Linux/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E5%B8%88%E5%B8%B8%E7%94%A8%E7%9A%84-Linux-%E5%91%BD%E4%BB%A4%E6%80%BB%E7%BB%93/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Linux/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E5%B8%88%E5%B8%B8%E7%94%A8%E7%9A%84-Linux-%E5%91%BD%E4%BB%A4%E6%80%BB%E7%BB%93/</guid><description>Linux 数据分析师常用命令</description><pubDate>Fri, 05 Nov 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;也许你有这样的疑问，数据分析师为什么要了解Linux？这不是开发人员应该了解的吗？把Windows+SQL+Excel+Python玩的精通，不香吗？&lt;/p&gt;
&lt;p&gt;以上的疑问也许处有人会提出，但随着个人的职业成长，企业数字化的发展，终究会与Linux系统打交道，比如：在数据挖掘时，大量的数据需要做分析、特征提取，然后跑模型，这些任务在个人的Windows系统基本完全做不了，只能在Linux服务器上来完成&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;备注&lt;/strong&gt;：在大厂就职的同学  and 公司基建做的非常好的，可以忽略本文，说明你们公司比本小编曾经就职的某手好点，当然多学习一些知识，对自己百利而无一害，活到老学到老&lt;/p&gt;
&lt;p&gt;&lt;em&gt;以下介绍的命令是基于： &lt;strong&gt;Centos系统&lt;/strong&gt;，Linux的一个发行版&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;常用命令&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pwd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当前所处的文件夹位置&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-6b3cd9b3a996fae6.webp&quot; alt=&quot;pwd&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ls&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;列出当前文件夹里面的文件及子文件夹&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-b428d850dc26df84.webp&quot; alt=&quot;ls&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ll&lt;/code&gt;
&lt;img src=&quot;./images/6641583-010733a1d184f2a4.webp&quot; alt=&quot;ll&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;该命令相当于 &lt;code&gt;ls -l&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;展示文件夹里面的文件及子文件夹详细信息，有点类似在Windows里面查看文件夹时以详细信息方式展示一样&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-c9427b666a882ba0.webp&quot; alt=&quot;ll&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;切换目录，换到别的文件夹&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-0b97c710d74bbeaf.webp&quot; alt=&quot;cd&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mkdir&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;创建一个新建文件夹&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-18e4b7755c0de7ff.webp&quot; alt=&quot;mkdir&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;cp 文件 新文件夹&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;复制文件到新的文件夹里面，copy的简写&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-1907e4cc00e72938.webp&quot; alt=&quot;cp&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cp -r 文件夹 新文件夹&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;复制整个文件夹到新的文件夹里面，需要添加 &lt;code&gt;-r&lt;/code&gt; 参数，进行递归式复制&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-b6fd00aa837d127b.webp&quot; alt=&quot;cp&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mv&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;mv 文件 新文件夹&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;移动文件到新文件夹，move 的简写&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-91f7956897fc3118.webp&quot; alt=&quot;mv&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mv 文件夹 新文件夹&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;移动文件夹到新文件夹&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-01f9753d425fdc9a.webp&quot; alt=&quot;mv&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cat&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;cat 文件名&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;展示文件里面的内容&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-9e1abc10bcf43580.webp&quot; alt=&quot;cat&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sort&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;sort 文件名&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;对文件里面的行进行排序&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-9f75d03a9b69ef4d.webp&quot; alt=&quot;sort&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sort -u 文件名&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;对文件里面的行进行去重并且排序，&lt;code&gt;-u&lt;/code&gt; 是 unique 的简写&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-b7419a9295c11a58.webp&quot; alt=&quot;sort&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;head&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;显示文件的前几行内容，在默认情况下，head命令显示文件的头10行内容，&lt;code&gt;-n &lt;/code&gt; 参数可以指定要显示的行数&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-804e9c9967df3927.webp&quot; alt=&quot;head&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tail&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;显示文件的后几行内容，在默认情况下，tail显示最后 10 行，&lt;code&gt;-n &lt;/code&gt; 参数可以指定要显示的行数&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-3dd27d7f971f068f.webp&quot; alt=&quot;tail&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;top&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实时动态显示各进程的情况，可以按 M与T 进行可视化变化，可以显示为进度条样式&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-daaf69f9d1b6e6ec.webp&quot; alt=&quot;top&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;df -h&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;显示目前在 Linux 系统上的文件系统使用情况统计磁盘，&lt;code&gt;-h&lt;/code&gt; 参数代表使用人类可读的格式 human-readable，是human的简写&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-b657bcd262e22a8c.webp&quot; alt=&quot;df&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ps -ef&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;查看服务器上所有运行的进程，类似Windows的查看任务管理器,PID 代表进程号&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-0387281a268dc11c.webp&quot; alt=&quot;ps&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kill -9 进程号&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;强制杀死进程，类似Windows的在任务管理器中结束某个进程任务，用上面的 ps 命令查出进程号后，可以直接强制退出该进程&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rm&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;删除文件或者文件夹，&lt;strong&gt;谨慎使用&lt;/strong&gt;，删除掉就不容易恢复，不像Windows在回收站可以找回&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rm 文件名&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;删除文件&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-73748ad77b78303e.webp&quot; alt=&quot;rm&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rm -r 文件夹&lt;/code&gt;
删除文夹，&lt;code&gt;-r&lt;/code&gt; 参数为递归删除文件夹及子文件夹里面的文件&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-c3bfec02fa9df65e.webp&quot; alt=&quot;rm&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;好用的学习网站&lt;/h1&gt;
&lt;p&gt;以上介绍的只是几个常用的命令，下面列出几个网站，个人感觉这几个比较好用，供大家可参考学习&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://man.linuxde.net/&quot;&gt;https://man.linuxde.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://c.biancheng.net/linux_tutorial/&quot;&gt;http://c.biancheng.net/linux_tutorial/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.runoob.com/linux/linux-tutorial.html&quot;&gt;https://www.runoob.com/linux/linux-tutorial.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Linux%E4%B9%8BNTFS%E3%80%81FAT32%E3%80%81exFAT-%E5%90%84%E7%A7%8D%E6%A0%BC%E5%BC%8F%E7%A1%AC%E7%9B%98%E6%8C%82%E8%BD%BD%E6%95%B4%E7%90%86.md&quot;&gt;Linux之NTFS、FAT32、exFAT 各种格式硬盘挂载整理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Linux-%EF%BC%88Centos-7%EF%BC%89%E4%B8%AD-Anaconda%E7%8E%AF%E5%A2%83%E7%AE%A1%E7%90%86%EF%BC%8C%E5%AE%89%E8%A3%85%E4%B8%8D%E5%90%8C%E7%9A%84%E7%89%88%E6%9C%ACPython%E5%8C%85.md&quot;&gt;Linux （Centos 7）中 Anaconda环境管理，安装不同的版本Python包&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Hive 中各种日期格式转换方法总结</title><link>https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive%E4%B8%AD%E5%90%84%E7%A7%8D%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E8%BD%AC%E6%8D%A2%E6%96%B9%E6%B3%95%E6%80%BB%E7%BB%93/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive%E4%B8%AD%E5%90%84%E7%A7%8D%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E8%BD%AC%E6%8D%A2%E6%96%B9%E6%B3%95%E6%80%BB%E7%BB%93/</guid><description>Hive 日期格式转换</description><pubDate>Fri, 22 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;日期计算平时在业务取数时经常涉及到，但是数据库中经常存放着不同的日期格式，有的存放是时间戳、有的是字符串等，这时需要对其进行转换才能提取到准确的数据，这里介绍的均是hive里面的函数功能，以下内容均是业务的数据需求经常使用的部分&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;时间戳&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;unix时间戳是从1970年1月1日（UTC/GMT的午夜）开始所经过的秒数，不考虑闰秒，一般为10位的整数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;一个在线工具：https://tool.lu/timestamp/&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-296fcd7bf38de1de.webp&quot; alt=&quot;时间戳&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;字符串日期&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如：&apos;2021-10-21 19:25:50&apos;，&apos;2021-10-21 20:25:50.0&apos;，&apos;2021-10-21 20:25&apos;&lt;/p&gt;
&lt;h1&gt;日期格式转换&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;时间戳---&amp;gt;正常的日期格式&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;获取当前时间戳&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select unix_timestamp()
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;把时间戳转为正常的日期&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select from_unixtime(unix_timestamp(),&apos;yyyy-MM-dd hh:mm:ss&apos;) as dt
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;业务中有时存放的是包含毫秒的整数，需要先转换为秒&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select from_unixtime(cast(create_time/1000 as bigint),&apos;yyyyMMdd&apos;) as dt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;字符串日期&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;假如数据库存放的是格式为：&quot;yyyy-MM-dd hh:mm:ss&quot;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;截取日期部分&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select substr(&apos;2021-10-22 17:34:56&apos;,1,10)
2021-10-22
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;字符串强制转换，获取日期&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select to_date(&apos;2021-10-22 17:34:56&apos;)
2021-10-22
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;也可以通过date_format实现&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select date_format(&apos;2021-10-22 17:34:56&apos;,&apos;yyyy-MM-dd&apos;)
2021-10-22
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;系统当前日期&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当前日期&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select current_date();
2021-10-22
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;字符串日期与系统当前日期比较，这个在业务中经常有用到&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;select substr(&apos;2021-10-22 17:34:56&apos;,1,10)&amp;gt;current_date()
false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;前一日/昨日&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select date_sub(current_date(),1);
2021-10-21
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;前一日12点/昨日12点&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在业务中与截取的字符串日期进行比较时用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select concat(date_format(date_sub(current_date(),1),&apos;yyyy-MM-dd&apos;),&apos; &apos;,&apos;12&apos;);
2021-10-21 12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;最近一个月/30天&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select date_sub(current_date(),30);
2021-09-22
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;当月第一天&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;业务中经常用在滚动计算当月每日的业绩数据&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select date_format(to_date(trunc(current_date(),&apos;MM&apos;)),&quot;yyyy-MM-dd&quot;);
2021-10-01
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;日期格式转换 yyyyMMdd---&amp;gt;yyyy-MM-dd&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select from_unixtime(unix_timestamp(&apos;20211022&apos;,&apos;yyyyMMdd&apos;),&quot;yyyy-MM-dd&quot;);
2021-10-22
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;两个日期相隔天数&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select datediff(&apos;2021-10-22&apos;, &apos;2021-10-01&apos;);
21
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Hive---HQL%E6%94%AF%E6%8C%81%E7%9A%842%E7%A7%8D%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E9%A3%8E%E6%A0%BC%EF%BC%8C%E4%BD%A0%E5%96%9C%E6%AC%A2%E5%93%AA%E4%B8%80%E7%A7%8D%EF%BC%9F.md&quot;&gt;Hive HQL支持的2种查询语句风格，你喜欢哪一种？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-%E5%9F%BA%E4%BA%8Edatetime%E5%BA%93%E7%9A%84%E6%97%A5%E6%9C%9F%E6%97%B6%E9%97%B4%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86.md&quot;&gt;Python 基于datetime库的日期时间数据处理&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Hive HQL支持的2种查询语句风格，你喜欢哪一种？</title><link>https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive---HQL%E6%94%AF%E6%8C%81%E7%9A%842%E7%A7%8D%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E9%A3%8E%E6%A0%BC%EF%BC%8C%E4%BD%A0%E5%96%9C%E6%AC%A2%E5%93%AA%E4%B8%80%E7%A7%8D%EF%BC%9F/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Hive/Hive---HQL%E6%94%AF%E6%8C%81%E7%9A%842%E7%A7%8D%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E9%A3%8E%E6%A0%BC%EF%BC%8C%E4%BD%A0%E5%96%9C%E6%AC%A2%E5%93%AA%E4%B8%80%E7%A7%8D%EF%BC%9F/</guid><description>Hive 2种查询语句风格</description><pubDate>Fri, 27 Aug 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;在平时业务运营分析中经常会提取数据，也就是大家俗称的Sql Boy，表哥表姐，各大公司数据中台现在大部分用的都是基于Hadoop的分布式系统基础架构，用的比较多的有Hive数据仓库工具，数据分析师在数据查询时用的就是HQL，语法与Mysql有所不同，基本每天都会写大量的HQL语句，但你有试过哪些风格的写法呢？哪种风格的查询语句更容易理解呢？可能不同的人有不同的看法，下面展示具体的风格代码样式，看看你喜欢哪种&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hadoop是一个由Apache基金会所开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下，开发分布式程序。充分利用集群的威力进行高速运算和存储。Hadoop实现了一个分布式文件系统（ Distributed File System），其中一个组件是HDFS（Hadoop Distributed File System）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;hive是基于Hadoop的一个数据仓库工具，用来进行数据提取、转化、加载，这是一种可以存储、查询和分析存储在Hadoop中的大规模数据的机制。hive数据仓库工具能将结构化的数据文件映射为一张数据库表，并提供SQL查询功能，能将SQL语句转变成MapReduce任务来执行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;风格一&lt;/h1&gt;
&lt;p&gt;这种风格大家都比较常用，&lt;strong&gt;从结果向源头倒着推&lt;/strong&gt;，直接多层嵌套，一层一层往里面写，业务逻辑复杂的话有可能写很多层，达到几百行之多，目前很多公司在有数仓的支持下，基本嵌套的层数会比较少&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select *
from
(
	(select *
	from a_temp
	where xxxx
    group by xxxx) as a
	left join 
	(select *
	from b_temp
	where xxxx) as b 
	on a.id=b.id
) temp
where xxxx
group by xxxx
order by xxxx
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;风格二&lt;/h1&gt;
&lt;p&gt;这种风格是利用 &lt;code&gt;with&lt;/code&gt; 语句，&lt;strong&gt;从源头向结果正向推&lt;/strong&gt;，可以把 &lt;code&gt;with&lt;/code&gt; 语句理解为建立了一个临时视图/表一样，后面的表引用前面的表，逻辑是正向推进&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;with a as(select *
		from a_temp
		where xxxx 
		group by xxxx),
	 b as(select *
		from b_temp
		where xxxx)
select *
from a left join b on a.id=b.id
where xxxx 
group by xxxx
order by xxxx
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;两种风格的区别&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;风格一：用的最多，从结果向源头倒着推&lt;/li&gt;
&lt;li&gt;风格二：容易理解，从源头向结果正向推&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-%E5%88%A9%E7%94%A8Pandas%E6%8A%8A%E6%95%B0%E6%8D%AE%E7%9B%B4%E6%8E%A5%E5%AF%BC%E5%85%A5Mysql.md&quot;&gt;Python 利用Pandas把数据直接导入Mysql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%9F%BA%E4%BA%8Essh%E8%BF%9E%E6%8E%A5%E8%BF%9C%E7%A8%8BMysql%E6%95%B0%E6%8D%AE%E5%BA%93.md&quot;&gt;Python 基于ssh连接远程Mysql数据库&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python 基于ssh连接远程Mysql数据库</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%9F%BA%E4%BA%8Essh%E8%BF%9E%E6%8E%A5%E8%BF%9C%E7%A8%8BMysql%E6%95%B0%E6%8D%AE%E5%BA%93/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-%E5%9F%BA%E4%BA%8Essh%E8%BF%9E%E6%8E%A5%E8%BF%9C%E7%A8%8BMysql%E6%95%B0%E6%8D%AE%E5%BA%93/</guid><description>Python 连接远程Mysql</description><pubDate>Fri, 20 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;如果需要访问远程服务器的Mysql数据库，但是该Mysql数据库为了安全期间，安全措施设置为只允许本地连接（也就是你需要登录到该台服务器才能使用），其他远程连接是不可以直接访问，并且相应的端口也做了修改，那么就需要基于ssh来连接该数据库。这种方式连接数据库与Navicat里面界面化基于ssh连接一样。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-a90b2c8a6726d5f9.webp&quot; alt=&quot;Navicat&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-622054202aa23f1b.webp&quot; alt=&quot;连接数据库&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;安装支持库&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;如果要连接Mysql，首先需要安装pymysql&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pip install pymysql
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;安装基于ssh的库sshtunnel&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pip install sshtunnel    #当前最新 0.3.1版
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;建议安装最新的sshtunnel库，旧版本库有一些bug&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;连接Mysql&lt;/h1&gt;
&lt;p&gt;基于ssh连接Mysql可以查看sshtunnel的文档，里面有一些案例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;with SSHTunnelForwarder(
        (&apos;192.168.1.1&apos;, 2222),
        ssh_password=&apos;123456&apos;,
        ssh_username=&apos;root&apos;,
        remote_bind_address=(&apos;127.0.0.1&apos;, 3306)) as server:
    print(&apos;SSH连接成功&apos;)
    conn = pymysql.connect(host=&apos;127.0.0.1&apos;,
                           port=server.local_bind_port,
                           user=&apos;root&apos;,
                           database=&apos;data&apos;,
                           charset=&apos;utf8&apos;)
    print(&apos;mysql数据库连接成功&apos;)
    cursor = conn.cursor()
    ...  #获取数据操作，此处省略
    cursor.close()
    conn.close()
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;自定义查询函数&lt;/h1&gt;
&lt;p&gt;可以对上面的连接进行封装为一个函数，方便其他地方使用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def mysql_ssh(sql,args=None):
    with SSHTunnelForwarder(
            (&apos;192.168.1.1&apos;, 2222),
            ssh_password=&apos;123456&apos;,
            ssh_username=&apos;root&apos;,
            remote_bind_address=(&apos;127.0.0.1&apos;, 3306)) as server:
        print(&apos;SSH连接成功&apos;)
        conn = pymysql.connect(host=&apos;127.0.0.1&apos;,
                               port=server.local_bind_port,
                               user=&apos;root&apos;,
                               database=&apos;data&apos;,
                               charset=&apos;utf8&apos;)
        print(&apos;mysql数据库连接成功&apos;)
        cursor = conn.cursor()
        print(&apos;游标获取成功&apos;)
        try:
            print(f&apos;执行查询语句：{sql}  参数：{args}&apos;)
            cursor.execute(sql,args)
            print(&apos;数据查询成功&apos;)
            conn.commit()
            print(&apos;事务提交成功&apos;)
            datas = cursor.fetchall()
            success = True
        except:
            print(&apos;数据查询失败&apos;)
            datas = None
            success = False

        print(&apos;正在关闭数据库连接&apos;)
        cursor.close()
        conn.close()

    return datas, success
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注意点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在使用数据库时，&lt;code&gt;conn.commit()&lt;/code&gt;、&lt;code&gt;cursor.close()&lt;/code&gt;、&lt;code&gt;conn.close()&lt;/code&gt;
这些一定要规范使用，防止不必要的bug&lt;/li&gt;
&lt;li&gt;传入参数时建议用这种方式&lt;code&gt;cursor.execute(sql,args)&lt;/code&gt;，防止sql注入的风险&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E5%8A%A0%E8%BD%BDtxt%E6%95%B0%E6%8D%AE%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98%E5%8D%87%E7%BA%A7%E7%89%88%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md&quot;&gt;Python加载txt数据乱码问题升级版解决方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./Python%E6%96%87%E4%BB%B6%E6%89%93%E5%8C%85%E6%88%90exe%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F.md&quot;&gt;Python文件打包成exe可执行程序&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注 DataShare （同微），不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Linux之NTFS、FAT32、exFAT-各种格式硬盘挂载整理</title><link>https://datashare-duo.github.io/datashare-blog/posts/Linux/Linux%E4%B9%8BNTFS%E3%80%81FAT32%E3%80%81exFAT-%E5%90%84%E7%A7%8D%E6%A0%BC%E5%BC%8F%E7%A1%AC%E7%9B%98%E6%8C%82%E8%BD%BD%E6%95%B4%E7%90%86/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Linux/Linux%E4%B9%8BNTFS%E3%80%81FAT32%E3%80%81exFAT-%E5%90%84%E7%A7%8D%E6%A0%BC%E5%BC%8F%E7%A1%AC%E7%9B%98%E6%8C%82%E8%BD%BD%E6%95%B4%E7%90%86/</guid><description>Linux 各种格式硬盘挂载</description><pubDate>Wed, 11 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;由于业务需要频繁处理大量视频（几十GB），通过公司内网传输太慢，于是就每次处理视频时需要在服务器挂载硬盘或U盘。业务人员给的硬盘或U盘格式有时不一样，目前遇到的格式：NTFS、FAT32、exFAT，这几种格式大家在Windows上基本很常见，于是总结了这些格式的硬盘如何有效挂载到Linux服务器，分享出来供大家参考&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NTFS挂载&lt;/li&gt;
&lt;li&gt;FAT32挂载&lt;/li&gt;
&lt;li&gt;exFAT挂载&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;NTFS挂载&lt;/h1&gt;
&lt;p&gt;第一步：安装驱动&lt;code&gt;ntfs-3g&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yum install ntfs-3g
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二步：查看硬盘信息（硬盘已通过USB插入服务器）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fdisk -l 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;会在最后列出该硬盘的信息，一般是sdb，默认只有1个分区，下面挂载时用的是&lt;strong&gt;sdb1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;但有的硬盘里面也有2个分区的，如下所示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Disk identifier: 9B602E4F-E563-4A27-9510-46DEBC0BAA20
#         Start          End    Size  Type            Name
 1           40       409639    200M  EFI System      EFI System Partition
 2       409640   3906961407    1.8T  Microsoft basic My Passport
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果是这种情况，下面挂载时就需要用到&lt;strong&gt;sdb2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;第三步：挂载硬盘&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /mnt
mkdir Windows   #挂载时一定要提前创建好该文件夹
mount -t ntfs-3g /dev/sdb1  /mnt/Windows
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第四步：解除挂载&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;umount /dev/sdb1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;硬盘挂载基本就以上这四步，下面主要列出其他格式硬盘挂载的重点步骤&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;FAT32挂载&lt;/h1&gt;
&lt;p&gt;不需要驱动，可以直接挂载&lt;/p&gt;
&lt;p&gt;下面的挂载命令 支持 &lt;strong&gt;中文、挂载后不同用户可读写权限&lt;/strong&gt;，具体参数含义可自行百度查询&lt;/p&gt;
&lt;p&gt;第三步：挂载硬盘&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mount -t vfat -o iocharset=utf8,umask=000,rw,exec /dev/sdb1 /mnt/Windows
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;exFAT挂载&lt;/h1&gt;
&lt;p&gt;第一步：安装驱动&lt;code&gt;fuse-exfat&lt;/code&gt;、&lt;code&gt;exfat-utils&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yum install fuse-exfat
yum install exfat-utils
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第三步：挂载硬盘&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mount /dev/sdb2  /mnt/Windows
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;总结&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;有的格式需要安装驱动，有的不需要&lt;/li&gt;
&lt;li&gt;硬盘里面具体要看有几个分区，挂载时指定分区号 &lt;code&gt;sdb1&lt;/code&gt; or &lt;code&gt;sdb2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./Linux-%EF%BC%88Centos-7%EF%BC%89%E4%B8%AD-Anaconda%E7%8E%AF%E5%A2%83%E7%AE%A1%E7%90%86%EF%BC%8C%E5%AE%89%E8%A3%85%E4%B8%8D%E5%90%8C%E7%9A%84%E7%89%88%E6%9C%ACPython%E5%8C%85.md&quot;&gt;Linux （Centos 7）中 Anaconda环境管理，安装不同的版本Python包&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E6%96%87%E4%BB%B6%E6%89%93%E5%8C%85%E6%88%90exe%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F.md&quot;&gt;Python文件打包成exe可执行程序&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注DataShare，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python文件打包成exe可执行程序</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E6%96%87%E4%BB%B6%E6%89%93%E5%8C%85%E6%88%90exe%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E6%96%87%E4%BB%B6%E6%89%93%E5%8C%85%E6%88%90exe%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F/</guid><description>Python 打包程序</description><pubDate>Mon, 19 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;有时写的Python程序需要交给业务人员使用，但业务人员电脑上基本都没有安装Python，并且业务人员也不会使用命令行，所以就需要把Python程序打包成exe可执行程序，让业务人员无需安装Python，可以直接使用。&lt;/p&gt;
&lt;p&gt;这里只针对Windows操作系统的打包，以及只针对业务人员使用场景。（Linux系统基本都是技术开发人员在使用，基本都用的是命令行；而Mac系统不知是否有相关的打包库，可以打包为dmg）&lt;/p&gt;
&lt;h1&gt;打包过程（以下均为在cmd命令行执行）&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;首先安装第三方库：&lt;code&gt;pyinstaller&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pip install pyinstaller
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;打包&lt;/strong&gt; &amp;lt;br/&amp;gt;
需要先切换到打包程序目录，
&lt;code&gt;cd c:\xxx\xxx&lt;/code&gt;
然后对Python程序进行打包&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pyinstaller -F xxx.py
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;结果&lt;/strong&gt; &amp;lt;br/&amp;gt;
如果打包成功，当前目录下会增加一个新的&lt;code&gt;dist&lt;/code&gt;文件夹，打开该文件夹，会发现打包好的exe文件：xxx.exe，文件名与Python程序文件相同&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;其他&lt;/strong&gt; &amp;lt;br/&amp;gt;
打包大概流程如上所示，除此之外&lt;code&gt;pyinstaller&lt;/code&gt;支持其他一些功能，比如打包时指定自定义图标，首先需要下载一张正常的ico，不能用直接修改后缀的，然后进行打包，一定是先图标文件路径，再是程序路径，如下所示：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pyinstaller -F  -i xxx.ico xxx.py
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;注意事项！！！&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;运行报错&lt;/strong&gt; &amp;lt;br/&amp;gt;
虽然经过一番折腾，终于打包好exe可执行程序，但是双击运行时总是报错，无法成功运行，这种情况大多数是因为缺少第三方库造成的。&amp;lt;br/&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;解决方法：&lt;/strong&gt; &amp;lt;br/&amp;gt;
在打包之前先在&lt;code&gt;cmd&lt;/code&gt;运行一次Python程序看是否成功运行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python xxx.py
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;如果能成功运行，那么打包后基本没什么问题&lt;/li&gt;
&lt;li&gt;如果运行失败，那么查看报错信息，是否缺少第三方库，然后进行&lt;code&gt;pip&lt;/code&gt;安装，确保能成功运行&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文件太大&lt;/strong&gt; &amp;lt;br/&amp;gt;
以上打包过程是不是很简单，但是有没有注意打包的exe文件有时会很大，有时几百兆大小，但是自己的Python程序也就几KB，这个问题也是自己之前遇到的难题（使用的是Anaconda），即使另外建立了新的环境也不行（&lt;code&gt;conda create -n 环境名&lt;/code&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;解决方法：&lt;/strong&gt; &amp;lt;br/&amp;gt;
一定要使用Python官网下载的原生Python程序，并且确保系统环境变量里面只有这一个Python路径，只有这一个Python路径，只有这一个Python路径！！！&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;亲测自己的打包程序从200M降到50M大小&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E5%B8%B8%E7%94%A8%E8%AF%AD%E5%8F%A5%E6%B1%87%E6%80%BB.md&quot;&gt;Python常用语句汇总&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Linux/Linux-%EF%BC%88Centos-7%EF%BC%89%E4%B8%AD-Anaconda%E7%8E%AF%E5%A2%83%E7%AE%A1%E7%90%86%EF%BC%8C%E5%AE%89%E8%A3%85%E4%B8%8D%E5%90%8C%E7%9A%84%E7%89%88%E6%9C%ACPython%E5%8C%85.md&quot;&gt;Linux （Centos 7）中 Anaconda环境管理，安装不同的版本Python包&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号DataShare，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>NumPy论文都已经登上了Nature，Pythoneer会用了吗？</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/NumPy%E8%AE%BA%E6%96%87%E9%83%BD%E5%B7%B2%E7%BB%8F%E7%99%BB%E4%B8%8A%E4%BA%86Nature%EF%BC%8CPythoneer%E4%BC%9A%E7%94%A8%E4%BA%86%E5%90%97%EF%BC%9F/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/NumPy%E8%AE%BA%E6%96%87%E9%83%BD%E5%B7%B2%E7%BB%8F%E7%99%BB%E4%B8%8A%E4%BA%86Nature%EF%BC%8CPythoneer%E4%BC%9A%E7%94%A8%E4%BA%86%E5%90%97%EF%BC%9F/</guid><description>NumPy 基础知识</description><pubDate>Fri, 25 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;背景&lt;/h1&gt;
&lt;p&gt;NumPy（Numerical Python）诞生已经过去了 15 年，前一段时间NumPy 核心开发团队的论文终于发表，详细介绍了使用 NumPy 的数组编程（Array programming），并且登上了Nature 。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NumPy 是什么？它是大名鼎鼎的使用 Python 进行科学计算的基础软件包，是 Python 生态系统中数据分析、机器学习、科学计算的主力军，极大简化了向量与矩阵的操作处理。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;功能强大的 N 维数组对象&lt;/li&gt;
&lt;li&gt;精密广播功能函数&lt;/li&gt;
&lt;li&gt;集成 C/C++ 和 Fortran 代码的工具&lt;/li&gt;
&lt;li&gt;强大的线性代数、傅立叶变换和随机数功能&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;在平时数据处理中，大部分人用的都是Pandas，用Numpy的场景可能比较少，但是Pandas是基于Numpy实现的更高级的库，使大家用起来更方便。但在做深度学习时用Numpy比较多，比如：图像处理，图片里面其实都是Numpy数组；音频处理；文本处理等等。&lt;/p&gt;
&lt;p&gt;下面为大家介绍一些Numpy的常用基础&lt;/p&gt;
&lt;h1&gt;Numpy基础&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;安装&lt;/strong&gt; &amp;lt;br/&amp;gt;
由于Numpy是第三方库，默认是不集成在Python里面，所以就需要手动安装一下：
如果你安装的是Anaconda，那么就不用再安装了，请忽略
如果你是从官方网站下载的Python，那么你就需要手动安装一下这个库&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;#指定阿里云镜像，安装更快
pip install numpy -i https://mirrors.aliyun.com/pypi/simple/   
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;导入&lt;/strong&gt; &amp;lt;br/&amp;gt;
默认成规，&lt;code&gt;numpy&lt;/code&gt;导入后命名为 &lt;code&gt;np&lt;/code&gt;，所以在python脚本（程序）里面看见&lt;code&gt;np&lt;/code&gt;一般都是代表&lt;code&gt;numpy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import numpy as np   
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;认识Ndarray&lt;/strong&gt; &amp;lt;br/&amp;gt;
计算机里面能计算的就是数字，也就是数学里面的各种数字，我们都知道数学里面的数组可以有多层，也就是多维，1维就是向量，2维就是矩阵，3维就是$x y z$坐标轴构成的空间（形象理解），但体现在&lt;code&gt;numpy&lt;/code&gt;中就是N 维数组对象 &lt;code&gt;ndarray&lt;/code&gt;，它是一系列同类型数据的集合。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;1维：&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import numpy as np
&amp;gt;&amp;gt;&amp;gt; a=np.array([1,2,3,4])
&amp;gt;&amp;gt;&amp;gt; print(a)
[1 2 3 4]
&amp;gt;&amp;gt;&amp;gt; type(a)
&amp;lt;class &apos;numpy.ndarray&apos;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; a.ndim
1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;2维：&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import numpy as np
&amp;gt;&amp;gt;&amp;gt; b=np.array([[1,2,3],[4,5,6]])
&amp;gt;&amp;gt;&amp;gt; print(b)
[[1 2 3]
 [4 5 6]]
&amp;gt;&amp;gt;&amp;gt; type(b)
&amp;lt;class &apos;numpy.ndarray&apos;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; b.ndim
2
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;切片和索引&lt;/strong&gt; &amp;lt;br/&amp;gt;
切片、索引与python内置的列表、字符串的切片和索引基本一样，如果理解了列表的切片和索引，那么&lt;code&gt;ndarray&lt;/code&gt;对象就不在话下&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import numpy as np
&amp;gt;&amp;gt;&amp;gt; a=np.arange(10)
&amp;gt;&amp;gt;&amp;gt; print(a)
[0 1 2 3 4 5 6 7 8 9]
&amp;gt;&amp;gt;&amp;gt; type(a)
&amp;lt;class &apos;numpy.ndarray&apos;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; a.ndim
1
&amp;gt;&amp;gt;&amp;gt; a[:5]
array([0, 1, 2, 3, 4])
&amp;gt;&amp;gt;&amp;gt; a[7:]
array([7, 8, 9])
&amp;gt;&amp;gt;&amp;gt; a[3:6]
array([3, 4, 5])
&amp;gt;&amp;gt;&amp;gt; a[::2]
array([0, 2, 4, 6, 8])
&amp;gt;&amp;gt;&amp;gt; a[::-1]
array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])

&amp;gt;&amp;gt;&amp;gt; a[0]
0
&amp;gt;&amp;gt;&amp;gt; a[5]
5
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数组操作&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;修改数组形状&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import numpy as np
&amp;gt;&amp;gt;&amp;gt; a=np.arange(10)
&amp;gt;&amp;gt;&amp;gt; print(a)
[0 1 2 3 4 5 6 7 8 9]
&amp;gt;&amp;gt;&amp;gt; type(a)
&amp;lt;class &apos;numpy.ndarray&apos;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; a.ndim
1
&amp;gt;&amp;gt;&amp;gt; b=a.reshape(5,2)
&amp;gt;&amp;gt;&amp;gt; print(b)
[[0 1]
 [2 3]
 [4 5]
 [6 7]
 [8 9]]
&amp;gt;&amp;gt;&amp;gt; b.ndim
2
&amp;gt;&amp;gt;&amp;gt; c=a.reshape(2,5)
&amp;gt;&amp;gt;&amp;gt; print(c)
[[0 1 2 3 4]
 [5 6 7 8 9]]
&amp;gt;&amp;gt;&amp;gt; c.ndim
2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;数组转置&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import numpy as np
&amp;gt;&amp;gt;&amp;gt; a=np.arange(12).reshape(3,4)
&amp;gt;&amp;gt;&amp;gt; print(a)
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
&amp;gt;&amp;gt;&amp;gt; np.transpose(a)
array([[ 0,  4,  8],
       [ 1,  5,  9],
       [ 2,  6, 10],
       [ 3,  7, 11]])
&amp;gt;&amp;gt;&amp;gt; a.T
array([[ 0,  4,  8],
       [ 1,  5,  9],
       [ 2,  6, 10],
       [ 3,  7, 11]])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;数组连接&lt;/strong&gt;&lt;/em&gt; &amp;lt;br/&amp;gt;
&lt;code&gt;concatenate&lt;/code&gt;、&lt;code&gt;stack&lt;/code&gt;、&lt;code&gt;hstack&lt;/code&gt;、&lt;code&gt;vstack&lt;/code&gt;这个几个函数均是数组连接，原理基本都一样，只要理解了其中一个，其他的都很好理解，这里只介绍&lt;code&gt;concatenate&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import numpy as np
&amp;gt;&amp;gt;&amp;gt; a=np.array([[1,2],[3,4]]
... )
&amp;gt;&amp;gt;&amp;gt; b=np.array([[5,6],[7,8]])
&amp;gt;&amp;gt;&amp;gt; np.con
np.concatenate( np.conj(        np.conjugate(   np.convolve(
&amp;gt;&amp;gt;&amp;gt; np.concatenate([a,b],axis=0)   #沿着0轴拼接
array([[1, 2],
       [3, 4],
       [5, 6],
       [7, 8]])
&amp;gt;&amp;gt;&amp;gt; np.concatenate([a,b],axis=1)   #沿着1轴拼接
array([[1, 2, 5, 6],
       [3, 4, 7, 8]])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;修改数组维度&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import numpy as np
&amp;gt;&amp;gt;&amp;gt; x=np.array([1,2])
&amp;gt;&amp;gt;&amp;gt; np.expand_dims(x,axis=0)
array([[1, 2]])
&amp;gt;&amp;gt;&amp;gt; np.expand_dims(x,axis=1)
array([[1],
       [2]])
&amp;gt;&amp;gt;&amp;gt; y=np.array([[1,2]])
&amp;gt;&amp;gt;&amp;gt; np.squeeze(y)    #从给定数组的形状中删除一维，当前维必须等于1
array([1, 2])
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数组计算&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import numpy as np
&amp;gt;&amp;gt;&amp;gt; a1=np.array([1,2,3,4])
&amp;gt;&amp;gt;&amp;gt; a2=np.array([5,5,5,5])
&amp;gt;&amp;gt;&amp;gt; a1+a2
array([6, 7, 8, 9])
&amp;gt;&amp;gt;&amp;gt; np.add(a1,a2)
array([6, 7, 8, 9])
&amp;gt;&amp;gt;&amp;gt; a1-a2
array([-4, -3, -2, -1])
&amp;gt;&amp;gt;&amp;gt; np.subtract(a1,a2)
array([-4, -3, -2, -1])
&amp;gt;&amp;gt;&amp;gt; a1*a2
array([ 5, 10, 15, 20])
&amp;gt;&amp;gt;&amp;gt; np.multiply(a1,a2)
array([ 5, 10, 15, 20])
&amp;gt;&amp;gt;&amp;gt; a1/a2
array([0.2, 0.4, 0.6, 0.8])
&amp;gt;&amp;gt;&amp;gt; np.divide(a1,a2)
array([0.2, 0.4, 0.6, 0.8])
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python--Numpy%E4%B8%AD%E7%9A%84%E8%8C%83%E6%95%B0.md&quot;&gt;Python Numpy中的范数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Pythonner%E8%BF%98%E5%9C%A8%E4%B8%BA%E4%BA%86%E7%BB%83%E4%B9%A0Numpy%E8%80%8C%E6%B2%A1%E6%9C%89%E7%9C%9F%E5%AE%9E%E6%95%B0%E6%8D%AE%E8%80%8C%E7%83%A6%E6%81%BC%E5%90%97%EF%BC%9F.md&quot;&gt;Pythonner还在为了练习Numpy而没有真实数据而烦恼吗？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号DataShare，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python math模块详解</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-math%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python-math%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3/</guid><description>Python math基础库</description><pubDate>Sun, 30 Aug 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;概述&lt;/h1&gt;
&lt;p&gt;math模块是内置模块，提供了许多对浮点数的数学运算函数，提供类似C语言标准定义的数学函数（This module provides access to the mathematical functions defined by the C standard）&lt;/p&gt;
&lt;p&gt;包含以下 &lt;strong&gt;&lt;code&gt;七部分&lt;/code&gt;&lt;/strong&gt; 函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;算术函数&lt;/strong&gt;（Number-theoretic and representation functions）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;幂函数与对数函数&lt;/strong&gt;（Power and logarithmic functions）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;三角函数&lt;/strong&gt;（Trigonometric functions）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;角度转换函数&lt;/strong&gt;（Angular conversion）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;双曲函数&lt;/strong&gt;（Hyperbolic functions）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;特殊函数&lt;/strong&gt;（Special functions）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;常量&lt;/strong&gt;（Constants）&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;math模块常用函数&lt;/h1&gt;
&lt;p&gt;虽然math模块提供的函数很多，但是现阶段工作中使用的很少，下面就列出一些实际工作中常用的函数：&lt;/p&gt;
&lt;p&gt;注意：虽然math是内置模块，但使用前需要先import导入该库&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import math
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.ceil(x)----------向上取整&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.ceil(2.1)
3
&amp;gt;&amp;gt;&amp;gt; math.ceil(3.7)
4
&amp;gt;&amp;gt;&amp;gt; math.ceil(-1.5)
-1
&amp;gt;&amp;gt;&amp;gt; math.ceil(-3.1)
-3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.floor(x)----------向下取整&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.floor(1.2)
1
&amp;gt;&amp;gt;&amp;gt; math.floor(4.8)
4
&amp;gt;&amp;gt;&amp;gt; math.floor(-0.1)
-1
&amp;gt;&amp;gt;&amp;gt; math.floor(-2.8)
-3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.exp(x)----------e的x次方，其中 e = 2.718281… 是自然对数的基数&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.exp(1)
2.718281828459045
&amp;gt;&amp;gt;&amp;gt; math.exp(2)
7.38905609893065
&amp;gt;&amp;gt;&amp;gt; math.exp(0)
1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.log(x,base=e)---------- 默认返回x 的自然对数,默认底为 e，如果指定底，返回指定底的对数&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.log(math.exp(1))
1.0
&amp;gt;&amp;gt;&amp;gt; math.log(math.exp(0))
0.0
&amp;gt;&amp;gt;&amp;gt; math.log(math.exp(2))
2.0
&amp;gt;&amp;gt;&amp;gt; math.log(4,base=2)
2.0
&amp;gt;&amp;gt;&amp;gt; math.log(9,base=3)
2.0
&amp;gt;&amp;gt;&amp;gt; math.log(100,base=10)
2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.pow(x, y)---------- x 的 y 次幂&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.pow(2,3)
8.0
&amp;gt;&amp;gt;&amp;gt; math.pow(4,2)
16.0
&amp;gt;&amp;gt;&amp;gt; math.pow(-5,2)
25.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.sqrt(x)---------- x 的算术平方根，也就是正数的平方根&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.sqrt(25)
5.0
&amp;gt;&amp;gt;&amp;gt; math.sqrt(4)
2.0
&amp;gt;&amp;gt;&amp;gt; math.sqrt(10)
3.1622776601683795
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.pi---------- 常量π，15位小数&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.pi
3.141592653589793
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.e---------- 常量e，15位小数&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.e
2.718281828459045
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.sin(x)---------- x弧度的正弦值&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.sin(math.pi/2)
1.0
&amp;gt;&amp;gt;&amp;gt; math.sin(math.pi/3)
0.8660254037844386
&amp;gt;&amp;gt;&amp;gt; math.sin(math.pi/6)    #近似0.5
0.49999999999999994
&amp;gt;&amp;gt;&amp;gt; math.sin(math.pi/4)
0.7071067811865476
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.cos(x)---------- x弧度的余弦值&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.cos(0)
1.0
&amp;gt;&amp;gt;&amp;gt; math.cos(math.pi/3)    #近似0.5
0.5000000000000001
&amp;gt;&amp;gt;&amp;gt; math.cos(math.pi/4)  
0.7071067811865476
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.degrees(x)----------将角度 x 从弧度转换为度数&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.degrees(math.pi)
180.0
&amp;gt;&amp;gt;&amp;gt; math.degrees(math.pi/2)
90.0
&amp;gt;&amp;gt;&amp;gt; math.degrees(math.pi/6)    #近似30
29.999999999999996
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;math.radians(x)----------将角度 x 从度数转换为弧度&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; math.radians(90)
1.5707963267948966
&amp;gt;&amp;gt;&amp;gt; math.radians(180)
3.141592653589793
&amp;gt;&amp;gt;&amp;gt; math.radians(360)
6.283185307179586
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;度数、弧度概念可参考历史相关文章，有详细说明&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/%E5%88%A9%E7%94%A8Python%E8%AE%A1%E7%AE%97%E4%B8%A4%E4%B8%AA%E5%9C%B0%E7%90%86%E4%BD%8D%E7%BD%AE%E4%B9%8B%E9%97%B4%E7%9A%84%E4%B8%AD%E7%82%B9.md&quot;&gt;利用Python计算两个地理位置之间的中点&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python--Numpy%E4%B8%AD%E7%9A%84%E8%8C%83%E6%95%B0.md&quot;&gt;Python Numpy中的范数&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Linux（Centos-7）中-Anaconda环境管理，安装不同的版本Python包</title><link>https://datashare-duo.github.io/datashare-blog/posts/Linux/Linux-%EF%BC%88Centos-7%EF%BC%89%E4%B8%AD-Anaconda%E7%8E%AF%E5%A2%83%E7%AE%A1%E7%90%86%EF%BC%8C%E5%AE%89%E8%A3%85%E4%B8%8D%E5%90%8C%E7%9A%84%E7%89%88%E6%9C%ACPython%E5%8C%85/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Linux/Linux-%EF%BC%88Centos-7%EF%BC%89%E4%B8%AD-Anaconda%E7%8E%AF%E5%A2%83%E7%AE%A1%E7%90%86%EF%BC%8C%E5%AE%89%E8%A3%85%E4%B8%8D%E5%90%8C%E7%9A%84%E7%89%88%E6%9C%ACPython%E5%8C%85/</guid><description>Linux Anaconda环境搭建</description><pubDate>Mon, 10 Aug 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;硬件信息及操作系统信息&lt;/h1&gt;
&lt;p&gt;服务器：戴尔R740&lt;/p&gt;
&lt;p&gt;显卡：英伟达 Tesla V100&lt;/p&gt;
&lt;p&gt;操作系统：CentOS Linux release 7.8.2003 (Core)&lt;/p&gt;
&lt;h1&gt;Anaconda安装&lt;/h1&gt;
&lt;p&gt;从官网下载 &lt;code&gt;Anaconda3-2020.02-Linux-x86_64.sh&lt;/code&gt;，运行后一步一步安装&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-fef60da1c790b3e7.webp&quot; alt=&quot;安装成功界面&quot; /&gt;&lt;/p&gt;
&lt;p&gt;参考：&amp;lt;br/&amp;gt;
&lt;a href=&quot;https://blog.csdn.net/Gary1_Liu/article/details/81297927&quot;&gt;https://blog.csdn.net/Gary1_Liu/article/details/81297927&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Anaconda环境管理&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;克隆环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;conda create --name newname --clone oldname&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;例如：&lt;code&gt;conda create --name pytorch1.5 --clone base&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;conda create -n 环境名 python=3.7&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;例如：&lt;code&gt;conda create -n pytorch1.5 python=3.7&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;激活环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;conda activate 环境名&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;例如：&lt;code&gt;conda activate pytorch1.5&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/6641583-ad9a9f79d217566c.webp&quot; alt=&quot;激活环境&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;退出环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;conda deactivate&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对虚拟环境中安装额外的包&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;conda install -n your_env_name [package]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;例如：&lt;code&gt;conda install -n pytorch1.5 pytorch==1.5.0 torchvision==0.6.0 cudatoolkit=10.2 -c pytorch&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;经测试后发现，只要激活了虚拟环境后，用&lt;code&gt;pip&lt;/code&gt;直接安装也可以，安装的包是直接在虚拟环境里面&lt;/p&gt;
&lt;p&gt;例如：&lt;code&gt;pip install torch==1.5.0 torchvision==0.6.0&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;删除环境内某个包&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;conda remove --name 环境名 包名&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;例如：&lt;code&gt;conda remove --name pytorch1.5  pytorch&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查看当前存在哪些虚拟环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;conda env list&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查看安装了哪些包&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;conda list&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查更新当前conda&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;conda update conda&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;删除虚拟环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;conda remove --name oldname --all&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%86%85%E7%BD%AE%E7%9A%84-os-%E6%A8%A1%E5%9D%97%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0%E3%80%81%E6%96%B9%E6%B3%95.md&quot;&gt;Python内置的 os 模块常用函数、方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python%E5%B8%B8%E7%94%A8%E8%AF%AD%E5%8F%A5%E6%B1%87%E6%80%BB.md&quot;&gt;Python常用语句汇总&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Python内置的 os 模块常用函数、方法</title><link>https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%86%85%E7%BD%AE%E7%9A%84-os-%E6%A8%A1%E5%9D%97%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0%E3%80%81%E6%96%B9%E6%B3%95/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/Python%E5%9F%BA%E7%A1%80%E5%BA%93/Python%E5%86%85%E7%BD%AE%E7%9A%84-os-%E6%A8%A1%E5%9D%97%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0%E3%80%81%E6%96%B9%E6%B3%95/</guid><description>Python os基础库</description><pubDate>Sat, 11 Jul 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;前言&lt;/h1&gt;
&lt;p&gt;无论是在自己Windows、MacOS电脑，还是在Linux服务器，在操作文件时，多多少少都会涉及到文件的管理。
Python里面有个自带的 &lt;strong&gt;&lt;code&gt;os&lt;/code&gt;&lt;/strong&gt; 模块，专门是用来对文件、路径等进行管理的工具，下面列出一些自己在工作中常用的函数、方法，供大家参考学习。&lt;/p&gt;
&lt;h1&gt;路径的正确表示，三种都可以&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;由于&lt;code&gt;\&lt;/code&gt;是转义的意思，所以路径都用&lt;code&gt;\\&lt;/code&gt;表示，例如：
&lt;code&gt;&apos;C:\\Users\\abc\\Desktop&apos;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;如果想用单个&lt;code&gt;\&lt;/code&gt;，可以在前面加个&lt;code&gt;r&lt;/code&gt;，例如：
&lt;code&gt;r&apos;C:\Users\abc\Desktop&apos;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;也可以用&lt;code&gt;/&lt;/code&gt;来表示，例如：
&lt;code&gt;&apos;C:/Users/abc/Desktop&apos;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;点点们的介绍&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;./&lt;/code&gt;   当前你所编辑的这个脚本所在目录
&lt;code&gt;../&lt;/code&gt;  当前你所编辑的这个脚本所在目录的上一级目录&lt;/p&gt;
&lt;h1&gt;os 模块常用函数、方法&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;无需pip安装，可以直接导入&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import os
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;获取当前工作路径&lt;/strong&gt;
也就是你编写的这个脚本所在的文件夹位置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;os.getcwd()    #C:\\Users\\abc\\Desktop\\Python\\python库
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;获取绝对路径&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;path=&apos;./111.xlsx&apos;
os.path.abspath(path)    #C:\\Users\\abc\\Desktop\\Python\\python库\\111.xlsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;获取文件的完整路径里面的文件名字&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;a=&apos;C:\\Users\\abc\\Desktop\\Python\\python库\\111.xlsx&apos;
os.path.basename(a)     #111.xlsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;获取文件的完整路径里面的路径&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;a=&apos;C:\\Users\\abc\\Desktop\\Python\\python库\\111.xlsx&apos;
os.path.dirname(a)     #C:\\Users\\abc\\Desktop\\Python\\python库
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;判断是否存在相应的文件或文件夹&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;a=&apos;./111.xlsx&apos;
b=&apos;C:\\Users\\abc\\Desktop\\Python\\python库\\111&apos;
os.path.exists(a)    #True
os.path.exists(b)   #False
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分隔文件的完整路径为：路径、文件名字&lt;/strong&gt;
相对上面的方法，这样可以一次都获取到，但是也有缺点，os.path.split&lt;strong&gt;只识别&lt;code&gt;/&lt;/code&gt;，不识别&lt;code&gt;\\&lt;/code&gt;&lt;/strong&gt;，因此在用该方法时，需要先进行替换&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;a=&apos;C:\\Users\\abc\\Desktop\\Python\\python库\\111.xlsx&apos;
b,c=os.path.split(a.replace(&apos;\\&apos;,&apos;/&apos;))
#b  C:/Users/abc/Desktop/Python/python库
#c  111.xlsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;删除存在的文件&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;a=&apos;./111.xlsx&apos;
os.remove(a)    #无返回值，直接删除该文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;br/&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;创建文件夹&lt;/strong&gt;
建议用makedirs方法，这样即可以直接创建单级文件夹，有可以创建多层级文件夹&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;os.makedirs(&apos;./a&apos;)
os.makedirs(&apos;./1/2&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上这些方法是在工作中经常使用的，如有新的路径的需求可以在其他一些网站进行查找&lt;/p&gt;
&lt;h1&gt;历史相关文章&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../%E6%95%B0%E5%AD%A6%E7%9F%A5%E8%AF%86/%E5%88%A9%E7%94%A8Python%E6%9E%9A%E4%B8%BE%E6%89%80%E6%9C%89%E7%9A%84%E6%8E%92%E5%88%97%E6%83%85%E5%86%B5.md&quot;&gt;利用Python枚举所有的排列情况&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../Python%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/Python-jupyter-%E5%B8%B8%E7%94%A8%E8%AF%AD%E5%8F%A5%E6%B1%87%E6%80%BB.md&quot;&gt;Python jupyter 常用语句汇总&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;以上是自己实践中遇到的一些问题，分享出来供大家参考学习，欢迎关注微信公众号：DataShare ，不定期分享干货&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>数据去重 VBA字典法</title><link>https://datashare-duo.github.io/datashare-blog/posts/EXCEL%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E4%B8%8EVBA/%E6%95%B0%E6%8D%AE%E5%8E%BB%E9%87%8D-----VBA%E5%AD%97%E5%85%B8%E6%B3%95/</link><guid isPermaLink="true">https://datashare-duo.github.io/datashare-blog/posts/EXCEL%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E4%B8%8EVBA/%E6%95%B0%E6%8D%AE%E5%8E%BB%E9%87%8D-----VBA%E5%AD%97%E5%85%B8%E6%B3%95/</guid><description>Excel 通过VBA编写宏程序来进行数据去重</description><pubDate>Mon, 18 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在Excel里面数据去重方法比较多，目前用的比较多的有：&lt;/p&gt;
&lt;h4&gt;1. 数据--筛选---高级筛选&lt;/h4&gt;
&lt;h4&gt;2. 数据透视表&lt;/h4&gt;
&lt;h4&gt;但以上这两种方法都有局限性，比如需要去重的区域是多列数据&lt;/h4&gt;
&lt;hr /&gt;
&lt;p&gt;下面介绍一种通过VBA编写宏程序来进行数据去重，可以去重多列数据&lt;/p&gt;
&lt;p&gt;先把代码呈现出来，再进行解释：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
Sub 字典方法()

    Dim rng As Range       &apos;定义一个区域，用于接收需要去重的单元格区域

    Set rng = Application.InputBox(&quot;请指定去重区域&quot;, &quot;数据源区域&quot;, , , , , , 8)     &apos;可以是一列，也可以是多列

    If rng Is Nothing Then End         &apos;如果没有选择区域，则退出，注：是End，不是End IF



    Dim arr    &apos;定义一个数组，用于存储去重区域的值

    arr = rng.value



    Dim a

    On Error Resume Next         &apos;这里需要忽略错误，后面添加重复键值会引发错误



    Dim dic As Object    

    Set dic = CreateObject(&quot;scripting.dictionary&quot;)            &apos;引用字典对象



    For Each a In arr

        If Len(a) &amp;gt; 0 Then     

            dic.Add CStr(a), &quot;&quot;     &apos;往字典里面添加键值

        End If

    Next a

    Err.Clear



    Set rng = Application.InputBox(&quot;请指定结果存放区域，单个单元格即可&quot;, &quot;存放区域&quot;, , , , , , 8)



    If Err &amp;lt;&amp;gt; 0 Then End



    rng(1).Resize(dic.Count, 1) = WorksheetFunction.Transpose(dic.Keys)         &apos;往单元格里面写入去重后的数据



End Sub

&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;这里主要运用的字典的键值唯一性，如果向字典里面添加已经存在的键，则会引发错误，所以中间部分需要忽略错误&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;数组+字典在VBA里面可以提升程序运行效率，如想提升VBA程序运行效率，可多运用数组、字典&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item></channel></rss>