#python #pandas #numpy #matrix #pivot-table
#python #панды #numpy #матрица #сводная таблица
Вопрос:
Я хотел бы преобразовать два массива (x и y) в матрицу частот n x n (n = 5), указав в каждой ячейке количество точек, которое содержит. Он заключается в повторной выборке обеих переменных на пять интервалов и подсчете существующего количества точек на ячейку.
Я пытался использовать сводную таблицу pandas, но не знаю, как ссылаться на каждую координату оси. Массивы X и Y — это две зависимые переменные, которые содержат значения от 0 до 100.
Я был бы очень признателен за чью-то помощь. Заранее большое вам спасибо.
Это пример кода:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Arrays example. They are always float type and ranging 0-100. (n_size array = 15)
x = 100 * np.random.random(15)
y = 100 * np.random.random(15)
# Df created for trying to pivot and counting values per cell
df = pd.DataFrame({'X':x,'Y':y})
# Plot the example data:
df.plot(x = 'X',y = 'Y', style = 'o')
Ответ №1:
Если вам явно не нужно использовать pandas
(чего вы не делаете, если речь идет только о частотной матрице), рассмотрите возможность использования numpy.histogram2d
:
# Sample data
x = 100*np.random.random(15)
y = 100*np.random.random(15)
Создайте свои ячейки (поскольку ваши ячейки x и y одинаковы, достаточно одного набора)
bins = np.linspace(0, 100, 5 1)
# bins = array([ 0., 20., 40., 60., 80., 100.])
Теперь используйте функцию гистограммы:
binned, binx, biny = np.histogram2d(x, y, bins = [bins, bins])
# To get the result you desire, transpose
objmat = binned.T
Примечание: значения x привязаны к первому измерению (ось 0), что визуально означает «вертикальный». Отсюда и транспонирование.
Построение графиков:
fig, ax = plt.subplots()
ax.grid()
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)
ax.scatter(x, y)
for i in range(objmat.shape[0]):
for j in range(objmat.shape[1]):
c = int(objmat[::-1][j,i])
ax.text((bins[i] bins[i 1])/2, (bins[j] bins[j 1])/2, str(c), fontdict={'fontsize' : 16, 'ha' : 'center', 'va' : 'center'})
Комментарии:
1. Я выбрал этот ответ, потому что он показался мне самым простым и позволяет изменять ‘n’, но все ответы фантастические. Спасибо всем вам, ребята!
Ответ №2:
Вы могли бы использовать GroupBy.size
сопоставление групповых осей с центром каждой сетки. Затем вы можете использовать Axes.text
их для рисования
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(20)
max_val = 100
n = 5
len_group = max_val // 5
x = max_val * np.random.random(15)
y = max_val * np.random.random(15)
# Df created for trying to pivot and counting values per cell
df = pd.DataFrame({'X':x,'Y':y})
x_groups = df['X'] // len_group * len_group len_group / 2
y_groups = df['Y'] // len_group * len_group len_group / 2
fig, ax= plt.subplots(figsize=(13, 6))
ax.set_ylim(0, max_val)
ax.set_xlim(0, max_val)
df.plot(x = 'X',y = 'Y', style = 'o', ax=ax)
for i, val in df.groupby([x_groups, y_groups]).size().items():
ax.text(*i, val,fontdict={'fontsize' : 20, 'ha' : 'center', 'va':'center'})
plt.grid()
Ответ №3:
Вы можете просто создать ячейки с pd.cut
помощью, а затем разархивировать groupby
ячейки по X
переменной, и у вас будет матрица подсчетов частот.
df['Xc'] = pd.cut(df['X'], range(0, 101, 20))
df['Yc'] = pd.cut(df['Y'], range(0, 101, 20))
mat = df.groupby(['Xc', 'Yc']).size().unstack('Xc')
mat
Xc (0, 20] (20, 40] (40, 60] (60, 80] (80, 100]
Yc
(0, 20] 0 1 1 0 0
(20, 40] 4 0 1 2 0
(40, 60] 0 0 0 0 0
(60, 80] 3 0 1 0 0
(80, 100] 1 0 1 0 0
Ответ №4:
Элегантного решения проблемы построения графика не существует. Но вот что вы можете сделать.
# Calculate the counts
counts = df.groupby([df.X.astype(int) // 20,
df.Y.astype(int) // 20]).size().astype(str)
# Restore the original scales
counts.index = pd.MultiIndex.from_tuples([(x * 20 10,
y * 20 10)
for x,y in counts.index.to_list()],
names=counts.index.names)
fig = plt.figure()
ax = fig.add_subplot(111)
# Plot the text labels
[ax.text(*xy, txt) for (xy, txt) in counts.items()]
# Update the axes extents
ax.axis([0, counts.index.levels[0].max() 10,
0, counts.index.levels[1].max() 10])
plt.show()
Ответ №5:
import pandas as pd
import numpy as np
import seaborn as sns
sns.set_style("whitegrid")
# Arrays example. They are always float type and ranging 0-100. (n_size array = 15)
x = 100 * np.random.random(15)
y = 100 * np.random.random(15)
# Df created for trying to pivot and counting values per cell
df = pd.DataFrame({'X':x,'Y':y})
ir = pd.interval_range(start=0, freq=20, end=100, closed='left')
df['xbin'] = pd.cut(df['X'], bins=ir)
df['ybin'] = pd.cut(df['Y'], bins=ir)
df['xbin'] = df['xbin'].apply(lambda x: x.mid)
df['ybin'] = df['ybin'].apply(lambda x: x.mid)
fig, ax= plt.subplots()
ax.set_ylim(0, 100)
ax.set_xlim(0, 100)
for i, val in df.groupby(['xbin', 'ybin']).size().items():
if val!=0:
ax.text(*i, val,fontdict={'fontsize' : 20, 'ha' : 'center', 'va' : 'center'})
Ответ №6:
Одним из вариантов является вызов np.add.at
ravel
матрицы частот
x = 100 * np.random.random(15)
y = 100 * np.random.random(15)
n = 5
points = (np.array([x, y]) / 20).astype(int)
z = np.zeros((n, n), dtype=int)
np.add.at(z.ravel(),
np.ravel_multi_index(points, z.shape),
np.ones(points.shape[1]))
Пример запуска:
print(points)
print(z)
[[0 0 0 2 4 1 2 1 1 0 1 1 3 0 0]
[0 0 1 4 0 4 1 0 1 3 3 1 0 0 3]]
[[3 1 0 2 0]
[1 2 0 1 1]
[0 1 0 0 1]
[1 0 0 0 0]
[1 0 0 0 0]]