Pandas数据分析中常见操作及详解


依据最近做的东西总结。

数据筛选与转化

按条件筛选:以多分类OvO、OvR方法划分样本集为例。给定的数据集如下:

train_data = np.array([[1,2,4],[2,1,0],[4,3,1],[8,0,2],[2,4,1],[1,3,2],[0,1,2],[3,2,1]])
train_label = np.array([0,3,1,2,0,1,0,2])

Numpy

如下的方法提取出了训练集中类别为1和2的样本。在OvO具体的实现中一般是提取两类训练分类器。

unique_labels = list(set(train_label))
data = train_data[(train_label == unique_labels[1]) | (train_label == unique_labels[2])]
label = train_label[train_label == unique_labels[1] | (train_label == unique_labels[2])]
print(data)
print(label)

输出的结果为:

[[4 3 1]
 [8 0 2]
 [1 3 2]
 [3 2 1]]
[1 2 1 2]

使用Numpy的好处是不改变数据类型。因为一般机器学习算法中给定的数据集是ndarray。但是如果要实现OvR,则需要改变标签为0-1,这时可以考虑提取出positive class 和 negative class,然后将两个ndarray合并。
以下以筛选1类样本为例,1类作为正例,其他作为反例。OvR划分样本集方法如下:

label1 = list(np.ones(len(train_labels[train_labels == unique_labels[1]])))
label0 = list(np.zeros(len(train_labels[train_labels != unique_labels[1]])))
label1.extend(label0) #这里注意extend是在原有的列表中追加,因此不能写成label = lable1.extend(label0)
label = np.array(label1) 
data1 = list(train_datas[train_labels == unique_labels[1]])
data0 = list(train_datas[train_labels != unique_labels[1]])
data1.extend(data0)
data = np.array(data1)
print(data)
print(label)

产生的训练数据及样本标签如下

[[4 3 1]
 [1 3 2]
 [1 2 4]
 ...
 [2 4 1]
 [0 1 2]
 [3 2 1]]
[1. 1. 0. 0. 0. 0. 0. 0.]

Pandas

实现该功能使用Pandas想法比较自然,按列筛选样本属性就可以。但是使用Pandas做的时候要进行数据类型的转化。转化的方式如下:

datas = zip(train_data.tolist(),train_labels) #注意tolist
datas = pd.DataFrame(datas,columns = ['data','label'])

这样则可以用DataFrame的操作方式来做筛选。如下仍然OvO是提取类别为1的样本。

temp = datas[datas.label == unique_label[1]]
data = temp['data'].tolist()
label = temp['label'].tolist()

这里要注意的是,最后还要将列数据转化回去。此外,对于训练集的数据,ndarray中常为列表的嵌套,如果直接训练集的数据和标签打包后转化为DataFrame,之后提取数据时得到的数据部分转化成ndarray之后,内部嵌套的元素也会有array()结构,与预期的结果不一致。
OvR的实现比较自然,并且只要转化标签就可以。需要注意的就是在筛选转化标签的时候不能直接改成0-1,因为原来样本的类别标号也可能是0或者1。直接修改会造成0类或1类所有样本标号相同。因此这里先改成了’T’和’F’。代码如下:

unique_labels = list(set(train_labels))
train_labels = pd.DataFrame(train_labels,columns = ['label'])
for i in range(len(unique_labels)):
	self.real_label.append(unique_labels[i])
    print('class {}'.format(unique_labels[i]))
    templabels = train_labels.copy()
    templabels[templabels.label != unique_labels[i]] = 'F'
    templabels[templabels.label == unique_labels[i]] = 'T'
    templabels[templabels.label == 'T'] = 1
    templabels[templabels.label == 'F'] = 0
    templabels = templabels['label'].tolist()
    print(templabels)

输出结果如下:

class 0
[1, 0, 0, 0, 1, 0, 1, 0]
class 1
[0, 0, 1, 0, 0, 1, 0, 0]
class 2
[0, 0, 0, 1, 0, 0, 0, 1]
class 3
[0, 1, 0, 0, 0, 0, 0, 0]

字符串按列整体处理

df中‘Pub_Date’列的内容为字符串格式的时间’2015/1/5 2:22:01’,现在只保留该时间的日期格式,去掉具体的时刻,并生成df[‘Pub_Month’]用于记录当前消息的发布月份。一个比较自然的想法是使用字符串的split,但是该方法不能对DataFrame的列做成体操作。因此使用DataFrame.str.partition("")方法。首先看一下该方法的输出:

df = pd.read_csv("环保成分股.csv")
part = df['Pub_Date'].str.partition(' ')
df['Pub_Date'] = df['Pub_Date'].str.partition(' ')[0]
print(df['Pub_Date'].head())
print(part.head())
print(type(part))

输出的结果为:

0    2015-01-05
1    2015-01-05
2    2015-01-05
3    2015-01-13
4    2015-01-22
Name: Pub_Date, dtype: object
            0  1         2
0  2015-01-05     02:22:01
1  2015-01-05     05:50:11
2  2015-01-05     07:50:17
3  2015-01-13     14:17:19
4  2015-01-22     15:57:02
<class 'pandas.core.frame.DataFrame'>

可以看到使用partition分割后的返回结果也是DataFrame,只不过分隔符号也占用了一列。且这种方法只能将原来的字符串分为两部分。比如如下使用’-'分割:

df = pd.read_csv("环保成分股.csv")
part = df['Pub_Date'].str.partition('-')
print(part.head())
print(type(part))

输出的结果

      0  1               2
0  2015  -  01-05 02:22:01
1  2015  -  01-05 05:50:11
2  2015  -  01-05 07:50:17
3  2015  -  01-13 14:17:19
4  2015  -  01-22 15:57:02
<class 'pandas.core.frame.DataFrame'>

数据合并

可以看成筛选的另一种形式,基本思路就是依据列属性筛选出符合条件的行数据,之后合并到新的DataFrame中。使用的命令为

newDataframe = pd.DataFrame()
temp = df[筛选条件]
newDataFrame = pd.concat([temp,newDataFrame],ignore_index = True)

例如筛选成体数据样本中的成分股数据代码如下:

#获取成分股数据
stockfile = open('上证环保2015年成分股.txt','r')
stocklist = []
for line in stockfile:
    index = line.split('\t')[2].replace('\n','')
    stocklist.append(index)
stocklist = list(set(stocklist))

#只保留环保成分股的新闻,合并生成新的DataFrame
df = pd.read_csv("网络新闻量化舆情数据库-新闻基本信息综合表.csv")
env = pd.DataFrame()
for i in range(0,len(stocklist)):
    tempenv = df[df.Top_Ment_Stkcd == int(stocklist[i])]
    env = pd.concat([env,tempenv],ignore_index=True)

分组统计函数

这里使用的分许统计函数是groupby。完成的功能时按日期和股票代码分组,同时累加组内TempScore,相当于获得某只股票某日的情感处理值。分组统计使用的是groups[列名].agg(操作),操作包括mean,sum。

df = pd.read_csv("环保成分股.csv")

#按日期和代码分组,情感值按热度加权,同日同股票合并成单条数据
df['TempScore'] = df['Overall_Senti_Score_Adjust'] * df['Popu_Score']
groups = df.groupby(['Pub_Date','Top_Ment_Stkcd'])
print(type(groups))
groupresult = groups['TempScore'].agg('sum')
print(type(groupresult))
print(groupresult.head())
pd.DataFrame(groupresult.to_csv("DailyScore1.csv"))

以上代码输出结果为

<class 'pandas.core.groupby.generic.DataFrameGroupBy'>
<class 'pandas.core.series.Series'>
Pub_Date             Top_Ment_Stkcd
2015-01-02 09:10:44  600133.0         -0.1585
2015-01-02 10:59:48  601727.0          0.5043
2015-01-02 19:06:19  601727.0         -5.1205
2015-01-05 01:45:26  600900.0          1.2480
2015-01-05 01:47:30  600236.0          0.4204
Name: TempScore, dtype: float64

下面分析一下groups的内部结构。遍历groups输出期中一项如下:
groupby产生的结果
可以看出每项中有两个元素:第一个位分组的关键字,这里是时间和股票标号形成的元组;第二个是组内的具体内容,格式是DataFrame。

数据选择

按条件提取DataFrame中某个数据。

weight = float(Weighted[(Weighted['Index1'] == stock)]["Weight"+str(i+1)])

这里的想法比较自然,先按行筛选股票stock,再选取这行的Weight中的数据,这相当于直接按照行列查找,自然有更合乎规范的写法df.loc[行条件,列条件]

weight = float(Weighted.loc[Weighted['Index1'] == stock,"Weight"+str(i+1)])

赋值

将以上提取的数据赋予符合某些条件的行。

tempdf = Dailydf[(Dailydf.Pub_Month == (i+1)) & (Dailydf.Top_Ment_Stkcd == int(stock))].copy()
tempdf["Weight"] = weight

注意生成tempdf的时候最后一定要加.copy()。相当于产新的副本后进行新的操作,不改变原来的样本。不写的话也能执行,但会有Warning:

SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  tempdf["Weight"] = weight
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值