python-13-pandas的常用操作和数据处理加速技巧

(1)获取数据
(2)数据处理:处理缺失数据,可视化
(3)特征工程
(4)算法训练:模型
(5)模型评估
(6)应用
from numpy import nan as NA
在这里插入图片描述

1 读取数据

1.1 导入和导出数据

一、导入数据

pd.read_csv(filename):从CSV文件导入数据
df.to_csv("aa.txt",index=0) # 不保存行索引
pd.read_table(filename):从限定分隔符的文本文件导入数据
pd.read_excel(filename):从Excel文件导入数据
pd.read_sql(query, connection_object):从SQL表/库导入数据
pd.read_json(json_string):从JSON格式的字符串导入数据
pd.read_html(url):解析URL、字符串或者HTML文件,抽取其中的tables表格
pd.read_clipboard():从你的粘贴板获取内容,并传给read_table()
pd.DataFrame(dict):从字典对象导入数据,Key是列名,Value是数据
pd.DataFrame(list,columns = ):从列表对象导入数据,通过columns指定列名,多用于连接数据库取数据

二、导出数据

df.to_csv(filename):导出数据到CSV文件
df.to_excel(filename):导出数据到Excel文件
df.to_sql(table_name, connection_object):导出数据到SQL表
df.to_json(filename):以Json格式导出数据到文本文件

1.2 分析数据

1.2.1 遍历DataFrame行

for index, row in df.iterrows():
    print(row["c1"], row["c2"])
    
df["method"]获取指定列
df.iloc[0]获取第一行的数据
df.iloc[0]["code"]获取第一行指定列的数据
df.shape获取行数和列数

查看数据

data = df #整个数据表
data = df.head(n) # 前n行
data = df.tail(n) # 末尾n行
data = df.info() # 缺失值查看
data = df.columns # 获取列名
data = df.shape # 获取DataFrame的行数和列数
data = df.index # 索引标签
data = df[x:y] # 任意x到y行,存在DataFrame里
data = df.loc[n] # 指定第n行,存在Series里
data = df["列名称"] # 查看某一列,存在Series里
data = df[["列名称1","列名称2"]] # 查看2列数据,存在DataFrame里

1.2.2 .loc基于标签索引

参考pandas索引和选择数据
pandas中有三种索引方法:.loc,.iloc和切片操作[]。

import pandas as pd
import numpy as np
data=pd.DataFrame(np.array([[1,2,3],[4,5,6]]),index=list("ab"),columns=list("ABC"))
print(data)

在这里插入图片描述
.loc主要是基于标签(label)的,包括行标签(index)和列标签(columns),即行名称和列名称,可以使用df.loc[index_name,col_name],选择指定位置的数据。
(1)使用单个标签
使用单个标签。
如果.loc[]中只有单个标签,那么选择的是某一行。

z=data.loc["a"]
print(type(z))
print(z)
输出
<class 'pandas.core.series.Series'>
A    1
B    2
C    3
Name: a, dtype: int32

(2)使用标签的list
使用标签的list:同样是只选择行。

z=data.loc[["a"]]
print(type(z))
print(z)
输出
<class 'pandas.core.frame.DataFrame'>
   A  B  C
a  1  2  3

另一种情况
z=data.loc[["a","b"]]
print(type(z))
print(z)
输出
<class 'pandas.core.frame.DataFrame'>
   A  B  C
a  1  2  3
b  4  5  6

(3)标签的切片对象
标签的切片对象:与通常的python切片不同,在最终选择的数据中包含切片的start和stop。

z=data.loc["a":"b"]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
a  1  2  3
b  4  5  6

(4)布尔型的数组
布尔型的数组:通常用于筛选符合某些条件的行。

z=data.loc[data.A>3]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
b  4  5  6
第二种情况
z=data.loc[data.A>3,["B","C"]]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   B  C
b  5  6

查询区间
df1=df.loc[((df.time=>st_str) & (df.time<=ed_str)),["time","data"]]

(5)可调用的函数

z=data.loc[lambda data:data.A>3,:]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
b  4  5  6
第二种情况
z=data.loc[lambda data:data.A>3]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
b  4  5  6

1.2.3 .iloc基于位置索引

iloc是基于位置的索引,利用元素在各个轴上的索引序号进行选择,序号超出范围会产生IndexError,切片时允许序号超过范围。
(1) 使用整数
使用整数与.loc相同,如果只使用一个维度,则对行选择,下标从0开始。

z=data.iloc[1]
print(type(z))
print(z)
<class 'pandas.core.series.Series'>
A    4
B    5
C    6
Name: b, dtype: int32

(2) 使用列表或数组
使用列表或数组,同样是对行选择。

z=data.iloc[[0,1]]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
a  1  2  3
b  4  5  6
第二种情况
z=data.iloc[np.array([0,1])]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
a  1  2  3
b  4  5  6

(3) 元素为整数的切片对象
元素为整数的切片对象:与.loc不同的是,这里下标为stop的数据不被选择。

z=data.iloc[0:1]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
a  1  2  3

也可以对列进行切片:

z=data.iloc[0:1,0:2]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B
a  1  2

(4)使用布尔数组进行筛选

z=data.iloc[np.array(data.A>3)]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
b  4  5  6


z=data.iloc[list(data.A>3)]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
b  4  5  6

(5)使用可调用函数


z=data.iloc[lambda data:[0,1]]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
a  1  2  3
b  4  5  6

1.2.4 切片操作[]

[]操作只能输入一个维度,不能用逗号隔开输入两个维度。

(1) 使用列名
使用列名:.loc和iloc只输入一维时选取的是行,而[]选取的是列,并且必须使用列名。

z=data[["A","C"]]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  C
a  1  3
b  4  6

(2) 使用布尔数组
使用布尔数组:bool数组的index需要和dataframe的index一致,此时选取的是行

l=pd.Series([False,True])
l.index=list("ab")
z=data[l]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
b  4  5  6

因此可以用来筛选符合条件的行
z=data[data.A>3]
print(type(z))
print(z)
<class 'pandas.core.frame.DataFrame'>
   A  B  C
b  4  5  6

2 数据预处理

2.1 滤除缺失数据

SeriesNew = Series.dropna()
SeriesNew = Series[Series.notnull()]
DataFrameNew = DataFrame.dropna()删除含NA的行
DataFrameNew = DataFrame.dropna(how="all")删除全为NA的行
DataFrameNew = DataFrame.dropna(axis=1,how="all")删除全为NA的列
DataFrameNew = DataFrame.dropna(axis=1)删除含NA的列
DataFrameNew = DataFrame.dropna(thresh=n)保留至少有n个非NA的行

注意:(1)DataFrame.dropna()这个操作将删除任何至少有一个空值的行,但是它将返回一个新的DataFrame,而不更改原来的数据,更改原数据可以在这个方法中指定inplace=True。

2.2 填充缺失数据

DataFrameNew = DataFrame.fillna(num)
DataFrameNew = DataFrame.fillna({1:0.5,2:7.3})填充指定列
DataFrame.fillna(0,inplace=True)就地修改
SeriesNew = Series.fillna(Series.mean())传入Series的平均值

2.3 移出重复数据

Series = DataFrame.duplicated()布尔型Series,各行是否是重复行
DataFrameNew = DataFrame.drop_duplicates()
DataFrameNew = DataFrame.drop_duplicates(['k1'])根据k1列过滤重复项
DataFrameNew = DataFrame.drop_duplicates(['k1','k2'])保留最后一个
SeriesNew = Series.map(字典)
SeriesNew = Series.str.lower()大写转小写
SeriesNew = Series.map(lambda x:f(x))

2.4 替换值

SeriesNew = Series.replace(-999,np.nan)
Series.replace(-999,np.nan,inplace=True)就地修改
SeriesNew = Series.replace([-999,-1000],np.nan)
SeriesNew = Series.replace([-999,-1000],[np.nan,0])
SeriesNew = Series.replace({-999:np.nan,-1000:0})

2.5 Timestamp

一、pandas中的时间可以做差

t1 = pd.Timestamp("2022-10-27 17:49:00")
t2 = pd.Timestamp("2022-10-27 17:50:00")
tt = t2 -t1
print(tt.total_seconds())
输出60秒。

import pandas as pd
timediff = pd.Timedelta(hours=1) # 时间偏差1h
print(t1-timediff)

二、pandas中的时间可以排序

# 数据排序
rr = [pd.Timestamp("2022-10-27 17:50:00"),pd.Timestamp("2022-10-26 17:50:00"),pd.Timestamp("2022-10-27 17:49:00")]
print("排序前",rr)
rr.sort() # 升序排列
print("排序后",rr)

DataFrame.query(“a>2”)对数据框进行挑选行的操作
(1)时间戳转换为日期时间
时间戳单位秒
pd.to_datetime()
(2)日期时间转变为日期时间索引
pd.DatetimeIndex()
(3)是否包含在其中
Series.isin()

2.6 按某一列排序

# 按指定的字段进行排序,指定升序或降序排列
df1 = df.sort_values(by='Time',ascending=True)
print(df1) # 排序完成后的数据

2.7 对某一列应用函数

df1["Time"] = df1["Time"].map(lambda x:f(x))

2.8 按索引拼接并填充数据

import pandas as pd
df1 = pd.DataFrame(A1.data,index=A1.time,columns=["0"])
df2 = pd.DataFrame(A2.data,index=A2.time,columns=["1"])
df3 = pd.DataFrame(A3.data,index=A3.time,columns=["2"])
print(df1)
print(df2)
print(df3)

在这里插入图片描述

zz = pd.merge(df1,df2,left_index=True,right_index=True,how='outer')
zz = pd.merge(zz,df3,left_index=True,right_index=True,how='outer')
print(zz)
#求交集
#zz = pd.merge(df2,df3,left_index=True,right_index=True,how='inner') 

在这里插入图片描述
填充数据

df_out = zz
mode = "forward"
for col in df_out.columns: 
    print(col)  
    if mode=="mean":
        fill=df_out[col].mean()
        df_out[col].fillna(fill, inplace = True)
    elif mode=="mode":
        fill=df_out[col].mode()[0]
        df_out[col].fillna(fill, inplace = True)
    elif mode=="forward":
        if pd.isnull(df_out[col].iloc[0]):
            tmp1 = df_out[col].dropna().to_list()[0]
            df_out[col].iloc[0]=tmp1
        df_out[col].fillna(method = 'ffill', inplace = True)
    elif mode=="backward":
        if pd.isnull(df_out[col].iloc[-1]):
            tmp2 = df_out[col].dropna().to_list()[-1]
            df_out[col].iloc[-1]=tmp2
        df_out[col].fillna(method = 'bfill', inplace = True) 
print(df_out)

在这里插入图片描述

3 进阶使用

3.1 重命名轴索引

DataFrame.index = DataFrame.index.map(函数)就地修改
DataFrameNew = DataFrame.rename()
s.value_counts()计数

3.2 图

fig = plt.figure()
ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
fig,axes = plt.subplot(2,2,sharex=True,sharey=True)
axes[0,0][1,0]
axes[0,1][1,1]
plt.subplots_adjust(wspace=0,hspace=0)调整子图间距
ax.plot(x,y,'g--')颜色线型
ax.plot(x,y,linstyle='--',color='g')颜色线型

ax.set_xticks([0,250,500])刻度位置
ax.set_xticklables(["one","two","three"])刻度标签

ax.set_title("标题")标题
ax.set_xlabel("名称")x轴的名称

ax.plot(x,y,label='one')图例配合label参数使用
ax.legend(loc="best")

ax.text()注解
ax.arrow()
ax.annotate()

plt.savefig()保存

Series.plot()
DataFrame.plot()
sns.barplot()柱状图
sns.distplot()直方图和密度图
sns.displot(a,bins=None,hist=True,kde=True,rug=False,fit=None)
sns.regplot()散点图和回归图
sns.pairplot()散点图矩阵,且对角线为直方图或密度图
sns.factorplot()
pd.merge()

3.3 分组

df.groupby('key')
df.groupby(['key1','key2'])
df.groupby().size()

3.4 字符串

str.split(',')拆分成列表
str.strip()去除空白符(包括换行符)
substr in str 子串定位
str.index(',')找不到会抛异常
str.find(':')
str.count(substr)子串出现次数
str.replace(被替,填充)
re.split('\s+',str)按一个或多个空白符(制表符、空格、换行符),拆分成列表

regex = re.compile(正则表达式)
regex.findall(str)返回列表
regex.search(str)起始和结束位置
regex.sub(替换物,str)返回新的字符串

4 数据处理加速技巧

Pandas数据处理加速技巧汇总
再见 for 循环!pandas 速度提升315倍!

从一个包含两列的 CSV 文件中读取数据,一列为日期及时间,另一列为以千瓦时 (kWh) 为单位的消耗电能。

import pandas as pd
df = pd.read_csv("demand_profile.csv")
print(df)

在这里插入图片描述
Pandas和NumPy有一个dtypes(数据类型)的概念。 如果未指定任何参数,则 date_time这一列将采用object dtype。

print(df.dtypes)
print(df.iat[0, 0], type(df.iat[0, 0]))

输出如下:
date_time      object
energy_kwh    float64
dtype: object
1/1/13 0:00 <class 'str'>

object不仅是str的容器,而且是任何不能完全适合一种数据类型的列的容器。将日期作为字符串处理会既费力又低效(这也会导致内存效率低下)。为了处理时间序列数据,需要将date_time列格式化为日期时间对象数组( Timestamp)。

df["date_time"] = pd.to_datetime(df['date_time'])
print(df.dtypes)
print(df)

输出如下:
date_time     datetime64[ns]
energy_kwh           float64
dtype: object
               date_time  energy_kwh
0    2013-01-01 00:00:00       0.586
1    2013-01-01 01:00:00       0.580
2    2013-01-01 02:00:00       0.572
3    2013-01-01 03:00:00       0.596
4    2013-01-01 04:00:00       0.592

日期和时间格式处理完毕,就可以着手计算电费了。

4.1 数据的简单循环220ms

使用时间成本将定义成三个部分:

data_type = {
    # 高峰
    "Peak":{"Cents per kWh":28,"Time Range":"17:00 to 24:00"},
    # 正常时段
    "Shoulder":{"Cents per kWh":20,"Time Range":"7:00 to 17:00"},
    # 非高峰
    "Off-Peak":{"Cents per kWh":12,"Time Range":"0:00 to 7:00"}, 
}

如果价格是一天中每小时每千瓦时 28 美分。

df['cost_cents'] = df['energy_kwh'] * 28
df.head()

输出如下:
	date_time	energy_kwh	cost_cents
0	2013-01-01 00:00:00	0.586	16.408
1	2013-01-01 01:00:00	0.580	16.240
2	2013-01-01 02:00:00	0.572	16.016
3	2013-01-01 03:00:00	0.596	16.688
4	2013-01-01 04:00:00	0.592	16.576

用apply方法写一个函数,函数里面写好时间条件的逻辑代码。

def apply_tariff(kwh, hour):
    """计算给定小时的电费"""   
    if 0 <= hour < 7:
        rate = 12
    elif 7 <= hour < 17:
        rate = 20
    elif 17 <= hour < 24:
        rate = 28
    else:
        raise ValueError(f'无效时间: {hour}')
    return rate * kwh

然后使用for循环来遍历df,根据apply函数逻辑添加新的特征,如下:

def apply_tariff_loop(df):
    energy_cost_list = []
    for i in range(len(df)):
        # 循环数据直接修改df
        energy_used = df['energy_kwh'][i]
        hour = df["date_time"][i].hour
        energy_cost = apply_tariff(energy_used, hour)
        energy_cost_list.append(energy_cost)
 
    df['cost_cents'] = energy_cost_list

调用情况如下:

%%time
apply_tariff_loop(df)

耗时225ms。

4.2 循环.iterrows()方法798ms

def apply_tariff_iterrows(df):
    energy_cost_list = []
    for index, row in df.iterrows():
        energy_used = row['energy_kwh']
        hour = row["date_time"].hour
        energy_cost = apply_tariff(energy_used, hour)
        energy_cost_list.append(energy_cost)
 
    df['cost_cents'] = energy_cost_list

调用如下:

%%time
apply_tariff_iterrows(df)

耗时:798ms。并没有显著加速效果。

4.3 .apply()方法210ms

可以使用 .apply() 方法进一步改进此操作。 Pandas 的.apply() 方法采用函数(可调用对象)并将它们沿 DataFrame的轴(所有行或所有列)应用。

lambda 函数将两列数据传递给 apply_tariff()。

def apply_tariff_withapply(df):
    df['cost_cents'] = df.apply(
        lambda row: apply_tariff(
            kwh=row['energy_kwh'],
            hour=row['date_time'].hour),
        axis=1)

调用如下:

%%time
apply_tariff_withapply(df)
耗时:210ms。

apply的语法优点很明显,行数少,代码可读性高。在这种情况下,所花费的时间大约是iterrows方法的一半。
但是,这还不是“非常快”。一个原因是apply()将在内部尝试循环遍历Cython迭代器。但是在这种情况下,传递的lambda不是可以在Cython中处理的东西,因此它在Python中调用并不是那么快。
如果我们使用apply()方法获取10年的小时数据,那么将需要大约15分钟的处理时间。如果这个计算只是大规模计算的一小部分,那么真的应该提速了。这也就是矢量化操作派上用场的地方。

4.4 使用.isin选择数据5.98ms

如果你不基于一些条件,而是可以在一行代码中将所有电力消耗数据应用于该价格:df [‘energy_kwh’] * 28,类似这种。那么这个特定的操作就是矢量化操作的一个例子,它是在pandas中执行的最快方法。

但是如何将条件计算应用为pandas中的矢量化运算
一个技巧是:根据你的条件,选择和分组DataFrame,然后对每个选定的组应用矢量化操作
在下面代码中,我们将看到如何使用pandas的.isin()方法选择行,然后在矢量化操作中实现新特征的添加。在执行此操作之前,如果将date_time列设置为DataFrame的索引,会更方便:

df.set_index('date_time', inplace=True)
 
def apply_tariff_isin(df):
    peak_hours = df.index.hour.isin(range(17, 24))
    shoulder_hours = df.index.hour.isin(range(7, 17))
    off_peak_hours = df.index.hour.isin(range(0, 7))
 
    df.loc[peak_hours, 'cost_cents'] = df.loc[peak_hours, 'energy_kwh'] * 28
    df.loc[shoulder_hours,'cost_cents'] = df.loc[shoulder_hours, 'energy_kwh'] * 20
    df.loc[off_peak_hours,'cost_cents'] = df.loc[off_peak_hours, 'energy_kwh'] * 12

调用如下:

%%time
apply_tariff_isin(df)
耗时:5.98ms。

上面.isin()方法返回的是一个布尔值数组,如下:

[False, False, False, ..., True, True, True]

布尔值标识了DataFrame索引datetimes是否落在了指定的小时范围内。然后把这些布尔数组传递给DataFrame的.loc,将获得一个与这些小时匹配的DataFrame切片。然后再将切片乘以适当的费率,这就是一种快速的矢量化操作了。

4.5 .cut()数据分箱1.98ms

在上面apply_tariff_isin中,我们通过调用df.loc和df.index.hour.isin三次来进行一些手动调整。如果我们有更精细的时间范围,你可能会说这个解决方案是不可扩展的。但在这种情况下,我们可以使用pandas的pd.cut()函数来自动完成切割:

def apply_tariff_cut(df):
    cents_per_kwh = pd.cut(x=df.index.hour,
                           bins=[0, 7, 17, 24],
                           include_lowest=True,
                           labels=[12, 20, 28]).astype(int)
    df['cost_cents'] = cents_per_kwh * df['energy_kwh']

调用如下:

%%time
apply_tariff_cut(df)
耗时:1.98ms。

上面代码pd.cut()会根据bin列表应用分组。
其中include_lowest参数表示第一个间隔是否应该是包含左边的。
这是一种完全矢量化的方法,它在时间方面是最快的:

4.6 使用Numpy继续加速973us

使用pandas时不应忘记的一点是Pandas的Series和DataFrames是在NumPy库之上设计的。并且,pandas可以与NumPy阵列和操作无缝衔接。
下面我们使用NumPy的 digitize()函数更进一步。它类似于上面pandas的cut(),因为数据将被分箱,但这次它将由一个索引数组表示,这些索引表示每小时所属的bin。然后将这些索引应用于价格数组:

import numpy as np
def apply_tariff_digitize(df):
    prices = np.array([12, 20, 28])
    bins = np.digitize(df.index.hour.values, bins=[7, 17, 24])
    df['cost_cents'] = prices[bins] * df['energy_kwh'].values

调用如下:

%%time
apply_tariff_digitize(df)
耗时:973us

5 异常处理

5.1 No module named _bz2

一、找到_bz2.cpython-36m-x86_64-linux-gnu.so文件
如果在机器上没有的话,可以到这里下载:
链接:https://pan.baidu.com/s/1GzUY4E0G2yVUfqxHOIzn1A
提取码:oiwh
#cd /usr/local/lib/python3.6/lib-dynload

在这里插入图片描述
将下载的 _bz2.cpython-36m-x86_64-linux-gnu.so 文件复制到 ./python3/lib/python3.6/lib-dynload 文件夹下。

二、安装一些依赖
#yum install --downloadonly --downloaddir=/root -y bzip2-devel
下载的安装包bzip2-devel-1.0.6-13.el7.x86_64.rpm
#yum install --downloadonly --downloaddir=/root -y xz-devel
#yum install --downloadonly --downloaddir=/root -y python-backports-lzma
#pip3 download -d ./ backports.lzma

三、安装步骤
#yum localinstall xz-devel-5.2.2-1.el7.x86_64.rpm
#yum localinstall python-backports-lzma-0.0.2-9.el7.x86_64.rpm
#pip3 install backports.lzma-0.0.14.tar.gz

5.2 Your installed Python is incomplete

Python运行异常UserWarning:Could not import the lzma module .Your installed Python is incomplete.

yum install xz-devel
yum install python-backports-lzma
pip install backports.lzma

修改/usr/local/lib/python3.6/lzma.py
在这里插入图片描述

try:
    from _lzma import *
    from _lzma import _encode_filter_properties, _decode_filter_properties
except ImportError:
    from backports.lzma import *
    from backports.lzma import _encode_filter_properties, _decode_filter_properties

5.3 jupyter不显示完整数据

使用jupyter notebook时,查询大量数据出现省略号,不显示完整数据。

一般出现这种情况是因为,你所查询的数据量超过了jupyter notebook默认设定的可见范围,故出现了省略号,忽略显示了中间大多数据信息。因此我们只需要增大其行和列的容纳量即可!!!

pd.set_option('display.width', 1000)  # 设置字符显示宽度
pd.set_option('display.max_rows', None)  # 设置显示最大

5.4 读excel中长数字变成科学计数法的问题

# pandas 读excel中的长数字时,即使excel中已经设置为文本,读进df后也会自动变成科学计数法。
# '''在读取时加上converter参数,先转成str再读'''
# data = pd.read_excel(data_path, converters={'订单编号':str})
或者
# df = pd.read_excel(file_path,dtype={'结算单号':str})  # 指定某一列为str类型
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮皮冰燃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值