יום חמישי, 27 בדצמבר 2012

אימות ודאי

במסענו הנמשך בין הפונקציות הנסתרות של SAS הגענו הפעם לפונקציה של SAS עם השם הכי פחות קשור למה שהיא מבצעת - verify.

פונקציה זו מקבלת שני פרמטרים (או יותר, אבל נגיע לזה בהמשך) ומחזירה לנו את המקום של התו הראשון במחרוזת המועברת כפרמטר הראשון שאיננו התו או המחרוזת שהועברו כפרמטר השני.
למעשה, הרבה יותר מסובך להסביר מה הפונקציה הזו עושה מאשר להראות:
data examples;
     length str_before $20;
     input str_before;
datalines;
00000000000000456709
00000000097654090000
97654362000000000000
;
run;

data examples1;
     set examples;
     first_no_0_position=verify(str_before,'0');
first_no_976_position=verify(str_before,'976');
run;

proc print data=examples1;
run;

התוצאה המתקבלת היא:


שימו לב לרשומה השניה. התו הראשון שאיננו אפס הוא תו מספר עשר וזה אכן מה שקיבלנו בעמודה first_no_0_position. קצת מוזר הוא הערך 1 שקיבלנו בעמודה first_no_976_position אבל קריאה חוזרת של פעולת הפונקציה verify תסביר תוצאה משונה זו. התו הראשון במחרוזת שבעמודה str_before שבו לא מתחילה המחרוזת ‘976’ הוא אכן התו הראשון ולכן קיבלנו 1 כתשובה.

עד כה, verify נראית די נחמדה ואפילו עם ניחוח אקזוטי כלשהו אבל לא באמת שימושית. אולם, כאשר נצוות אותה לפונקציה הסלבריטאית substr נוכל להתחיל להבין את השימושיות שלה:

data examples2;
     set examples;
     substr_result=substr(str_before, verify(str_before,'0'));
run;

proc print data=examples2;
run;


 שימוש נפוץ בפונקציה זו הוא להוריד אפסים מובילים שמערכות ERP מאוד אוהבות להוסיף לערכים שונים כגון מק"טים, סעיפים חשבונאים וכו'. היתרון בפונקציה זו היא שאנחנו יכולים להיות בטוחים שרק האפסים המובילים יעלמו וכל יתר האפסים ישארו ללא פגע (תנסו לעשות שימוש בפונקציה compress כדי להוריד את האפסים המובילים בדוגמא לעיל ותקבלו תוכנית עם באג לוגי קשה במיוחד לגילוי...)

כפי שרמזנו בתחילה, ניתן להעביר יותר משני פרמטרים לפונקציה זו. במקרה זה היא תחזיר לנו את המיקום של התו הראשון שהוא לא אחד מתוים או מהמחרוזות שהועברו כפרטרים השני ואילך. קוד אחד שווה אלף מילים:

data examples3;
     set examples;
     first_no_0_4_9_position=verify(str_before,'0','4','9');
run;

proc print data=examples3;
run;


verify החזירה לנו את המקום של התו הראשון שהוא לא ‘0’ וגם לא ‘4’ וגם לא ‘9’.

אכן לא צפוי שנשתמש בפונקציה זו בכל יום אבל מידי פעם נתקל במקרים בהם היא תוכל לחסוך לנו זמן ומאמץ וגם להרשים משתמשי SAS אחרים שיקראו את הקוד שלנו...

חגי


יום שבת, 27 באוקטובר 2012

לאנליטיקה התחל כאן

 הרעיון של אנליטיקה עיסקית (Business Analytics) כדבר הבא אחרי הבינה העיסקית (Business Intelligence) צובר תאוצה רבה בשנים האחרונות. חברת SAS, שחרטה את האנליטיקה על דגלה כבר לפני עשרות שנים, מהווה, כמובן, חלק חשוב בשינוי הזה. היתרונות והחזון ברורים לכולם אבל לעיתים קרובות עולה השאלה מאיפה מתחילים? איך אני יכול להפוך את הארגון שלי לארגון אנליטי?

באופן טבעי מיד עולים רעיונות כגון כריית נתונים, חיזוי ואופטימיזציה כדרכים לשילוב של אנליטיקה בארגון והפיכתו ל – "ארגון אנליטי". אין שום ספק שיישום יכולות אנליטיות שכאלו יכול לתרום רבות לארגון אבל, לרוב, מדובר בפרויקט מאתגר המכוון לפתור בעיה עסקית ממוקדת. הרעיון של "ארגון אנליטי" הוא בהטמעה של האנליטיקה בארגון כולו ובכל התהליכים בו והוא תלוי במוכנות של הארגון להתמודדות עם תוצרים וניתוחים מורכבים, איכות גבוהה של נתונים, מוכנות לשנות תהליכים קיימים, זמינות של כלים ואנשים מתאימים והחשוב ביותר הוא תמיכה גורפת של כל רמות ההנהלה.

הקונספט של "ארגון אנליטי" הוא לא בינארי – הכל או כלום. נכון יותר להסתכל על זה כסקלה רחבה שכל ארגון יכול וצריך לנוע עליה לאורך הזמן לכיוון נקודת הקצה האידאלית של ארגון אנליטי מושלם. הסוד הוא לא לנסות להגיע מעמידה ל – 120 קמ"ש מיד. ארגונים הם לא מכונית ספורט, אם כבר, הם מזכירים יותר רכבת משא כבדה, אבל אם משקיעים מספיק כוח למשך מספיק זמן גם רכבת המשא הכבדה ביותר תגיע בסוף למהירות הזו.

השאלה היא, כמובן, מאיפה מתחילים? איך גורמים לארגון להתחיל לנוע ולעשות את הצעד הראשון בכיוון שילוב מקיף יותר של אנליטיקה בארגון. אחת האפשרויות עולה מפוסט מעניין ומומלץ של ליאו סאדובי העוסק בתהליך קבלת ההחלטות העיסקיות בארגון. הוא מונה חמש קטגוריות של אינפורמציה הנדרשות לתמיכה בקבלת החלטות:
1.       המצב הנוכחי של הארגון.
2.       יכולות הארגון.
3.       תחזית.
4.       מידת השונות או אי הוודאות במידע בשלושת הנקודות הקודמות.
5.       בקרה ומעקב.

לדעתו של ליאו הנקודה הרביעית - כימות של השונות ושל אי הודאות - היא החשובה ביותר למנהל בעת קבלת ההחלטות. האם תחזית המכירות לשנה הקרובה היא בין 105 מיליון ש"ח לבין 95 מיליון ש"ח או בין 50 מיליון ש"ח לבין 150 מיליון? האם כאשר אנחנו מציגים בכלי ה – BI שלנו שמשך שיחה ממוצעת למוקד שירות הלקוחות שלנו הוא 300 שניות הכוונה היא שמשך השיחות הוא בין 290 ל – 310 שניות או בין 100 ל – 500 שניות? האם משך השבתה עקב תקלה של קו הייצור שלנו הוא בין 60 ל – 80 דקות או בין 10 ו – 130 דקות. האם ב - 95% מהפעמים קו הייצור חזר לעבוד לאחר 70 דקות, לאחר 100 דקות או לאחר 30 דקות?

העשרת הנתונים המסופקים למקבלי ההחלטות בתוצרים של ניתוחים סטטיסטים בסיסיים-לכאורה היא פתח מצוין להתחלה של שילוב אנליטיקה בארגון. השינוי מתרבות של מספר אחד – הממוצע ואין בלתו – למתן טווח ערכים או ממוצע וסטיית תקן יכול להוות נייר לקמוס מצוין למידת המוכנות של הארגון לאנליטיקה ודרך מצוינת להרגיל את הארגון לעשות שימוש בה בתהליכים הקיימים של קבלת ההחלטות היומיומית שלו.

מערכת ה – SAS כוללת בתוכה מגוון עצום של יכולות שכאלו. רק לשם ההמחשה נזכיר את proc rank, את proc univariate ואת proc means המסוגלים, בצורה קלה ופשוטה, להפיק מגוון עצום של מידע על אי הוודאות והשונות המובנים בכל עולם נתונים. האינטגרציה של מערכת ה – SAS מבטיחה גישה פשוטה וקלה ליכולות אלו בעזרת כלי ניתוח גרפיים כגון Enterprise Guide ורכיבי ה – BI  של SAS כך שהעלות להתחיל לעשות בהם שימוש, הן מבחינת הזמן והן מבחינת המשאבים, היא נמוכה מאוד והתועלת - מיידית.

ברגע שהארגון למד והתרגל לעבוד עם סטיות תקן ועשירונים המעבר להיסטוגרמות, לרגרסיות ולניתוחים מורכבים יותר כגון כריית נתונים וחיזוי יהיה הרבה יותר פשוט מבחינת התרבות הארגונית והיכולת לשלב תוצרים מורכבים שכאלו בתהליכי העבודה הסטנדרטים. מבלי שנרגיש הפכנו את הארגון שלנו לארגון אנליטי.

אפשרות נוספת לשילוב אנליטיקה בארגון היא לשם מתן הקשר – Context – לנתונים אבל על כך בפוסט עתידי.

חגי.

יום שבת, 15 בספטמבר 2012

שנה טובה

שלום,

כמנהגנו לקראת ראש השנה גם בפוסט זה נעסוק בנושא התאריכים ב – SAS. הפעם נתחיל מההתחלה וננסה להסביר נושא זה אשר מעורר פחד ויראה בקרב לא מעט משתמשי SAS, גם המנוסים שבהם.

SAS מייצגת תאריך או נקודה כלשהי בזמן ע"י ערך נומרי כלשהו. ערך זה הוא מספר ככל מספר אחר. ההבדל היחיד בינו לבין "סתם" מספר הוא ההחלטה שלנו להתייחס לערך שלו כמייצג יחידת זמן. הבחירה היא אומנם שלנו אבל אם החלטנו להתייחס למספר מסוים כמייצג יחידת זמן כלשהי אז עלינו לזרום עם ההגדרות המובנות במערכת ה – SAS בנוגע לייצוג וטיפול בזמן.

מפתחי מערכת ה – SAS החליטו על שלוש דרכים לייצג נקודה בזמן – תאריך (date), שעה (time) ותאריך-שעה (datetime). תאריך מיוצג ע"י מספר הימים שעברו מה – 1/1/1960, זמן מיוצג ע"י מספר השניות שעברו מחצות הלילה ואילו תאריך-שעה מיוצג ע"י מספר השניות שעברו מה – 1/1/1960 בחצות הלילה. הטבלה הבאה מסכמת את הנושא:
סוג
יחידות
נקודת האפס
ערך לדוגמא
הזמן אותו הוא מייצג
תאריך
ימים
1/1/1960
19251
15/09/2012
שעה
שניות
00:00:00
74889
20:48:09
תאריך-שעה
שניות
1/1/1960:00:00:00
1663361341
15/09/2012 20:49:01

כמובן שאם אנחנו רוצים לכתוב בתוכנית ה – SAS שלנו תאריך מסוים לא נרוץ ללוח השנה ונתחיל לספור כמה ימים עברו מאז ה – 1/1/1960 ועד לתאריך אותו אנחנו רוצים להזין. SAS מאפשרת לנו לכתוב תאריך או שעה בצורה נוחה לבני אדם אבל כדי ש – SAS תצליח להבין לבד למה אנחנו מתכוונים אנחנו צריכים לכתוב אותו בצורה מסוימת:
סוג
פורמט כתיבה
לדוגמא
תאריך
"ddmmmyy"d
"15SEP2012"d (*), (**)
שעה
"hh:mm:ss"t
"21:12:54"t
תאריך-שעה
"ddmmmyy:hh:mm:ss"dt
"15SEP2012:21:12:54"dt
(*) מבחינת SAS אין הבדל בין אותיות גדולות לקטנות כך שגם "15sep2012"d יתקבל בברכה.
(**) במקרה של תאריכים אין הבדל בין מרכאות כפולות לבודדות ולכן גם '15sep2012'd הוא תקין לחלוטין.

כאמור, ההחלטה שערך מסוים מייצג יחידת זמן מסוימת היא שלנו בלבד. שום דבר לא מונע מאיתנו להחליט ש – 19251 מהטבלה שלמעלה דווקא מייצג שעה ביום ולא תאריך. במקרה שכזה מספר זה ייצג את השעה 05:20:51 (חמש, עשרים דקות וחמישים ואחת שניות לפנות בוקר).

שיטה זו לייצוג זמן במערכות ממוחשבות אינה ייחודית ל – SAS. לדוגמא, אקסל של חברת מיקרוסופט עושה שימוש באותו מנגנון לייצוג זמן.  ההבדל הוא שבאקסל נקודת האפס היא 1/1/1900 והשעה ביום מיוצגת ע"י שבר עשרוני.

SAS מאפשרת לנו גם להמיר בין שלושת דרכי ייצוג אלו בעזרת פונקציות ייעודיות:
מ -
ל -
נשתמש בפונקציה
לדוגמא
תאריך
תאריך-שעה
mydttm=dhms(mydt,0,0,0)
תאריך-שעה
תאריך
mydt=datepart(mydttm)
תאריך-שעה
שעה
mytm=timepart(mydttm)

מבחינת המחשב הכל פשוט מאוד. תאריכים הם מספרים ומחשבים טובים מאוד בעבודה עם מספרים. הבעיות נוצרות בחיבור שבין המחשב לבני האדם. מרבית האנשים יעדיפו לקבל 15/09/2012 על פני 19251 כתשובה לשאלה מה התאריך היום. למעשה, אנשים בארה"ב דווקא יעדיפו לקבל כתשובה 9/15/2012 ואילו אנשים ביפן יצפו ל - 2012/09/15.

בעיה נוספת נובעת מהמורכבות של לוח השנה עצמו. לדוגמא, אם יש לנו תאריך ביד ונרצה להוסיף לו שבוע פשוט נוסיף למספר המייצג את התאריך את הערך 7. אבל, מה אם נרצה להמיר את התאריך שלנו לאותו יום בחודש הקודם? מספר הימים שנצטרך להחסיר יכול להיות 31, 30, 29 או 28 תלוי בחודש ובשנה הספציפים.

כדי לפתור את הבעיה הראשונה SAS מכילה מגוון רחב מאוד של format-ים ו – informat-ים המאפשרים לנו להציג תאריך בצורה הנוחה ביותר. לכל אחד משלושת סוגי הייצוג של יחידות הזמן יש את ה – format-ים וה – informat-ים המתאימים לו.

הקטע הטריקי הוא שאנחנו בתור המשתמשים צריכים לוודא שבחרנו את ה – format המתאים ליחידת הזמן שלנו. כאמור, מבחינת SAS כל תאריך מכל סוג שהוא הוא רק מספר ואין לה שום דרך לדעת מה מספר זה מייצג בפועל. לדוגמא, אם החלטנו שהמספר 19251 מייצג תאריך אזי נציג אותו באחד מה – format-ים של התאריכים – למשל ddmmyy10. – ונקבל 15/09/2012. אנחנו יכולים באותה מידה להחליט שמספר זה מייצג שעה ביום ואם נפעיל עליו אחד מה – format-ים של שעה – למשל time. – נקבל 5:20:51:
data _null_;
      x=19251;
      put x ddmmyy10.;
      put x time.;
      put x datetime.;
run;

15/09/2012
 5:20:51
01JAN60:05:20:51
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds


כדי לפתור את הבעיה השניה SAS מכילה גם מספר פונקציות שכל ייעודן הוא טיפול בתאריכים. שתי פונקציות שימושיות במיוחד הן intnx המשמשת להוספה או החסרה של יחידות זמן מתאריך ו – intck המאפשרת לחשב כמה יחידות זמן יש בין שני תאריכים. לפונקציות אלו מגוון רחב של פרמטרים ואפשרויות שימוש והטבלה הבאה מציגה רק מספר שימושים נפוצים. הקטע החשוב בפונקציות אלו הוא לבחור את יחידת הזמן המתאימה למה שאנחנו רוצים להשיג ולסוג התאריך שלנו (תאריך, שעה או תאריך-שעה).
מה רוצים לעשות
מה כותבים
מה מקבלים
להוסיף 15 ימים לתאריך
intnx('day', "15sep2012"d, 15)
"30sep2012"d
להוסיף 15 ימים לתאריך-שעה
intnx('dtday', "15sep2012:00:00:00"dt, 15) (*)
"30sep2012:00:00:00"dt
להוריד שבוע מתאריך
intnx('week', "15sep2012"d, -1)
"08sep2012"d
להוסיף 50 דקות לשעה
intnx('minute',"13:45:12"t, 50, 's')
"14:35"12"t
מה היום האחרון בחודש של תאריך
intnx('month', "15sep2012"d, 0, 'e')
"30sep2012"d
למצוא כמה ימים יש בין שני תאריכים
intck('day', "22aug2012"d, "15sep2012"d)
24
למצוא כמה שעות יש בין שני תאריך-שעה
intck('hour', "22aug2012:00:45:12"dt, "15sep2012:13:34:00"dt)
589
למצוא כמה רבעונים יש בין שני תאריך-שעה
intck('dtqtr', "22aug2012:00:45:12"dt, "15sep2010:13:34:00"dt) (*)
8- (**)
(*) שימו לב שאם מטפלים בתאריך-שעה יש להוסיף "dt" לפני יחידת הזמן ("dtday" או "dtqtr").
(**) קיבלנו ערך שלילי מכיוון שהתאריך-שעה הראשון הוא מאוחר יותר מתאריך-השעה השני.

מקווה שפוסט זה סייע מעט להסביר את נושא התאריכים ב – SAS ושנה טובה לכל בית ישראל מאנשי מיה מחשבים וממני.

חגי

יום שבת, 21 ביולי 2012

התמזגות, התאחדות, התערבבות

ערכים חסרים (missing) אינם זרים למרבית משתמשי ה – SAS. ב – SAS ערך חסר בעמודה נומרית מיוצג ע"י נקודה ואילו ערך חסר בעמודת טקסט מיוצג ע"י מחרוזת ריקה ("") או מחרוזת המכילה רווח אחד (" "). SAS אפילו מגדילה לעשות ומאפשרת לנו להגדיר 28 סוגים של ערכים נומרים חסרים. למה זה טוב אתם שואלים? ובכן זה מאפשר לנו לציין בצורה פשוטה לא רק שהערך חסר אלא גם את הסיבה לכך. לדוגמא, אם אנחנו מנתחים נתוני סקר ניתן להבדיל בין 'המשתמש לא ענה בכלל', 'המשתמש בחר באפשרות "לא רלוונטי"' ו – "לא הצלחנו להבין מה המשתמש ענה".
הרעיון של "ערך חסר " מונח בבסיס תיאוריית בסיס הנתונים הרלציוני (טבלאי) וכל בסיס נתונים כלשהו מאפשר ייצוג העובדה שתא כלשהו בטבלה איננו מכיל כלום. לרוב בהקשר של בסיסי נתונים ערך חסר מכונה NULL.
לטיפול בערכים חסרים קיימות ב – SAS מספר פונקציות ייעודיות ואחת השימושיות והנחבאות שבהן היא COALESCE. הפונקציה הזו מקבלת פרמטר אחד או יותר ומחזירה את הראשון (משמאל לימין) שהוא לא חסר או NULL. לדוגמא:

data sample;
length n1 n2 8 c1 c2 $1;
input n1 n2 c1 $ c2 $;
infile datalines dsd delimiter=',';
datalines;
1,2,X,Y
.,3,,Z
.,.,,
;
run;

proc print data=sample;
title 'Dataset: SAMPLE';
run;

proc sql;
create table sample_sql as
select
n1,
n2,
c1,
c2,
coalesce(n1,n2,4) as n3,
coalesce(n1,n2) as n4,
coalesce(c1,c2,'T') as c3,
coalesce(c1,c2) as c4
from
sample;
quit;

proc print data=sample_sql;
title 'Dataset: SAMPLE_SQL';
run;

נקודה שצריך לשים לה לב היא שכאשר משתמשים בפונקציה זו בתוך PROC SQL היא יודעת לטפל בערכים נומרים וטקסטואלים כאחד אבל אם אנחנו רוצים להשתמש בה בתוך DATA Step אז היא יודעת לעבוד עם ערכים נומרים בלבד. עבור שדות טקסטואלים צריך לקרוא לאחותה COALESCEC – עם האות C (בשביל character) בסוף. לדוגמא:

data sample_datastep;
set sample;
length n3 n4 8 c3 c4 $1;
n3=coalesce(n1,n2,4);
n4=coalesce(n1,n2);
c3=coalescec(c1,c2,'T');
c4=coalescec(c1,c2);
run;

proc print data=sample_datastep;
title 'Dataset: SAMPLE_DATASTEP';
run;

ולסיום, למי שתהה על כותרת הפוסט הזה אזי המילה coalesce באנגלית פירושה התמזגות, התאחדות, התערבבות וממנה הגיעה המילה קואליציה.
חגי