2011-07-26 14 views
6

Czy w Oracle 11 istnieje wbudowany sposób sprawdzania korelacji wartości w polu varchar2? Na przykład, biorąc pod uwagę prostą tabelę, takie jak ten:Korelacja wartości varchar

MEAL_NUM INGREDIENT 
-------------------- 
1   BEEF 
1   CHEESE 
1   PASTA 
2   CHEESE 
2   PASTA 
2   FISH 
3   CHEESE 
3   CHICKEN 

Chcę uzyskać informację liczbową, że w oparciu o MEAL_NUM, ser jest kojarzony głównie z makaronem i do zmniejszenia stopnia z wołowina, kurczak i ryby.

Moja pierwsza skłonność polega na użyciu funkcji CORR i przekształceniu ciągów znaków w liczby, prawdopodobnie przez wyliczenie ich wcześniej lub pobranie rownum z unikalnego wyboru.

Jakieś sugestie, jak temu zaradzić?

Odpowiedz

0

co z takim zapytaniem?

select t1.INGREDIENT, count(*)a 
from table t1, 
    (select meal_num 
     from table 
     where INGREDIENT = 'CHEESE') t2 
where t1.INGREDIENT <> 'CHEESE' 
and t1.meal_num=t2.mealnum 
group by t1.INGREDIENT; 

wynik powinien być ilością czasu, jaką każdy składnik ma w posiłku z CHEESE.

3

Nie będziesz chciał używać CORR - jeśli utworzysz "numer żywności" i przypiszesz wołowinę = 1, kurczaka = 2 i makaron = 3, wówczas współczynnik korelacji wskaże Ci, czy zwiększony ser koreluje ze zwiększonym "numer żywności". Ale "liczba żywności", która jest wyższa lub niższa, nie ma znaczenia, odkąd ją wymyśliłeś. Więc nie używaj CORR, chyba że twoje jedzenie jest w jakiś sposób uporządkowane, podobnie jak liczby.

Sposób, w jaki mówią o tym statystycy, to levels of measurement. W języku połączonego artykułu, MEAL_NUM jest miarą nominalną - lub może miarą porządkową, jeśli posiłki były ułożone w kolejności, ale tak czy inaczej, to naprawdę zły pomysł, aby użyć współczynników korelacji na nim.

Prawdopodobnie będziesz chciał zamiast tego znaleźć coś w stylu "jaki procent posiłków z wołowiny ma również ser?" Następujący produkt zwróci, dla każdego składnika, liczbę posiłków, które go zawierają, a także liczbę posiłków, które go zawierają ORAZ ser. Sztuczka polega na tym, że COUNT liczy tylko wartości inne niż null.

SELECT Other.Ingredient, 
     COUNT(*) AS TotalMeals, 
     COUNT(Cheese.Ingredient) AS CheesyMeals 
    FROM table Other 
LEFT JOIN table Cheese 
     ON (Cheese.Ingredient = 'Cheese' 
     AND Cheese.Meal_Num = Other.Meal_Num) 
GROUP BY Other.Ingredient 

Ostrzeżenie: zwraca błędne wyniki, jeśli składnik zawiera dwa składniki w jednym posiłku.

Edytuj: Okazuje się, że nie interesuje Cię specjalnie ser. Naprawdę chcesz wszystkich par "korelacji". Możemy więc wyodrębnić "Ser" i nazwać je tylko pierwszymi i drugimi składnikami. Dodałem do tego "PossibleScore", który próbuje zachowywać się jak procent posiłków, ale nie daje silnego wyniku, jeśli jest bardzo mało przypadków składnika.

SELECT First.Ingredient, 
     Second.Ingredient, 
     COUNT(*) AS MealsWithFirst, 
     COUNT(First.Ingredient) AS MealsWithBoth, 
     COUNT(First.Ingredient)/(COUNT(*) + 3) AS PossibleScore, 
    FROM table First 
LEFT JOIN table Second 
     ON (First.Meal_Num = Second.Meal_Num) 
GROUP BY First.Ingredient, Second.Ingredient 

Kiedy klasyfikowane według wynik, to powinien wrócić

PASTA CHEESE 2 2 0.400 
CHEESE PASTA  3 2 0.333 
BEEF  CHEESE 1 1 0.250 
BEEF  PASTA  1 1 0.250 
FISH  CHEESE 1 1 0.250 
FISH  PASTA  1 1 0.250 
CHICKEN CHEESE 1 1 0.250 
PASTA BEEF  2 1 0.200 
PASTA FISH  2 1 0.200 
CHEESE BEEF  3 1 0.167 
CHEESE FISH  3 1 0.167 
CHEESE CHICKEN 3 1 0.167 
+2

To bardzo dobra informacja. Myślę, że powodem, dla którego OP chciał użyć funkcji takiej jak corr(), jest to, że mógłby zastosować ją do całego zestawu danych, a nie tylko jednego składnika. –

+0

@ James Oh; to naprawdę bardzo dobry punkt. Byłoby interesującym ćwiczeniem uogólnić mój "serowy" stół, tak aby niekoniecznie był nazywany "serem", ale poczekam na wiadomość z PO. –

+0

Tak, planuję pozwolić, aby to coś działało na całym zbiorze danych. – owook

2

Czy jaźń zalogowany, aby uzyskać wszystkie w kombinacji składników, a następnie corr przez dwa meal_nums

SELECT t1.INGREDIENT, t2.INGREDIENT, CORR(t1.MEAL_NUM, t2.MEAL_NUM) 
FROM TheTable t1, TheTable t2 
WHERE t1.INGREDIENT < t2.INGREDIENT 
GROUP BY t1.INGREDIENT, t2.INGREDIENT 

powinno dać coś takiego:

BEEF CHEESE 0.999 
BEEF PASTA 0.998 
CHEESE PASTA 0.977 

AKTUALIZACJA: jak Chris wskazuje, to nie zadziała tak jak jest.Miałem nadzieję, że jest jakiś sposób na sfałszowanie mapowania z porządkowej meal_num na wartość przedziału (@Chris, thanks for the link). To może nie być możliwe, w takim przypadku ta odpowiedź nie pomogłaby.

+1

Jestem prawie pewien, że to zły pomysł; jeśli wołowina pojawia się w posiłkach 2, 3, 4, a ser pojawia się tylko w posiłku 6, wówczas znajdziecie współczynnik korelacji z parami (2,6), (3,6) i (4,6). To będzie problem - wszystkie punkty leżą na poziomej linii, a współczynnik korelacji zwróci tam coś bardzo interesującego. –

+0

Aktualizacja: To nie tylko fałszywe alarmy - moje statystyki są trochę zardzewiałe, ale myślę, że współczynnik korelacji powinien zwrócić błąd dzielenia przez zero, jeśli podasz mu moje przykładowe dane. Jeśli podasz 'CORR' coś, co w rzeczywistości nie jest miarą liczbową, żądasz wszelkiego rodzaju problemów. –

+0

[tutaj] (http://en.wikipedia.org/wiki/Levels_of_measurement) jest bardziej techniczną dyskusją o tym, co próbowałem powiedzieć słowami "miara liczbowa". –

1

Spróbuj DBMS_FREQUENT_ITEMSET:

--Create sample data 
create table meals(meal_num number, ingredient varchar2(10)); 

insert into meals 
select 1, 'BEEF' from dual union all 
select 1, 'CHEESE' from dual union all 
select 1, 'PASTA' from dual union all 
select 2, 'CHEESE' from dual union all 
select 2, 'PASTA' from dual union all 
select 2, 'FISH' from dual union all 
select 3, 'CHEESE' from dual union all 
select 3, 'CHICKEN' from dual; 

commit; 

--Create nested table type to hold results 
CREATE OR REPLACE TYPE fi_varchar_nt AS TABLE OF VARCHAR2(10); 
/

--Find the items most frequently combined with CHEESE. 
select bt.setid, nt.column_value, support occurances_of_itemset 
    ,length, total_tranx 
from 
(
    select 
     cast(itemset as fi_varchar_nt) itemset, rownum setid 
     ,support, length, total_tranx 
    from table(dbms_frequent_itemset.fi_transactional(
     tranx_cursor => cursor(select meal_num, ingredient from meals), 
     support_threshold => 0, 
     itemset_length_min => 2, 
     itemset_length_max => 2, 
     including_items => cursor(select 'CHEESE' from dual), 
     excluding_items => null)) 
) bt, 
table(bt.itemset) nt 
where column_value <> 'CHEESE' 
order by 3 desc; 


    SETID COLUMN_VAL OCCURANCES_OF_ITEMSET  LENGTH TOTAL_TRANX 
---------- ---------- --------------------- ---------- ----------- 
     4 PASTA       2   2   3 
     3 FISH       1   2   3 
     1 BEEF       1   2   3 
     2 CHICKEN      1   2   3