2011-07-26 13 views
6

¿Existe una forma incorporada en Oracle 11 para verificar la correlación de valores en un campo varchar2? Por ejemplo, dada una tabla sencilla como esta:Correlación de valores varchar

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

Quiero conseguir una indicación numérica que en base a MEAL_NUM, el queso se empareja sobre todo con la pasta, y de atenuar grados con carne de res, pollo y pescado.

Mi primera inclinación es usar la función CORR y transformar las cuerdas en un número, ya sea enumerando previamente o agarrando el rownum de una selección única.

¿Alguna sugerencia de cómo hacerlo?

Respuesta

0

¿Qué tal una consulta como esa?

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; 

el resultado debe ser el número de veces que cada ingrediente comparte un meal_num con QUESO.

3

No va a querer usar CORR - si crea un "número de alimento" y asigna Beef = 1, Chicken = 2 y Pasta = 3, entonces un coeficiente de correlación le dirá si el aumento de queso se correlaciona con un aumento "número de comida". Pero el "número de comida" es más alto o más bajo no significa nada desde que lo inventaste. Por lo tanto, no use CORR a menos que sus alimentos en realidad estén ordenados de alguna manera, como lo son los números.

La manera en que los estadísticos hablan sobre esto es con levels of measurement. En el lenguaje del artículo vinculado, MEAL_NUM es una medida nominal, o tal vez una medida ordinal si las comidas sucedieron en orden, pero de cualquier forma, es una mala idea usar coeficientes de correlación en ella.

Probablemente desearás encontrar algo como "¿qué porcentaje de las comidas de carne también tienen queso?" Lo siguiente devolverá, para cada ingrediente, el número de comidas que lo contienen y también el número de comidas que lo contienen Y el queso. El truco es que COUNT solo cuenta valores no nulos.

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 

Advertencia: arroja un resultado erróneo si incluye un ingrediente dos veces en una de las comidas.

Editar: Resulta que usted no está interesado específicamente en el queso. Realmente quieres todos los pares de "correlaciones". Entonces, podemos extraer el "queso" y llamarlo solo el primer y segundo ingrediente. Agregué una "Puntuación Posible" a esta que intenta actuar como un porcentaje de las comidas, pero no da una puntuación fuerte si hay muy pocas instancias del ingrediente.

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 

Cuando ordenados por puntuación, esto debe volver

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

Esto es realmente una buena información. Creo que la razón por la que OP quería usar una función como corr() es para poder aplicarla a todo el conjunto de datos en lugar de solo un ingrediente. –

+0

@James Oh; ese es un muy buen punto en realidad. Sería un ejercicio interesante generalizar mi tabla de "Queso" para que no necesariamente se llame "Queso", pero esperaré a escuchar del OP. –

+0

Sí, planeo dejar que esto se ejecute en todo el conjunto de datos. – owook

2

hacer un auto se unen para obtener toda la en combinaciones de ingredientes, a continuación, corr por los dos 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 

deben darle algo como:

BEEF CHEESE 0.999 
BEEF PASTA 0.998 
CHEESE PASTA 0.977 

ACTUALIZACIÓN: como Chris señala, esto no funcionará como está.Lo que esperaba es que podría haber alguna manera de burlar un mapeo desde el ordinal meal_num a un intervalo (@Chris, gracias por el enlace) valor. Eso puede no ser posible, en cuyo caso esta respuesta no ayudaría.

+1

Estoy bastante seguro de que esta es una mala idea; si la carne aparece en las comidas 2, 3, 4 y el queso aparece solo en la comida 6, entonces encontrará el coeficiente de correlación con los pares (2,6), (3,6) y (4,6). Eso será un problema: todos los puntos se encuentran en una línea horizontal, y el coeficiente de correlación devolverá algo muy interesante allí. –

+0

Actualización: No solo son falsos positivos: mis estadísticas están un poco oxidadas, pero creo que el coeficiente de correlación debería devolver un error de división por cero si le das mis datos de ejemplo. Si le das a 'CORR' cualquier cosa que no sea realmente una medida numérica, estás pidiendo todo tipo de problemas. –

+0

[Aquí] (http://en.wikipedia.org/wiki/Levels_of_measurement) es una discusión más técnica de lo que estaba tratando de decir con las palabras "medida numérica". –

1

Trate 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 
Cuestiones relacionadas