TOC

Pandas 基础

数据结构

  • Series 一维
  • DataFrame 二维,或多维

之前的 Pannel 三维数组完全可以用 DataFrame 嵌套表示。
后来被移除了,挺好的。

pd.Series(
    data=None,
    index=None,
    dtype=None,
    name=None,
    copy=False,
    fastpath=False,
)
pd.DataFrame(
    data=None,
    index: 'Optional[Axes]' = None,
    columns: 'Optional[Axes]' = None,
    dtype: 'Optional[Dtype]' = None,
    copy: 'bool' = False,
)

连接 concat

pd.concat(
    objs: Union[Iterable[ForwardRef('NDFrame')], Mapping[Optional[Hashable], ForwardRef('NDFrame')]],
    axis=0,
    join='outer',
    ignore_index: bool = False,
    keys=None,
    levels=None,
    names=None,
    verify_integrity: bool = False,
    sort: bool = False,
    copy: bool = True,
) -> Union[ForwardRef('DataFrame'), ForwardRef('Series')]

df1 = pd.DataFrame({'key': tuple('abcd'), 'data': range(1, 5)})
df2 = pd.DataFrame({'key': tuple('abcd'), 'data': range(6, 10)})
pd.concat([df1, df2])

合并 merge

pd.merge(
    left,
    right,
    how: str = 'inner',
    on=None,
    left_on=None,
    right_on=None,
    left_index: bool = False,
    right_index: bool = False,
    sort: bool = False,
    suffixes=('_x', '_y'),
    copy: bool = True,
    indicator: bool = False,
    validate=None,
) -> 'DataFrame'
df1 = pd.DataFrame(range(10))
df2 = pd.DataFrame(range(20))
df3 = pd.merge(df1, df2)

df4 = pd.DataFrame({'a': 1, 'b': 2}, index=['x', 'y'])
df5 = pd.DataFrame({'key': 'abcd', data=range(4)})
pd.merge(df4, df5)

how 参数:

  • left 左连接
  • right 右连接
  • inner 内连接
  • outer 外连接
  • cross 交叉连接,笛卡儿积

分组

import random

所有姓名 = ('小李 四眼 大红 雀儿 宝宝 山鸡 皮蛋 猴子 芝麻 拐子 蝴蝶 '
           '乐高 五花 伟哥 金子 老班 旺仔 二狗 圆圆 熊猫 泰迪 婆婆 '
           '小白 小强 电脑').split(' ')
所有学科 = ('语文 数学 英语 物理 化学 生物 历史 地理 政治 体育 实践').split(' ')

# 成绩表 = {姓名: {学科: random.choice('SABCD') for 学科 in 所有学科} for 姓名 in 所有姓名}
# 成绩 = pd.DataFrame({学科: [成绩表[姓名][学科] for 姓名 in 所有姓名] for 学科 in 所有学科}, index=所有姓名)

def 评级(分数):
    if 分数 < 60:
        return 'D'
    elif 分数 < 75:
        return 'C'
    elif 分数 < 85:
        return 'B'
    elif 分数 < 95:
        return 'A'
    return 'S'

成绩表 = {姓名: {学科: random.randint(60, 100) for 学科 in 所有学科} for 姓名 in 所有姓名}
for 成绩 in 成绩表.values():
    成绩['总分'] = sum(成绩.values())
    成绩['评级'] = 评级(成绩['总分'] / len(所有学科))
所有条目 = 所有学科 + ['总分', '评级']
成绩 = pd.DataFrame({条目: [成绩表[姓名][条目] for 姓名 in 所有姓名] for 条目 in 所有条目}, index=所有姓名)
成绩

grouped = 成绩['总分'].groupby(成绩['评级'])
grouped
# <pandas.core.groupby.generic.SeriesGroupBy object at 0x7f248a930460>
grouped.mean()
# 评级
# A    938.000000
# B    876.954545
# C    813.000000
# Name: 总分, dtype: float64

聚合

grouped = 成绩.groupby(成绩['评级'])
grouped
# <pandas.core.groupby.generic.DataFrameGroupBy object at 0x7f248a981e20>

grouped.mean()
grouped['总分'].mean()
grouped['语文'].quantile(0.9)

appregate

def peak_to_peak(arr):
    return arr.max() - arr.min()
# .aggregate(func=None, *args, engine=None, engine_kwargs=None, **kwargs)
# 有一个别名:.agg
grouped.agg(peak_to_peak)
grouped['总分'].agg(peak_to_peak)

# 这个很不错,计算每一列的 count, mean, std, min, 0.25, 0.50, 0.75, max
grouped.describe()

top

def top(df, n=1, column='语文'):
    return df.sort_values(by=column)[-n:]

top(成绩)
grouped.apply(top)

缺失数据处理

  • .isnull => 找到 None, np.nan
  • .dropna => data[data.notnull()]
  • .fillna
pf1 = pd.Series(['a', 'b', '12', 12, True, None, [], (), {}, set(), np.nan])
pf1
pf1.isnull()

data = pd.DataFrame([[1, 2, None], [5, None, 4]])
data
data.dropna()
data.dropna(how='all')
data.dropna(thresh=2)
data.fillna(0, inplace=True)
data.fillna({1: 50, 2: 100})

data = pd.DataFrame(np.random.randn(4, 5))
data.iloc[:2, 1] = data.iloc[:3, 2] = np.nan
data

data = pd.DataFrame({
    'a': [random.choice(['one', 'two', 'three', 'four']) for _ in range(10)],
    'b': [random.choice(['jim', 'may', 'jacob', 'lucy']) for _ in range(10)],
})
data
data.duplicated()
data.drop_duplicated()
data['c'] = range(10)
data
data.duplicated()
data.drop_duplicates(['a']) # 按列去重
data.drop_duplicates(['a', 'b'])
data.drop_duplicates(['a', 'b'], keep='last')

# a = data['a'].str.lower()
a = data['a']
data['d'] = a.map({'one': 'O', 'two': 'T', 'three': 'T', 'four': 'F'})

import random
所有姓名 = ('小李 四眼 大红 雀儿 宝宝 山鸡 皮蛋 猴子 芝麻 拐子 蝴蝶 '
           '乐高 五花 伟哥 金子 老班 旺仔 二狗 圆圆 熊猫 泰迪 婆婆 '
           '小白 小强 电脑').split(' ')
所有学科 = ('语文 数学 英语 物理 化学 生物 历史 地理 政治 体育 实践').split(' ')
成绩表 = {姓名: {学科: random.randint(60, 100) for 学科 in 所有学科} for 姓名 in 所有姓名}
成绩 = pd.DataFrame({学科: [成绩表[姓名][学科] for 姓名 in 所有姓名] for 学科 in 所有学科}, index=所有姓名)
成绩['语文'].map(lambda x: 评级(x))

replace

data = pd.Series(np.random.randint(1, 100, 100))
data.to_string()
data.replace(1, np.nan, inplace=True)
data.replace([1, 2], np.nan, inplace=True)
data.replace(range(10), np.nan, inplace=True)
data.replace([1, 2], [0, np.nan], inplace=True)  # 必须相同长度
data.replace({1: 0, 2: np.nan}, inplace=True)
data[data.isnull()]

filter

成绩['语文'][成绩['语文'] > 90]
成绩[成绩['语文'] > 90]
# np.sum(成绩)
成绩[np.sum(成绩) > 2000]  # 平均分达到 80 的科目,即 25 个人,总分 2000
# 成绩.sum(axis=1)
成绩[成绩.sum(axis=1) > 900]  # 总分超过 900 分的人

data = pd.DataFrame(np.random.randn(10, 10))
data.describe()
data[np.abs(data[0]) < 1]        # 列出第 0 列绝对值小于 1 的行
data[(np.abs(data) < 1).any(1)]  # 列出所有列 绝对值小于 1 的行
data.iloc[:,(np.abs(data) < 1).any(0)]

其他数据来源

csv

参数超级多,就不搬到这里来了。

pd.read_csv()
pd.read_table()

JSON

pd.read_json()

Excel

Excel,无人不知,无人不晓,可以认为是一种数据存储和可视化工具。

pd.read_excel()

数据库

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_sql.html

只要支持 Python DB-API 就行。

# pandas.read_sql(sql, con,
#                 index_col=None,
#                 coerce_float=True,
#                 params=None,
#                 parse_dates=None,
#                 columns=None,
#                 chunksize=None)
# pandas.read_sql_query(sql, con,
#                       index_col=None,
#                       coerce_float=True,
#                       params=None,
#                       parse_dates=None,
#                       chunksize=None)
# pandas.read_sql_table(table_name, con,
#                       schema=None,
#                       index_col=None,
#                       coerce_float=True,
#                       parse_dates=None,
#                       columns=None,
#                       chunksize=None)
df = pd.read_sql(sql, con=conn)
df = pd.read_sql(sql, con=conn, index_col='id')