Tengo un struct que contiene miles de muestras de datos. Cada punto de datos contiene varios objetos. Por ejemplo:

Structure(1).a = 7
Structure(1).b = 3
Structure(2).a = 2
Structure(2).b = 6
Structure(3).a = 1
Structure(3).b = 6
...
... (thousands more)
...
Structure(2345).a = 4
Structure(2345).b = 9

… y así sucesivamente.

Si quería encontrar el número de índice de todas las ‘.b’ de los objetos que contienen el número 6, yo habría esperado que la función siguiente haría el truco:

find(Structure.b == 6)

… y espero la respuesta para contener ‘2’ y ‘3’ (por la entrada que se muestra arriba).

Sin embargo, esto no funciona. ¿Cuál es la sintaxis correcta y/o podría ser la organización de mis datos en una manera más lógica en el primer lugar?

  • Como una nota al margen: Es mucho más RAM-eficiente (y conveniente) para tener estructuras de matrices (es decir, un escalar, con una estructura de 2000×1 campo a) de las matrices de estructuras, ya que cada elemento de una estructura viene con un par de bytes de sobrecarga de memoria.
  • pero no se podía representar el «vacío» de los campos.
  • Simplemente reemplazarlos con NaNs.
  • también, es cierto.
  • muchas gracias; ahora he arreglado mis datos en una estructura de matrices de vuestros consejos. Mucho más lógico 🙂 Única salvedad es que las cosas pueden desalinear si uno de mis matrices no contienen el mismo número de elementos. Pero, me aseguro de que hacer.
InformationsquelleAutor CaptainProg | 2013-01-23

3 Comentarios

  1. 24

    La sintaxis Structure.b para un array de structs le da un lista separada por comas, así que tendrás que concatenar todos ellos (por ejemplo, el uso de soportes de []) con el fin de obtener un vector:

    find([Structure.b] == 6)

    Para la entrada que se muestra arriba, el resultado es el esperado:

    ans =
         2     3

    Como Jonas señaló, esto funciona sólo si no hay ningún campo vacío que contiene las matrices, ya que vacía las matrices no se refleja en el resultado de la concatenación de.

    El manejo de estructuras con campos vacíos

    Si usted sospecha que estos campos pueden contener vacío matrices, ya sea convertir a NaNs (si es posible…) o considerar el uso de una de las soluciones más seguras sugerido por Rody.

    Además, he pensado de otra interesante alternativa para esto el uso de cadenas. Podemos concatenar todo en una cadena delimitada para mantener la información acerca de los campos vacíos y, a continuación, convertir de nuevo (esto, en mi humilde opinión, es más fácil ser hecho en MATLAB que manejar valores numéricos almacenados en las celdas).

    Inspirado por Jonas comentario, podemos convertir los campos vacíos para NaNs así:

    str = sprintf('%f,', Structure.b)
    B = textscan(str, '%f', 'delimiter', ',', 'EmptyValue', NaN)

    y esto le permite aplicar find en el contenido de B:

    find(B{:} == 6)
    
    ans =
         2
         3
    • Tenga en cuenta que esto va a volver malo índices para los campos que vienen después de un vacío.
    • Tengo la impresión de que no hay campos vacíos, pero tienes razón. Voy a hablar de eso.
    • Ver a mi nueva respuesta 🙂
    • Vale la pena mencionar que esto también funciona con los objetos. Si array es una MxN miclase matriz con las propiedades: myProp, entonces find([array.myProp] == value) funciona como se esperaba. (No tratamos con valores vacíos)
  2. 9

    Edificio en EitanT la respuesta con Jonas comentario, de una manera más segura podría ser

    >> S(1).a = 7;
       S(1).b = 3;
       S(2).a = 2;
       S(2).b = 6;
       S(3).a = 1;
       S(3).b = [];
       S(4).a = 1;
       S(4).b = 6;
    
    >> find( cellfun(@(x)isequal(x,6),{S.b}) )
    ans =
         2     4

    Probablemente no es muy rápido a pesar de que (en comparación con EitanT de la versión), por lo que sólo utilice esta opción cuando sea necesario.

    • +1: por el camino, usted podría utilizar cellfun(@(x)isequal(x, 6), {S.b}) para la cellfun lógica. isequal puede manejar matrices vacías también.
    • cierto! Maldita sea, siempre hay que olvidar que uno. La edición de…
    • btw: 10K! felicidades! 🙂
    • buen trabajo, SE parte de la comunidad 🙂
    • También, felicidades por la insignia de plata!
  3. 9

    Otra respuesta a esta pregunta! Esta vez, vamos a comparar el rendimiento de los siguientes 4 métodos:

    1. Mi método original
    2. EitanT del método original (que no controla emtpies)
    3. EitanT del método mejorado el uso de cadenas
    4. Un nuevo método: un simple for-loop
    5. Otro nuevo método: una vectorizados, emtpy versión segura

    El código de la prueba:

    % Set up test
    N = 1e5;
    S(N).b = [];
    for ii = 1:N
    S(ii).b = randi(6); end
    % Rody Oldenhuis 1
    tic
    sol1 = find( cellfun(@(x)isequal(x,6),{S.b}) );
    toc
    % EitanT 1
    tic
    sol2 = find([S.b] == 6);
    toc
    % EitanT 2
    tic
    str = sprintf('%f,', S.b);
    values = textscan(str, '%f', 'delimiter', ',', 'EmptyValue', NaN);
    sol3 = find(values{:} == 6);
    toc
    % Rody Oldenhuis 2
    tic
    ids = false(N,1);
    for ii = 1:N
    ids(ii) = isequal(S(ii).b, 6);
    end
    sol4 = find(ids);
    toc
    % Rody Oldenhuis 3
    tic
    idx = false(size(S));
    SS = {S.b};
    inds = ~cellfun('isempty', SS);
    idx(inds) = [SS{inds}]==6;
    sol5 = find(idx);
    toc
    % make sure they are all equal
    all(sol1(:)==sol2(:))
    all(sol1(:)==sol3(:))
    all(sol1(:)==sol4(:))
    all(sol1(:)==sol5(:))

    Resultados en mi máquina en el trabajo (APU AMD A6-3650 (4 núcleos), 4GB de RAM, Windows 7 de 64 bits):

    Elapsed time is 28.990076 seconds. % Rody Oldenhuis 1 (cellfun)
    Elapsed time is 0.119165 seconds.  % EitanT 1 (no empties)
    Elapsed time is 22.430720 seconds. % EitanT 2 (string manipulation)
    Elapsed time is 0.706631 seconds.  % Rody Oldenhuis 2 (loop)
    Elapsed time is 0.207165 seconds.  % Rody Oldenhuis 3 (vectorized)
    ans =
    1
    ans =
    1
    ans =
    1
    ans =
    1

    En mi Homebox (AMD Phenom(tm) II X6 1100T (6 núcleos), 16GB de RAM, Ubuntu64 12.10):

    Elapsed time is 0.572098 seconds.  % cellfun
    Elapsed time is 0.119557 seconds.  % no emtpties
    Elapsed time is 0.220903 seconds.  % string manipulation
    Elapsed time is 0.107345 seconds.  % loop
    Elapsed time is 0.180842 seconds.  % cellfun-with-string

    Amará JIT 🙂

    y wow…alguien sabe por qué los dos sistemas se comportan de manera tan diferente?

    También, hecho poco conocido — cellfun con uno de los posibles argumentos de la cadena es increíblemente rápido (el cual va a mostrar cuánto la sobrecarga de funciones anónimas requieren…).

    Aún, si usted puede estar absolutamente seguro de que no hay vacía, vaya para EitanT la respuesta original; eso es lo que Matlab es para. Si usted no puede estar seguro, sólo tiene que ir para el bucle.

    • +1: yo siempre subestiman los desagradables bucles!
    • Se puede evaluar esto en contra de mi de la solución original para una estructura sin campos vacíos?
    • hay que ir; parece que el método es inmejorable.
    • También echa un vistazo a mi tercera solución 🙂
    • Por qué hay una diferencia entre cellfun('isempty', ...) y cellfun(@isempty, ...)? De acuerdo a la documentación oficial, el argumento de cadena es aceptada sólo por compatibilidad con versiones anteriores… y otra cosa, en mi máquina el textscan solución funciona x10 más rápido de lo que he mostrado aquí, así que me pregunto ¿cuál es la razón para esta discrepancia.
    • Con respecto a la cellfun-con-cadena, Yair Altman ha escrito esta muy claramente escrito publicación del blog sobre él-creo que, en realidad, aprendí de él. Con respecto a la gran diferencia en el rendimiento de su cadena de solución, no estoy seguro. Sé que algunos procesadores tienen los circuitos dedicados para muchas manipulaciones de cadenas, lo que tal vez tiene algo que ver con eso. Pero no pin me down en esto 🙂 voy a probar esta cosa en mi casa de la máquina para la buena medida.
    • ver mis ediciones. Al parecer, es de hecho un problema de la CPU.
    • Wow. Muchas complicado métodos para hacer algo que parece que debería ser tan simple. Gracias por todas las ideas. No, gracias a The Mathworks para que no sea fácil 😉
    • bueno, sí implementar algunos métodos fáciles…los métodos fáciles son, sin embargo, no siempre el más rápido 🙂

Dejar respuesta

Please enter your comment!
Please enter your name here