Позвольте мне предисловие к этому ответу со следующим комментарием:
ЭТО НЕПРАВИЛЬНЫЙ СПОСОБ ДЕЛАТЬ ЭТО. ЭТО ПРЕДОТВРАТЬ НА ЧИСЛЕННУЮ НЕУСТОЙЧИВОСТЬ И БОЛЬШЕ СКОРОСТЬ, ЧТО ДРУГИЕ МЕТОДЫ ПРЕДСТАВЛЕНЫ, ИСПОЛЬЗУЮТСЯ НА ВАШЕМ СОБСТВЕННОМ РИСКЕ.
Сказанное, я не мог устоять перед решением проблемы с динамической точки зрения (и я надеюсь, вы получите свежий взгляд на проблему). В теории это должно работать все время, но вычисления собственных значений могут часто терпеть неудачу. Идея состоит в том, чтобы рассматривать ваш список как поток из строк в столбцы. Если две строки имеют общую ценность, между ними существует соединительный поток. Если бы мы думали об этих потоках как о воде, мы бы увидели, что потоки кластеризуются в маленькие пулы, когда между ними существует соединительный путь. Для простоты я собираюсь использовать меньший набор, хотя он также работает с вашим набором данных:
from numpy import where, newaxis
from scipy import linalg, array, zeros
X = [[0,1,3],[2],[3,1]]
Нам нужно преобразовать данные в потоковый граф. Если строка i втекает в значение j , поместим ее в матрицу. Здесь у нас есть 3 строки и 4 уникальных значения:
A = zeros((4,len(X)), dtype=float)
for i,row in enumerate(X):
for val in row: A[val,i] = 1
В общем, вам нужно будет изменить 4
, чтобы записать количество уникальных значений, которые у вас есть. Если набор представляет собой список целых чисел, начиная с 0, как у нас, вы можете просто сделать это самым большим числом. Теперь мы выполняем разложение по собственным значениям. SVD, если быть точным, поскольку наша матрица не является квадратной.
S = linalg.svd(A)
Мы хотим сохранить только часть 3х3 этого ответа, поскольку она будет представлять поток пулов. На самом деле нам нужны только абсолютные значения этой матрицы; нам остается только, есть ли поток в этом пространстве cluster .
M = abs(S[2])
Мы можем представить эту матрицу M как марковскую матрицу и сделать ее явной по нормировке строк. Как только мы это получим, мы вычисляем (слева) разложение собственного значения. этой матрицы.
M /= M.sum(axis=1)[:,newaxis]
U,V = linalg.eig(M,left=True, right=False)
V = abs(V)
Теперь несвязная (неэргодическая) марковская матрица обладает приятным свойством, что для каждого несвязного кластера существует собственное значение единицы. Собственные векторы, связанные с этими значениями единства, являются теми, которые мы хотим:
idx = where(U > .999)[0]
C = V.T[idx] > 0
Я должен использовать .999 из-за вышеупомянутой числовой неустойчивости. На этом мы закончили! Каждый независимый кластер может теперь вывести соответствующие строки:
for cluster in C:
print where(A[:,cluster].sum(axis=1))[0]
Что дает, как и предполагалось:
[0 1 3]
[2]
Измените X
на lst
, и вы get: [ 0 1 3 4 5 10 11 16] [2 8]
.
Добавление
Почему это может быть полезно? Я не знаю, откуда берутся ваши базовые данные, но что происходит, когда соединения не являются абсолютными? У строки 1
есть запись 3
80% времени - как бы вы обобщили проблему? Метод потока выше работал бы очень хорошо и был бы полностью параметризован этим значением .999
, чем дальше от единства, тем слабее ассоциация.
Визуальное представление
Поскольку изображение стоит 1K слов, вот графики матриц A и V для моего примера и ваши lst
соответственно. Обратите внимание, как в V
разбивается на два кластера (это блок-диагональная матрица с двумя блоками после перестановки), так как для каждого примера было только два уникальных списка!
[/g9] [/g10]
Быстрая реализация
Оглядываясь назад, я понял, что вы можете пропустить шаг SVD и вычислить только один decomp:
M = dot(A.T,A)
M /= M.sum(axis=1)[:,newaxis]
U,V = linalg.eig(M,left=True, right=False)
Преимущество этого метода (помимо скорости) состоит в том, что M
теперь является симметричным, поэтому вычисление может быть более быстрым и точным (никаких мнимых значений не беспокоить)
Итак, вы вызываете adapter.notifyDataSetChanged()
, поэтому никакой другой метод notify___
не нужен (изменение набора данных в любом случае отключает анимацию.)
В этом случае самый простой (и наиболее эффективный) способ делать что-то будет, чтобы использовать RealmResults
напрямую, а не извлекать каждый элемент в ArrayList
, который затем используется точно таким же образом.
Итак, это должно быть как
public static RealmResults<City> getStoredCities(){
RealmQuery<City> query = getRealmInstance().where(City.class);
return realm.where(City.class)
.findAllSorted("timestamp", Sort.DESCENDING);
}
И
public static void removeCity(City city){
final String cityName = city.getCityName();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
RealmResults<City> result = realm.where(City.class).equalTo("cityName", cityName).findAll();
result.deleteAllFromRealm();
}
});
}
И
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
RealmHelper.removeCity(getItem(position));
}
});
И
// dependency: compile 'io.realm:android-adapters:1.3.0' // <-- for Realm 3.x+, use 2.0.0
public class CityListAdapter extends RealmRecyclerViewAdapter<City, CityListViewHolder> {
OnItemClickListener onItemClickListener;
OnItemLongClickListener onItemLongClickListener;
public CityListAdapter(@NonNull Context context,
@Nullable OrderedRealmCollection<City> data,
OnItemClickListener onItemClickListener,
OnItemLongClickListener onItemLongClickListener) {
super(context, data, true);
this.onItemClickListener = onItemClickListener;
this.onItemLongClickListener = onItemLongClickListener;
}
@Override
public CityListViewholder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.city_item_navigation_viewholder, parent, false);
CityListViewholder cityListViewholder = new CityListViewholder(view, parent.getContext());
return cityListViewholder;
}
@Override
public void onBindViewHolder(CityListViewholder holder, int position) {
holder.cityName.setText(getItem(position).getCityName());
holder.bindClick(position, onItemClickListener);
holder.bindLongClick(position, onItemLongClickListener);
}
public static class CityListViewholder extends RecyclerView.ViewHolder {
TextView cityName;
ImageView cityIcon;
public CityListViewholder(View itemView,
Context context) {
super(itemView);
cityName = (TextView)itemView.findViewById(R.id.city_name);
cityIcon = (ImageView)itemView.findViewById(R.id.city_icon);
}
public void bindClick(final int position, final OnItemClickListener onItemClickListener){
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemClickListener.onItemClick(position);
}
});
}
public void bindLongClick(final int position, final OnItemLongClickListener onItemLongClickListener) {
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
onItemLongClickListener.onItemLongClick(position);
return true;
}
});
}
}
}
Используя RealmRecyclerViewAdapter
, вызывается notifyDataSetChanged()
всякий раз, когда ваши результаты меняются.
RealmHelper.removeCity(getData().get(position));
– Isabelle 30 July 2016 в 07:38getItem(position)
также работает, если я знаю правильно, хотяgetData()
работал для меня – EpicPandaForce 30 July 2016 в 09:06results.get(position)
, но я не уверен, где вы используете код. – EpicPandaForce 30 July 2016 в 09:07getData()
- методRealmRecyclerViewAdapter
– EpicPandaForce 4 August 2016 в 12:42