Python 3.x 将数据帧列分为十进制并附加到矩阵
tl;dr:我的代码实现了我想要的功能,除了一个元素:为每个代码块定义Python 3.x 将数据帧列分为十进制并附加到矩阵,python-3.x,pandas,Python 3.x,Pandas,tl;dr:我的代码实现了我想要的功能,除了一个元素:为每个代码块定义tick\u slice的行不会返回所需的切片。如果您想跳过我的数据的详细信息,请跳到下面以“我的问题:”开头的第4段 我有下面的代码,其中我将csv文件读入一个数据帧。csv文件中的数据按如下方式组织:第一行包含格式为YYYYMMDD的日期,该格式在350列中按降序排列。在每列(每个日期下方)中都有唯一的标识符(有点像股票符号)。大多数列的行数不同,从几百行到几千行不等,标识符从“最佳”到“最差”排序 我的愿望是制作一个矩阵
tick\u slice
的行不会返回所需的切片。如果您想跳过我的数据的详细信息,请跳到下面以“我的问题:”开头的第4段
我有下面的代码,其中我将csv文件读入一个数据帧。csv文件中的数据按如下方式组织:第一行包含格式为YYYYMMDD的日期,该格式在350列中按降序排列。在每列(每个日期下方)中都有唯一的标识符(有点像股票符号)。大多数列的行数不同,从几百行到几千行不等,标识符从“最佳”到“最差”排序
我的愿望是制作一个矩阵(然后输出到一个新的csv文件)。该矩阵按如下方式构建:从输入csv数据的第一列开始,获取标识符的前十分位(10%),并将其放置在输出矩阵的第一列。接下来,移动到输入csv数据的第二列,从该列中获取标识符的前十分位,并将这些标识符放置在输出矩阵的第一列中,位于第一步中放置的数据下方。按照变量hld\u per
给出的次数重复此操作。然后向右移动一列并重复这些步骤。因此,在我当前的代码中,嵌套for循环将首先覆盖输入csv数据的第1:12列,然后是第2:13列,以此类推
我目前有十个重复的代码块,以创建10个输出文件,每十分之一个,从最好到最坏(下面的代码只显示前两个十块,以节省空间;此外,我知道重复这个代码块10次是低效的,但我会在当前代码按预期工作后解决这个问题)
我的问题:下面的代码实现了我想要的大部分功能,但是为每个嵌套for循环定义tick\u slice
的行并没有按预期工作。原因如下:例如,假设一列有35个标识符。如前所述,我的前九个十分位数将分别包含3个标识符,第十个十分位数将包含8个标识符。我希望十个十分位数的大小尽可能一致。我已经看过qcut,但我不知道如何应用它
非常感谢您的帮助。此外,如果有一种完全不同的方式在熊猫身上实现这一点,我当然愿意接受任何建议
部分代码:
import pandas as pd
hld_per = 12
quantiles = 10
permnos = pd.read_csv('Ranks.csv')
my_headers = list(permnos.columns)
total_cols = len(permnos.columns)
ports1 = []
for i in range(total_cols-(hld_per-1)):
permlist = []
for j in range(hld_per):
tick_slice = int(permnos.iloc[:,i+j].count()/quantiles)
col_slice = permnos.iloc[0:tick_slice, i+j].tolist()
permlist = permlist + col_slice
ports1.append(permlist)
matrix = pd.DataFrame(ports1)
matrix = matrix.T
matrix.columns = my_headers[0:len(matrix.columns)]
matrix.to_csv('ports1.csv', sep=',', index=False, header=True)
ports2 = []
for i in range(total_cols-(hld_per-1)):
permlist = []
for j in range(hld_per):
tick_slice = int(permnos.iloc[:,i+j].count()/quantiles)
col_slice = permnos.iloc[tick_slice:tick_slice*2, i+j].tolist()
permlist = permlist + col_slice
ports2.append(permlist)
matrix = pd.DataFrame(ports2)
matrix = matrix.T
matrix.columns = my_headers[0:len(matrix.columns)]
matrix.to_csv('ports2.csv', sep=',', index=False, header=True)
根据该代码,permnos.head()
生成:
20131231 20131130 20131031 20130930 20130831 20130731 20130630 \
0 93044.0 93044.0 13264 13264 89169.0 82486.0 91274.0
1 79702.0 91515.0 90710 81148 47387.0 88359.0 93353.0
2 85751.0 85724.0 88810 11513 85576.0 47387.0 85576.0
3 85576.0 89169.0 81562 81562 81148.0 10294.0 10294.0
4 13264.0 90710.0 82281 47387 11285.0 90710.0 47387.0
20131231 20131130 20131031 20130930 20130831 20130731 20130630 \
0 93044.0 93044.0 13264.0 13264.0 89169.0 82486.0 91274.0
1 79702.0 91515.0 90710.0 81148.0 47387.0 88359.0 93353.0
2 85751.0 85724.0 88810.0 11513.0 85576.0 47387.0 85576.0
3 93044.0 13264.0 13264.0 89169.0 82486.0 91274.0 85653.0
4 91515.0 90710.0 81148.0 47387.0 88359.0 93353.0 91274.0
20131231 20131130 20131031 20130930 20130831 20130731 20130630 \
0 85576.0 89169.0 81562.0 81562.0 81148.0 10294.0 10294.0
1 13264.0 90710.0 82281.0 47387.0 11285.0 90710.0 47387.0
2 90539.0 47387.0 93044.0 92805.0 82281.0 89169.0 66852.0
3 89169.0 81562.0 81562.0 81148.0 10294.0 10294.0 89169.0
4 90710.0 82281.0 47387.0 11285.0 90710.0 47387.0 93353.0
matrix.head()
对于ports1
生成:
20131231 20131130 20131031 20130930 20130831 20130731 20130630 \
0 93044.0 93044.0 13264 13264 89169.0 82486.0 91274.0
1 79702.0 91515.0 90710 81148 47387.0 88359.0 93353.0
2 85751.0 85724.0 88810 11513 85576.0 47387.0 85576.0
3 85576.0 89169.0 81562 81562 81148.0 10294.0 10294.0
4 13264.0 90710.0 82281 47387 11285.0 90710.0 47387.0
20131231 20131130 20131031 20130930 20130831 20130731 20130630 \
0 93044.0 93044.0 13264.0 13264.0 89169.0 82486.0 91274.0
1 79702.0 91515.0 90710.0 81148.0 47387.0 88359.0 93353.0
2 85751.0 85724.0 88810.0 11513.0 85576.0 47387.0 85576.0
3 93044.0 13264.0 13264.0 89169.0 82486.0 91274.0 85653.0
4 91515.0 90710.0 81148.0 47387.0 88359.0 93353.0 91274.0
20131231 20131130 20131031 20130930 20130831 20130731 20130630 \
0 85576.0 89169.0 81562.0 81562.0 81148.0 10294.0 10294.0
1 13264.0 90710.0 82281.0 47387.0 11285.0 90710.0 47387.0
2 90539.0 47387.0 93044.0 92805.0 82281.0 89169.0 66852.0
3 89169.0 81562.0 81562.0 81148.0 10294.0 10294.0 89169.0
4 90710.0 82281.0 47387.0 11285.0 90710.0 47387.0 93353.0
matrix.head()
对于ports2
产生:
20131231 20131130 20131031 20130930 20130831 20130731 20130630 \
0 93044.0 93044.0 13264 13264 89169.0 82486.0 91274.0
1 79702.0 91515.0 90710 81148 47387.0 88359.0 93353.0
2 85751.0 85724.0 88810 11513 85576.0 47387.0 85576.0
3 85576.0 89169.0 81562 81562 81148.0 10294.0 10294.0
4 13264.0 90710.0 82281 47387 11285.0 90710.0 47387.0
20131231 20131130 20131031 20130930 20130831 20130731 20130630 \
0 93044.0 93044.0 13264.0 13264.0 89169.0 82486.0 91274.0
1 79702.0 91515.0 90710.0 81148.0 47387.0 88359.0 93353.0
2 85751.0 85724.0 88810.0 11513.0 85576.0 47387.0 85576.0
3 93044.0 13264.0 13264.0 89169.0 82486.0 91274.0 85653.0
4 91515.0 90710.0 81148.0 47387.0 88359.0 93353.0 91274.0
20131231 20131130 20131031 20130930 20130831 20130731 20130630 \
0 85576.0 89169.0 81562.0 81562.0 81148.0 10294.0 10294.0
1 13264.0 90710.0 82281.0 47387.0 11285.0 90710.0 47387.0
2 90539.0 47387.0 93044.0 92805.0 82281.0 89169.0 66852.0
3 89169.0 81562.0 81562.0 81148.0 10294.0 10294.0 89169.0
4 90710.0 82281.0 47387.0 11285.0 90710.0 47387.0 93353.0
如果我理解正确,那么是的,
qcut()
可以为您提供所需的拆分
我们将首先构建一个示例permnos
数据帧。这是基于OPpermnos.head()
,加上几个额外的行来说明列长度的异构性
import pandas as pd
data = {'20130630': {0: 91274.0, 1: 93353.0, 2: 85576.0, 3: 10294.0, 4: 47387.0, 5: np.nan, 6: np.nan},
'20130731': {0: 82486.0, 1: 88359.0, 2: 47387.0, 3: 10294.0, 4: 90710.0},
'20130831': {0: 89169.0, 1: 47387.0, 2: 85576.0, 3: 81148.0, 4: 11285.0},
'20130930': {0: 13264, 1: 81148, 2: 11513, 3: 81562, 4: np.nan},
'20131031': {0: 13264, 1: 90710, 2: 88810, 3: 81562, 4: 82281},
'20131130': {0: 93044.0, 1: 91515.0, 2: 85724.0, 3: 89169.0, 4: 90710.0, 5: 80000., 6: 900000.},
'20131231': {0: 93044.0, 1: 79702.0, 2: 85751.0, 3: 85576.0, 4: 13264.0, 5: np.nan}}
permnos = pd.DataFrame(data)
permnos
20130630 20130731 20130831 20130930 20131031 20131130 20131231
0 91274.0 82486.0 89169.0 13264.0 13264.0 93044.0 93044.0
1 93353.0 88359.0 47387.0 81148.0 90710.0 91515.0 79702.0
2 85576.0 47387.0 85576.0 11513.0 88810.0 85724.0 85751.0
3 10294.0 10294.0 81148.0 81562.0 81562.0 89169.0 85576.0
4 47387.0 90710.0 11285.0 NaN 82281.0 90710.0 13264.0
5 NaN NaN NaN NaN NaN 80000.0 NaN
6 NaN NaN NaN NaN NaN 900000.0 NaN
考虑什么qcut()
:
out:如果标签为False,则为整数的分类或序列或数组返回类型(分类或系列)取决于输入:如果输入是系列,则返回类型类别的系列 我们正在传递序列数据,因此我们将获得一系列类型
category
作为输出。例如:
n_bin = 3
out = pd.qcut(permnos["20130630"].dropna(), n_bin)
out
0 (89374.667, 93353.0]
1 (89374.667, 93353.0]
2 (60116.667, 89374.667]
3 (10293.999, 60116.667]
4 (10293.999, 60116.667]
Name: 20130630, dtype: category
Categories (3, interval[float64]): [(10293.999, 60116.667] < (60116.667, 89374.667] < (89374.667, 93353.0]]
使用这种方法,我们应该能够通过只获取在每次迭代的目标分位数中扣合的条目,从每个列中获取我们想要的切片
我们可以通过将核心操作包装在一个函数中,construct\u matrix()
来压缩一些内容
UDPATED(根据注释,适用于多个矩阵) 考虑到我们可能希望基于
n_-bin
构建任意数量的矩阵,我们建立了一个construct_-matrix()
循环,其中第一个循环之后的每个新start_-pos
都是start_-pos
+end_-pos
,这是在上一次迭代的函数中设置的。我们将结果矩阵存储在列表中,矩阵
matrices = []
start_pos = 0
# number of qcut bins
n_bin = 3
for i in range(1, n_bin):
end_cat = n_bin - i
print("matrix: {}, start_pos: {}, end_cat: {}".format(i, start_pos, end_cat))
matrix, start_pos = construct_matrix(permnos, hld_per, total_cols, n_bin, my_headers,
start_pos=start_pos, end_cat=end_cat)
matrices.append(matrix)
print(matrix)
print()
输出:
matrix: 1, start_pos: 0, end_cat: 2
20130630 20130731 20130831
0 91274.0 82486.0 89169.0
1 93353.0 88359.0 47387.0
2 82486.0 89169.0 13264.0
3 88359.0 47387.0 81148.0
4 89169.0 13264.0 13264.0
5 47387.0 81148.0 90710.0
6 13264.0 13264.0 93044.0
7 81148.0 90710.0 91515.0
8 13264.0 93044.0 85724.0
9 90710.0 91515.0 93044.0
10 NaN 85724.0 79702.0
matrix: 2, start_pos: 2, end_cat: 1
20130630 20130731 20130831
0 85576.0 47387.0 85576.0
1 47387.0 85576.0 11513.0
2 85576.0 11513.0 88810.0
3 11513.0 88810.0 85724.0
4 88810.0 85724.0 89169.0
5 NaN 89169.0 85751.0
这将使您能够(大致)在列和分位数之间找到所需的均匀分割。我从未能够使用
qcut
为这一点设计解决方案,但我已经找到了一种适合我的规格的替代解决方案。希望其他人也能发现这一点
import pandas as pd
hld_per = 12
quantiles = 10
permnos = pd.read_csv('Ranks.csv')
my_headers = list(permnos.columns)
total_cols = len(permnos.columns)
def slice_range(col_length, quantile):
increment = col_length // 10
remainder = col_length % 10 + 1
addon = 0
for i in range(quantile-1):
remainder = max(0, remainder - 1)
if remainder > 0:
addon += 1
start = (quantile - 1) * increment + addon
return start
for i in range(quantiles):
ports = []
for j in range(total_cols-(hld_per-1)):
permlist = []
for k in range(hld_per):
col_len = permnos.iloc[:,j+k].count()
start = slice_range(col_len, i+1)
end = slice_range(col_len, (i+2))
col_slice = permnos.iloc[start:end, j+k].tolist()
permlist += col_slice
ports.append(permlist)
matrix = pd.DataFrame(ports).T
matrix.columns = my_headers[0:len(matrix.columns)]
matrix.to_csv("portstst5_" + str(i+1) + ".csv", sep=',', index=False, header=True)
如果您能够提供您描述的数据示例以及所需的输出,这将非常有用。看见它现在的描述方式有点混乱;希望这个被截断的例子能有所帮助。对于输入文件,假设前三列分别具有日期头20161231、20161130和20161031。在20161231之下是标识符1到30(30个标识符);20161130以下为31至70(40个标识符);20161031以下为71至105(35个标识符)。前2个输入列很简单,因为它们除以10;第三是麻烦。在输出的第1列中,您将看到1、2、3、31、32、33、34、71、72、73,可能还有74。我的问题是如何最好地将第3列划分为大致相等的存储桶。你能为
ports1
和ports2
发布permnos.head()
和matrix.head()
吗?@andrew_reece我现在已经在原始问题中发布了这一点(请告诉我这条评论是否不必要,是否应该删除)。谢谢。我尝试使用n_bin=10,并通过matrix10生成matrix1。matrix1和matrix2都工作得很好。矩阵3到10不起作用。根据我的测试,原因似乎是由于start=(out==out.cat.categories[start\u cat]).sum()
(和end\u cat)为matrix2到10生成了相同的start
。如果我理解正确,这是因为每个类别出现的次数相同(或接近)。这怎么能适应,,