Python
# Import Libraries
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from scipy.stats import zscore

# Configurasi plot
sns.set(style="whitegrid")

# Data Input
data = {
    'No': list(range(1, 151)),
    'VD': [8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 6, 4, 5, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9, 5, 6, 4, 7, 8, 3, 9],
    'VP': [5, 8, 7, 3, 9, 6, 5, 4, 7, 5, 4, 9, 8, 3, 6, 4, 8, 3, 7, 5, 6, 9, 4, 6, 7, 5, 8, 9, 3, 7, 6, 4, 9, 8, 3, 5, 6, 4, 7, 8, 3, 9, 6, 5, 8, 4, 7, 9, 6, 5, 8, 4, 3, 7, 5, 6, 9, 4, 5, 7, 9, 3, 6, 5, 7, 8, 4, 5, 9, 3, 6, 4, 5, 7, 8, 3, 6, 9, 4, 5, 3, 7, 8, 9, 4, 5, 7, 6, 4, 9, 3, 5, 7, 8, 3, 5, 9, 6, 4, 5, 7, 8, 4, 9, 6, 5, 7, 8, 4, 7, 9, 6, 5, 4, 7, 8, 4, 9, 5, 6, 4, 7, 3, 4, 9, 8, 3, 7, 6, 4, 9, 5, 8, 3, 7, 6, 4, 9, 3, 5, 4, 9, 6, 3, 8, 7, 5, 4, 9, 7],
    'VS': [7, 6, 4, 8, 5, 3, 9, 6, 5, 8, 3, 6, 4, 9, 5, 7, 6, 4, 9, 8, 3, 5, 8, 7, 4, 9, 3, 6, 4, 5, 8, 3, 7, 5, 9, 4, 7, 6, 3, 9, 5, 4, 7, 9, 3, 6, 5, 8, 3, 7, 6, 5, 9, 4, 8, 3, 5, 7, 6, 3, 8, 5, 4, 9, 6, 3, 7, 8, 6, 5, 9, 7, 6, 3, 4, 9, 5, 3, 8, 7, 6, 4, 5, 3, 6, 9, 4, 3, 8, 5, 6, 4, 9, 6, 4, 7, 3, 5, 9, 6, 4, 3, 7, 5, 3, 4, 9, 6, 3, 5, 8, 3, 9, 6, 5, 3, 7, 6, 3, 9, 5, 6, 8, 7, 5, 6, 4, 9, 5, 8, 7, 3, 6, 5, 4, 8, 8, 5, 7, 6, 3, 5, 7, 4, 9, 6, 3, 9, 6, 5]
}

df = pd.DataFrame(data)
df.set_index('No', inplace=True)

# Person Fit Analysis
# Menghitung Infit dan Outfit
df['Infit_MNSQ'] = (df['VD'] - df['VD'].mean())**2 / df['VD'].var()
df['Outfit_MNSQ'] = (df['VP'] - df['VP'].mean())**2 / df['VP'].var()

# Visualisasi
plt.figure(figsize=(12, 6))
sns.scatterplot(data=df, x='Infit_MNSQ', y='Outfit_MNSQ', hue='VS', palette='coolwarm', legend='full')
plt.axhline(1.0, color='red', linestyle='--', label='Ideal Fit')
plt.axvline(1.0, color='red', linestyle='--')
plt.title('Person Fit Analysis')
plt.xlabel('Infit Mean Square')
plt.ylabel('Outfit Mean Square')
plt.legend(title='VS Score')
plt.show()

# Differential Item Functioning (DIF) Analysis
# Membagi data berdasarkan median
median_vd = df['VD'].median()
df['Group'] = np.where(df['VD'] >= median_vd, 'High VD', 'Low VD')

# Menghitung rata-rata setiap kelompok
group_means = df.groupby('Group').mean()

# Visualisasi
plt.figure(figsize=(12, 6))
sns.barplot(x=group_means.index, y=group_means['VP'], palette='muted')
plt.title('Differential Item Functioning Analysis')
plt.xlabel('VD Group')
plt.ylabel('Average VP Score')
plt.show()

# Test Information Function (TIF)
# Menghitung informasi tes
abilities = np.linspace(df['VS'].min(), df['VS'].max(), 100)
test_information = []

for ability in abilities:
    information = np.sum((ability - df['VS'])**2)
    test_information.append(information)

# Visualisasi TIF
plt.figure(figsize=(12, 6))
plt.plot(abilities, test_information, color='blue', label='Test Information')
plt.title('Test Information Function')
plt.xlabel('Ability')
plt.ylabel('Information')
plt.legend()
plt.show()

# Person-Item Map
plt.figure(figsize=(12, 8))
plt.scatter(df['VD'], df['VS'], color='green', label='Items')
plt.scatter(df['VP'], df['VS'], color='blue', label='Persons')
plt.axhline(y=df['VS'].mean(), color='red', linestyle='--', label='Average VS')
plt.title('Person-Item Map')
plt.xlabel('VD & VP Scores')
plt.ylabel('VS Scores')
plt.legend()
plt.show()

# Histogram Distribution
plt.figure(figsize=(18, 6))
plt.subplot(1, 3, 1)
sns.histplot(df['VD'], bins=10, kde=True, color='blue')
plt.title('Histogram of VD')

plt.subplot(1, 3, 2)
sns.histplot(df['VP'], bins=10, kde=True, color='green')
plt.title('Histogram of VP')

plt.subplot(1, 3, 3)
sns.histplot(df['VS'], bins=10, kde=True, color='red')
plt.title('Histogram of VS')

plt.tight_layout()
plt.show()

# Person Separation Index (PSI)
person_variance = df[['VD', 'VP', 'VS']].var().mean()
error_variance = (df['Infit_MNSQ'] + df['Outfit_MNSQ']).var() / 2
psi = (person_variance - error_variance) / person_variance

print(f'Person Separation Index (PSI): {psi:.2f}')

# Rasch Reliability
rasch_reliability = 1 - (error_variance / person_variance)

print(f'Rasch Reliability: {rasch_reliability:.2f}')
Person Separation Index (PSI): 0.85
Rasch Reliability: 0.85
script.py:50: FutureWarning: 

Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `x` variable to `hue` and set `legend=False` for the same effect.

  sns.barplot(x=group_means.index, y=group_means['VP'], palette='muted')