У меня есть данные Pandas о мощности генератора (МВт) по типу топлива.Я хотел показать предполагаемое распределение мощности завода двумя способами: по заводу (легко) и по МВт (сложнее).Вот пример:
# import libraries
import pandas as pd
import numpy as np
import seaborn as sns
# generate empty dataframe
df = pd.DataFrame(data=None,columns=['Fuel','MW'])
# create and seed a randomstate object (to make #s repeatable below)
rnd = np.random.RandomState(7)
# generate fake data for each fuel type and append to df
for myfuel in ['Biomass','Coal','Hydro','Natural Gas','Oil','Solar','Wind','Other']:
mymean = rnd.uniform(low=2.8,high=3.2)
mysigma = rnd.uniform(low=0.6,high=1.0)
df = df.append(
pd.DataFrame({'Fuel': myfuel,
'MW': np.array(rnd.lognormal(mean=mymean,sigma=mysigma,size=1000))
}),
ignore_index=True
)
# make violinplot
sns.violinplot(x = 'Fuel',
y = 'MW',
data=df,
inner=None,
scale='area',
cut=0,
linewidth=0.5
)
А вот график предполагаемых распределений размера завода по МВт, который составляет этот код:
![un-weighted violinplot](https://i.stack.imgur.com/D2jv7.png)
Эта скрипка очень обманчива и лишена контекста.Поскольку он не взвешен, тонкий хвост в верхней части каждой категории скрывает тот факт, что относительно немного растений в хвосте содержат много (возможно, даже большую часть) МВт мощности.Поэтому я хочу второй сюжет с распределением по MWs - по сути, это взвешенная версия этого первого скрипичного сюжета.
Я хотел бы знать, нашел ли кто-нибудь изящный способ сделать такой«взвешенный» участок скрипки, или если у кого-то есть идея о самом изящном способе сделать это.
Я подумал, что мог бы пройтись по каждой строке моего кадра данных уровня завода и разложить данные завода (в новый кадр данных) в данные уровня MW.Например, для строки в кадре данных уровня завода, на котором показана установка мощностью 350 МВт, я мог бы разложить ее на 3500 новых строк моего нового кадра данных, каждый из которых представляет мощность 100 кВт.(Я думаю, что мне нужно перейти как минимум к уровню разрешения 100 кВт, потому что некоторые из этих станций довольно малы, в диапазоне 100 кВт.) Этот новый кадр данных будет огромным, но тогда я мог бы сделать скрипку с разложеннымданные.Это казалось немного грубой силой.Есть лучшие идеи для подхода?
Обновление:
Я реализовал метод грубой силы, описанный выше.Вот как это выглядит, если кому-то интересно.Это не «ответ» на этот вопрос, потому что мне все равно было бы интересно, если кто-нибудь знает более элегантный / простой / эффективный способ сделать это.Поэтому, пожалуйста, присоединяйтесь, если вы знаете такой способ.В противном случае, я надеюсь, что этот метод грубой силы мог бы пригодиться кому-то в будущем.
Чтобы было легко понять, что взвешенный план скрипки имеет смысл, я заменил случайные данные на простой однородный ряд чисел от 010. В соответствии с этим новым подходом, участок скрипки df должен выглядеть довольно равномерно, а участок скрипки взвешенных данных (dfw) должен постепенно расширяться к вершине скрипки.Это именно то, что происходит (см. Изображение скрипичных участков ниже).
# import libraries
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# generate empty dataframe
df = pd.DataFrame(data=None,columns=['Fuel','MW'])
# generate fake data for each fuel type and append to df
for myfuel in ['Biomass','Coal','Hydro','Natural Gas','Oil','Solar','Wind','Other']:
df = df.append(
pd.DataFrame({'Fuel': myfuel,
# To make it easy to see that the violinplot of dfw (below)
# makes sense, here we'll just use a simple range list from
# 0 to 10
'MW': np.array(range(11))
}),
ignore_index=True
)
# I have to recast the data type here to avoid an error when using violinplot below
df.MW = df.MW.astype(float)
# create another empty dataframe
dfw = pd.DataFrame(data=None,columns=['Fuel','MW'])
# since dfw will be huge, specify data types (in particular, use "category" for Fuel to limit dfw size)
dfw = dfw.astype(dtype={'Fuel':'category', 'MW':'float'})
# Define the MW size by which to normalize all of the units
# Careful: too big -> loss of fidelity in data for small plants
# too small -> dfw will need to store an enormous amount of data
norm = 0.1 # this is in MW, so 0.1 MW = 100 kW
# Define a var to represent (for each row) how many basic units
# of size = norm there are in each row
mynum = 0
# loop through rows of df
for index, row in df.iterrows():
# calculate and store the number of norm MW there are within the MW of each plant
mynum = int(round(row['MW']/norm))
# insert mynum rows into dfw, each with Fuel = row['Fuel'] and MW = row['MW']
dfw = dfw.append(
pd.DataFrame({'Fuel': row['Fuel'],
'MW': np.array([row['MW']]*mynum,dtype='float')
}),
ignore_index=True
)
# Set up figure and axes
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, sharey='row')
# make violinplot
sns.violinplot(x = 'Fuel',
y = 'MW',
data=df,
inner=None,
scale='area',
cut=0,
linewidth=0.5,
ax = ax1
)
# make violinplot
sns.violinplot(x = 'Fuel',
y = 'MW',
data=dfw,
inner=None,
scale='area',
cut=0,
linewidth=0.5,
ax = ax2
)
# loop through the set of tick labels for both axes
# set tick label size and rotation
for item in (ax1.get_xticklabels() + ax2.get_xticklabels()):
item.set_fontsize(8)
item.set_rotation(30)
item.set_horizontalalignment('right')
plt.show()
![un-weighted and weighted violinplots](https://i.stack.imgur.com/fLrVQ.png)