- Przygotowanie środowiska Jupyter do pracy z projektem.
from pyspark.sql.dataframe import DataFrame
from pyspark.sql import SparkSession
spark = SparkSession(sc)
- Pobieramy dane z pliku "gcredit.csv" i umieszczamy w pliku DataFrame. Plik zawiera opisy kolumn.
df = spark.read.format('com.databricks.spark.csv').\
options(header='true', \
inferschema='true').load("/home/spark/files/gcredit.csv",header=True);
- Wylistowanie kolumn zawartych w dokumencie.
df.columns
- Analiza danych zawartych w pliku danych z wykorzystaniem funkcji describe(). Funkcja describe() zwraca większość wyników statystycznych,
takich jak wartość min, mediana, maksimum, kwartyle i odchylenie standardowe. Za pomocą funkcji zdefiniowanej przez użytkownika
można uzyskać jeszcze więcej wyników statystycznych.
df[['Account Balance','No of dependents']].toPandas().describe()
- Do realizacji kolejnego zadania przygotowana została funkcja która zwraca kwartyle i percentyle
def describe_pd(df_in, columns, style):
'''
Function to union the basic stats results and deciles
:param df_in: the input dataframe
:param columns: the cloumn name list of the numerical variable
:param style: the display style
:return : the numerical describe info. of the input dataframe
:author: Wenqiang Feng
:email: von198@gmail.com
'''
if style == 1:
percentiles = [25, 50, 75]
else:
percentiles = np.array(range(0, 110, 10))
percs = np.transpose([np.percentile(df_in.select(x).collect(), percentiles) for x in columns])
percs = pd.DataFrame(percs, columns=columns)
percs['summary'] = [str(p) + '%' for p in percentiles]
spark_describe = df_in.describe().toPandas()
new_df = pd.concat([spark_describe, percs],ignore_index=True,sort=True)
new_df = new_df.round(2)
return new_df[['summary'] + columns]
- Do prezentacji funkcji zostaną wybrane następujące parametry: "Account Balance" i "No of dependents". Na początek prezentacja
wartości parametrów dla funkcjonalności standardowej a następnie z utworzoną funkcją.
num_cols = ['Account Balance','No of dependents']
- Przetwarzanie wybranych danych z wykorzystaniem describe().
df.select(num_cols).describe().show()
- Przetworzenie danych z wykorzystaniem opracowanej funkcji wymaga dołączenia pakietów: numpy i pandas.
import numpy as np
import pandas as pd
- Przetworzenie danych z wykorzystaniem describe() z opracowaną funkcją.
output = describe_pd(df,num_cols,1)
output['summary']= output['summary'].astype(str)
# convert just columns
output[num_cols] = output[num_cols].apply(pd.to_numeric)
output.dtypes
spark.createDataFrame(output).show()
- Przetwarzanie danych z wykorzystaniem opracowanej funkcji w wersji z percyntylami.
output = describe_pd(df,num_cols,2)
output['summary']= output['summary'].astype(str)
# convert just columns
output[num_cols] = output[num_cols].apply(pd.to_numeric)
spark.createDataFrame(output).show()
- Współczynnik skośności i kurtoza [6,7,8].
- Kurtoza
- Kurtoza jest miarą koncentracji wyników. Kurtoza informuje nas o tym, na ile nasze obserwacje,
wyniki są skoncentrowane wokół średniej.
Miara ta informuje nas jak dużo naszych wyników / obserwacji jest zbliżona do wartości średniej,
czy większość z zaobserwowanych wyników ma wartość podobną do średniej?
Rozkłady prawdopodobieństwa można podzielić ze względu na wartość kurtozy na rozkłady:
- mezokurtyczne (rozkład normalny K = 0 ) - wartość kurtozy wynosi 0, spłaszczenie rozkładu jest podobne
do spłaszczenia rozkładu normalnego (dla którego kurtoza wynosi dokładnie 0)
- leptokurtyczne (rozkład wysmukły K > 0 ) - kurtoza jest dodatnia, wartości cechy bardziej
skoncentrowane niż przy rozkładzie normalnym
- platokurtyczne (rozkład spłaszczony K < 0 ) - kurtoza jest ujemna,
wartości cechy mniej skoncentrowane niż przy rozkładzie normalnym
- Współczynnik skośności
- Skośność jest miarą asymetrii obserwowanych wyników. Informuje nas o tym jak wyniki dla danej
zmiennej kształtują się wokół średniej. Czy większość zaobserwowanych wyników jest z lewej strony średniej,
blisko wartości średniej czy z prawej strony średniej?
Innymi słowy, czy w naszym zbiorze obserwacji więcej jest wyników, które są niższe niż średnia
dla całej grupy, wyższe czy równe średniej?
Współczynnik skośności przyjmuje wartość zero dla rozkładu symetrycznego, wartości ujemne dla rozkładów o lewostronnej
asymetrii (wydłużone lewe ramię rozkładu) i wartości dodatnie dla rozkładów o prawostronnej asymetrii (wydłużone prawe ramię rozkładu).
W ramach testu sprawdzimy rozkład dla parametru "Age (years)".
var = 'Age (years)'
# pyspark.sql.function
#df.select(skewness(var),kurtosis(var)).show()
# pandas skew(), kurtosis()
df[['Age (years)']].toPandas().skew(),df[['Age (years)']].toPandas().kurtosis()
- Histogramy. Różnica pomiędzy histogramem i wykresem słupkowym [9].
Do kolejnych zadań wykorzystamy dane 'Credit Amount' i 'Age (years)'. Na początek wyświetlmy wartości parametru 'Credit Amount'.
df.select('Credit Amount').show(5)
- W kolejnym zadaniu analizujemy wiek osób które pobierały kredyt. Wynikiem realizacji
tego punktu będzie histogram liczby kredytów w zależności od wieku.
data1 = df.select('Age (years)').toPandas()
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
%matplotlib inline
plt.rcParams['figure.figsize'] =(16,9)
plt.style.use('ggplot')
sns.set()
var = 'Age (years)'
x = data1[var]
bins = np.arange(0, 100, 5.0)
plt.figure(figsize=(10,8))
# the histogram of the data
plt.hist(x, bins, alpha=0.8, histtype='bar', color='gold',
ec='black',weights=np.zeros_like(x) + 100. / x.size)
plt.xlabel(var)
plt.ylabel('percentage')
plt.xticks(bins)
plt.show()
#fig.savefig(var+".pdf", bbox_inches='tight')
- Kolejny skrypt umożliwi wyświetlenie liczby kredytów i ich procentowego udziału w zależności od wieku kredytobiorców.
var = 'Age (years)'
x = data1[var]
bins = np.arange(0, 100, 5.0)
########################################################################
hist, bin_edges = np.histogram(x,bins,
weights=np.zeros_like(x) + 100. / x.size)
# make the histogram
fig = plt.figure(figsize=(20, 8))
ax = fig.add_subplot(1, 2, 1)
# Plot the histogram heights against integers on the x axis
ax.bar(range(len(hist)),hist,width=1,alpha=0.8,ec ='black', color='gold')
# # Set the ticks to the middle of the bars
ax.set_xticks([0.5+i for i,j in enumerate(hist)])
# Set the xticklabels to a string that tells us what the bin edges were
labels =['{}'.format(int(bins[i+1])) for i,j in enumerate(hist)]
#labels.insert(0,'0')
ax.set_xticklabels(labels)
plt.xlabel(var)
plt.ylabel('percentage')
########################################################################
hist, bin_edges = np.histogram(x,bins) # make the histogram
ax = fig.add_subplot(1, 2, 2)
# Plot the histogram heights against integers on the x axis
ax.bar(range(len(hist)),hist,width=1,alpha=0.8,ec ='black', color='gold')
# # Set the ticks to the middle of the bars
ax.set_xticks([0.5+i for i,j in enumerate(hist)])
# Set the xticklabels to a string that tells us what the bin edges were
labels =['{}'.format(int(bins[i+1])) for i,j in enumerate(hist)]
#labels.insert(0,'0')
ax.set_xticklabels(labels)
plt.xlabel(var)
plt.ylabel('count')
plt.suptitle('Histogram of {}: Left with percentage output;Right with count output'
.format(var), size=16)
plt.show()
#fig.savefig(var+".pdf", bbox_inches='tight')
- W ramach kolejnych punktów będziemy tworzyli wykresy prezentujące udział poszczególnych grup wiekowych
w całkowitym pobranym kredycie. Na początek funkcja przyporządkowująca osobę do odpowiedniej grupy
a następnie utworzenie odpowiedniego zestawu danych.
def age_condition(x):
if pd.isnull(x):
return "missing"
elif x < 25:
return "<25"
elif 25 <= x <= 34:
return "25-34"
elif 35 <= x <= 44:
return "35-44"
elif 45 <= x <= 54:
return "45-54"
elif 55 <= x <= 64:
return "55-64"
else:
return "65+"
from pyspark.sql.functions import udf
from pyspark.sql.types import StringType, DoubleType
age_udf = udf(lambda x: age_condition(x), StringType())
df = df.withColumn("age_class", age_udf("Age (years)"))
df.select(['age_class','Age (years)']).show(3)
- Sprawdzamy poprawność przypisania do grup wiekowych i wykorzystując paramater 'Occupation' tworzymy kwerendę krzyżową.
df.select(['age_class','Credit Amount']).\
groupBy('age_class').count().show()
df.stat.crosstab("age_class", "Occupation").show()
- Dla utworzonych grup wiekowych tworzymy wartości zaagregowane dla parametru 'Credit Amount' tj. wartość średnia, wartość minimalna i maksymalna oraz liczba
wystąpień.
from pyspark.sql import functions as F
from pyspark.sql.functions import rank,sum,col
from pyspark.sql import Window
window = Window.rowsBetween(Window.unboundedPreceding,Window.unboundedFollowing)
# withColumn('Percent %',F.format_string("%5.0f%%\n",col('Credit_num')*100/col('total'))).\
tab = df.select(['age_class','Credit Amount']).\
groupBy('age_class').\
agg(F.count('Credit Amount').alias('Credit_num'),
F.mean('Credit Amount').alias('Credit_avg'),
F.min('Credit Amount').alias('Credit_min'),
F.max('Credit Amount').alias('Credit_max')).\
withColumn('total',sum(col('Credit_num')).over(window)).\
withColumn('Percent',col('Credit_num')*100/col('total')).\
drop(col('total'))
tab.show()
- W kolejnym zadaniu przeniesiemy dane do biblioteki 'pandas' i zmienimy prezentację wartości w zależności od grup wiekowych.
plot_data = tab.toPandas()
plot_data.sort_values('age_class')
custom_dict = {'<25': 0, '25-34': 1, '35-44': 2, '45-54': 3, '55-64': 4, '65+': 5}
plot_data['index']= plot_data['age_class'].replace(custom_dict)
plot_data.sort_values('index')
- Prezentacja wyników analizy na wykresie kołowym.
plot_data = plot_data.sort_values('index')
# Data to plot
labels = plot_data.age_class
sizes = plot_data.Percent
colors = ['gold', 'yellowgreen', 'lightcoral','blue', 'lightskyblue','green','red']
explode = (0, 0.1, 0, 0,0,0) # explode 1st slice
# Plot
plt.figure(figsize=(10,8))
plt.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', shadow=True, startangle=140)
plt.axis('equal')
plt.show()
- Prezentacja wyników analizy na wykresie słukowym.
labels = plot_data.age_class
missing = plot_data.Percent
ind = [x for x, _ in enumerate(labels)]
plt.figure(figsize=(10,8))
plt.bar(ind, missing, width=0.8, label='missing', color='gold')
plt.xticks(ind, labels)
plt.ylabel("percentage")
plt.show()
- Analiza wyników ze względu na płeć osoby biorącej kredyt.
labels = ['missing', '<25', '25-34', '35-44', '45-54','55-64','65+']
missing = np.array([0.000095, 0.024830, 0.028665, 0.029477, 0.031918,0.037073,0.026699])
man = np.array([0.000147, 0.036311, 0.038684, 0.044761, 0.051269, 0.059542, 0.054259])
women = np.array([0.004035, 0.032935, 0.035351, 0.041778, 0.048437, 0.056236,0.048091])
ind = [x for x, _ in enumerate(labels)]
plt.figure(figsize=(10,8))
plt.bar(ind, women, width=0.8, label='women', color='gold', bottom=man+missing)
plt.bar(ind, man, width=0.8, label='man', color='silver', bottom=missing)
plt.bar(ind, missing, width=0.8, label='missing', color='#CD853F')
plt.xticks(ind, labels)
plt.ylabel("percentage")
plt.legend(loc="upper left")
plt.title("demo")
plt.show()
- Ostatni wykres przedstawia zależność liczby kredytów od jego wielkości.
# prepare for the plot data
var = 'Credit Amount'
plot_data = df.select(var).toPandas()
x= plot_data[var]
bins =[0,200,400,600,700,800,900,1000,2000,3000,4000,5000,6000,10000,25000]
hist, bin_edges = np.histogram(x,bins,weights=np.zeros_like(x) + 100. / x.size) # make the histogram
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(1, 1, 1)
# Plot the histogram heights against integers on the x axis
ax.bar(range(len(hist)),hist,width=1,alpha=0.8,ec ='black',color = 'gold')
# # Set the ticks to the middle of the bars
ax.set_xticks([0.5+i for i,j in enumerate(hist)])
# Set the xticklabels to a string that tells us what the bin edges were
#labels =['{}k'.format(int(bins[i+1]/1000)) for i,j in enumerate(hist)]
labels =['{}'.format(bins[i+1]) for i,j in enumerate(hist)]
#labels.insert(0,'0')
ax.set_xticklabels(labels)
#plt.text(-0.6, -1.4,'0')
plt.xlabel(var)
plt.ylabel('percentage')
plt.show()