我们最好pd.concat 将它们垂直添加到单个帧中并将其附加到列表中,而不是一个一个地附加计数值和标准化值。
所以原来的代码可以改写成这样:
li = []
for col in df.columns:
value_counts = df[col].value_counts()
value_percentage = df[col].value_counts(normalize=True).map('{:.0%}'.format)
li.append(pd.concat([value_counts, value_percentage]).to_frame().reset_index())
resultdf = pd.concat(li, axis=1)
resultdf.to_excel("resultdf.xlsx")
让 Excel 进行格式化
如果我们让 Excel 自己将数据格式化为百分比会怎样?我认为最简单的方法是使用Styler。但在此之前,我建议摆脱Index 列。正如我所看到的,它们都指的是相同的等级1,2,3,4,5。因此我们可以将它们用作公共索引,从而使索引有意义。此外,我将使用MultiIndex 来分隔计数值和标准化值,如下所示:
formula = ['counts', 'percent']
values = [1, 2, 3, 4, 5]
counted = pd.DataFrame(index=pd.MultiIndex.from_product([formula, values], names=['formula', 'values']))
counted 是我们的数据容器,目前它是空的。让我们填写:
for col in df.columns:
counts = df[col].value_counts()
percent = counts / counts.sum()
counted[col] = pd.concat([counts, percent], keys=formula)
有了这些数据,让我们对它们应用一些样式,然后再转换成 Excel 文件:
styled_data = (
counted.style
.set_properties(**{'number-format': '0'}, subset=pd.IndexSlice['counts', columns])
.set_properties(**{'number-format': '0%'}, subset=pd.IndexSlice['percent', columns])
)
styled_data.to_excel('test.xlsx')
现在我们在 Excel 中的数据如下所示:
它们都是数字,我们可以在进一步的计算中使用它们。
完整代码
from pandas import DataFrame, MultiIndex, IndexSlice, concat
from numpy.random import default_rng
# Initial parameters
rng = default_rng(0)
data_length = 100
genres = ['Pop', 'Dance', 'Rock', 'Jazz']
values = [1, 2, 3, 4, 5]
formula = ['counts', 'percent']
file_name = 'test.xlsx'
# Prepare data
data = rng.integers(min(values), max(values), size=(data_length, len(genres)), endpoint=True)
df = DataFrame(data, columns=genres)
# Prepare a container for counted data
index = MultiIndex.from_product([formula, values], names=['formula', 'values'])
counted = DataFrame(index=index)
# Fill in counted data
for col in df.columns:
counts = df[col].value_counts()
percent = counts / counts.sum()
counted[col] = concat([counts, percent], keys=formula)
# Apply number formatting and save the data in a Excel file
styled_data = (
counted.style
.set_properties(**{'number-format': '0'}, subset=IndexSlice['counts', :])
.set_properties(**{'number-format': '0%'}, subset=IndexSlice['percent', :])
)
styled_data.to_excel(file_name)
附言
注意不要混淆。对于使用的虚拟数据,我们可以在counts 和percent 部分中看到相同的值。那是因为数据是如何构建的。我用了100 个值的总数在初始数据帧df。所以value_counts 的数量和它们的百分比是相等的。
蟒蛇 3.11.0
熊猫 1.5.1
numpy 1.23.4
更新
如果我们想保留原始数据每一列的值,但使用Styler 为输出帧的后半部分设置数字格式,那么我们应该以某种方式重命名Index 列,因为Styler 需要唯一列/传递的DataFrame 中的索引标签。我们可以将它们重命名为“Values.Pop”、“Valuse.Dance”等。或者我们可以对列使用多索引,IMO 看起来更好:
import pandas as pd
from numpy.random import default_rng
rng = default_rng(0)
columns = ['Pop', 'Dance', 'Rock', 'Jazz']
data = rng.integers(1, 5, size=(100, len(columns)), endpoint=True)
df = pd.DataFrame(data, columns=columns)
li = []
for col in df.columns:
value_counts = df[col].value_counts()
value_percentage = value_counts / value_counts.sum()
item = (
pd.concat([value_counts, value_percentage])
.rename('count')
.rename_axis('value')
.to_frame()
.reset_index()
)
li.append(item)
resultdf = pd.concat(li, axis=1, keys=df.columns)
styled_result = (
resultdf.style
.set_properties(
**{'number-format': '0%'},
subset=pd.IndexSlice[len(resultdf)/2:, pd.IndexSlice[:,'count']])
)
styled_result.to_excel('my_new_excel.xlsx')
在这种情况下,输出将如下所示: